1) Modified dungeon related codes.

2) Send PacketPlayerEnterSceneNotify with more details.
3) Fixed dungeon reward statue gadget.
4) Fixed dungeon entries and exits teleportation
5) Fixed showing dungeon entries in handbook and domain interface for normal dungeons and quest entries
6) Added weekly boss discount and refresh implementation
This commit is contained in:
mjolsic 2023-08-10 23:11:16 +10:00
parent 9d6ca5ee00
commit b1baa2f09c
61 changed files with 6837 additions and 4515 deletions

View File

@ -0,0 +1,480 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: DungeonRestartReq.proto
package emu.grasscutter.net.proto;
public final class DungeonRestartReqOuterClass {
private DungeonRestartReqOuterClass() {}
public static void registerAllExtensions(
com.google.protobuf.ExtensionRegistryLite registry) {
}
public static void registerAllExtensions(
com.google.protobuf.ExtensionRegistry registry) {
registerAllExtensions(
(com.google.protobuf.ExtensionRegistryLite) registry);
}
public interface DungeonRestartReqOrBuilder extends
// @@protoc_insertion_point(interface_extends:DungeonRestartReq)
com.google.protobuf.MessageOrBuilder {
}
/**
* <pre>
* CmdId: 961
* EnetChannelId: 0
* EnetIsReliable: true
* IsAllowClient: true
* </pre>
*
* Protobuf type {@code DungeonRestartReq}
*/
public static final class DungeonRestartReq extends
com.google.protobuf.GeneratedMessageV3 implements
// @@protoc_insertion_point(message_implements:DungeonRestartReq)
DungeonRestartReqOrBuilder {
private static final long serialVersionUID = 0L;
// Use DungeonRestartReq.newBuilder() to construct.
private DungeonRestartReq(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {
super(builder);
}
private DungeonRestartReq() {
}
@java.lang.Override
@SuppressWarnings({"unused"})
protected java.lang.Object newInstance(
UnusedPrivateParameter unused) {
return new DungeonRestartReq();
}
@java.lang.Override
public final com.google.protobuf.UnknownFieldSet
getUnknownFields() {
return this.unknownFields;
}
private DungeonRestartReq(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
this();
if (extensionRegistry == null) {
throw new java.lang.NullPointerException();
}
com.google.protobuf.UnknownFieldSet.Builder unknownFields =
com.google.protobuf.UnknownFieldSet.newBuilder();
try {
boolean done = false;
while (!done) {
int tag = input.readTag();
switch (tag) {
case 0:
done = true;
break;
default: {
if (!parseUnknownField(
input, unknownFields, extensionRegistry, tag)) {
done = true;
}
break;
}
}
}
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
throw e.setUnfinishedMessage(this);
} catch (java.io.IOException e) {
throw new com.google.protobuf.InvalidProtocolBufferException(
e).setUnfinishedMessage(this);
} finally {
this.unknownFields = unknownFields.build();
makeExtensionsImmutable();
}
}
public static final com.google.protobuf.Descriptors.Descriptor
getDescriptor() {
return emu.grasscutter.net.proto.DungeonRestartReqOuterClass.internal_static_DungeonRestartReq_descriptor;
}
@java.lang.Override
protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
internalGetFieldAccessorTable() {
return emu.grasscutter.net.proto.DungeonRestartReqOuterClass.internal_static_DungeonRestartReq_fieldAccessorTable
.ensureFieldAccessorsInitialized(
emu.grasscutter.net.proto.DungeonRestartReqOuterClass.DungeonRestartReq.class, emu.grasscutter.net.proto.DungeonRestartReqOuterClass.DungeonRestartReq.Builder.class);
}
private byte memoizedIsInitialized = -1;
@java.lang.Override
public final boolean isInitialized() {
byte isInitialized = memoizedIsInitialized;
if (isInitialized == 1) return true;
if (isInitialized == 0) return false;
memoizedIsInitialized = 1;
return true;
}
@java.lang.Override
public void writeTo(com.google.protobuf.CodedOutputStream output)
throws java.io.IOException {
unknownFields.writeTo(output);
}
@java.lang.Override
public int getSerializedSize() {
int size = memoizedSize;
if (size != -1) return size;
size = 0;
size += unknownFields.getSerializedSize();
memoizedSize = size;
return size;
}
@java.lang.Override
public boolean equals(final java.lang.Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof emu.grasscutter.net.proto.DungeonRestartReqOuterClass.DungeonRestartReq)) {
return super.equals(obj);
}
emu.grasscutter.net.proto.DungeonRestartReqOuterClass.DungeonRestartReq other = (emu.grasscutter.net.proto.DungeonRestartReqOuterClass.DungeonRestartReq) obj;
if (!unknownFields.equals(other.unknownFields)) return false;
return true;
}
@java.lang.Override
public int hashCode() {
if (memoizedHashCode != 0) {
return memoizedHashCode;
}
int hash = 41;
hash = (19 * hash) + getDescriptor().hashCode();
hash = (29 * hash) + unknownFields.hashCode();
memoizedHashCode = hash;
return hash;
}
public static emu.grasscutter.net.proto.DungeonRestartReqOuterClass.DungeonRestartReq parseFrom(
java.nio.ByteBuffer data)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data);
}
public static emu.grasscutter.net.proto.DungeonRestartReqOuterClass.DungeonRestartReq parseFrom(
java.nio.ByteBuffer data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data, extensionRegistry);
}
public static emu.grasscutter.net.proto.DungeonRestartReqOuterClass.DungeonRestartReq parseFrom(
com.google.protobuf.ByteString data)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data);
}
public static emu.grasscutter.net.proto.DungeonRestartReqOuterClass.DungeonRestartReq parseFrom(
com.google.protobuf.ByteString data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data, extensionRegistry);
}
public static emu.grasscutter.net.proto.DungeonRestartReqOuterClass.DungeonRestartReq parseFrom(byte[] data)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data);
}
public static emu.grasscutter.net.proto.DungeonRestartReqOuterClass.DungeonRestartReq parseFrom(
byte[] data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data, extensionRegistry);
}
public static emu.grasscutter.net.proto.DungeonRestartReqOuterClass.DungeonRestartReq parseFrom(java.io.InputStream input)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageV3
.parseWithIOException(PARSER, input);
}
public static emu.grasscutter.net.proto.DungeonRestartReqOuterClass.DungeonRestartReq parseFrom(
java.io.InputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageV3
.parseWithIOException(PARSER, input, extensionRegistry);
}
public static emu.grasscutter.net.proto.DungeonRestartReqOuterClass.DungeonRestartReq parseDelimitedFrom(java.io.InputStream input)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageV3
.parseDelimitedWithIOException(PARSER, input);
}
public static emu.grasscutter.net.proto.DungeonRestartReqOuterClass.DungeonRestartReq parseDelimitedFrom(
java.io.InputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageV3
.parseDelimitedWithIOException(PARSER, input, extensionRegistry);
}
public static emu.grasscutter.net.proto.DungeonRestartReqOuterClass.DungeonRestartReq parseFrom(
com.google.protobuf.CodedInputStream input)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageV3
.parseWithIOException(PARSER, input);
}
public static emu.grasscutter.net.proto.DungeonRestartReqOuterClass.DungeonRestartReq parseFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageV3
.parseWithIOException(PARSER, input, extensionRegistry);
}
@java.lang.Override
public Builder newBuilderForType() { return newBuilder(); }
public static Builder newBuilder() {
return DEFAULT_INSTANCE.toBuilder();
}
public static Builder newBuilder(emu.grasscutter.net.proto.DungeonRestartReqOuterClass.DungeonRestartReq prototype) {
return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);
}
@java.lang.Override
public Builder toBuilder() {
return this == DEFAULT_INSTANCE
? new Builder() : new Builder().mergeFrom(this);
}
@java.lang.Override
protected Builder newBuilderForType(
com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
Builder builder = new Builder(parent);
return builder;
}
/**
* <pre>
* CmdId: 961
* EnetChannelId: 0
* EnetIsReliable: true
* IsAllowClient: true
* </pre>
*
* Protobuf type {@code DungeonRestartReq}
*/
public static final class Builder extends
com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements
// @@protoc_insertion_point(builder_implements:DungeonRestartReq)
emu.grasscutter.net.proto.DungeonRestartReqOuterClass.DungeonRestartReqOrBuilder {
public static final com.google.protobuf.Descriptors.Descriptor
getDescriptor() {
return emu.grasscutter.net.proto.DungeonRestartReqOuterClass.internal_static_DungeonRestartReq_descriptor;
}
@java.lang.Override
protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
internalGetFieldAccessorTable() {
return emu.grasscutter.net.proto.DungeonRestartReqOuterClass.internal_static_DungeonRestartReq_fieldAccessorTable
.ensureFieldAccessorsInitialized(
emu.grasscutter.net.proto.DungeonRestartReqOuterClass.DungeonRestartReq.class, emu.grasscutter.net.proto.DungeonRestartReqOuterClass.DungeonRestartReq.Builder.class);
}
// Construct using emu.grasscutter.net.proto.DungeonRestartReqOuterClass.DungeonRestartReq.newBuilder()
private Builder() {
maybeForceBuilderInitialization();
}
private Builder(
com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
super(parent);
maybeForceBuilderInitialization();
}
private void maybeForceBuilderInitialization() {
if (com.google.protobuf.GeneratedMessageV3
.alwaysUseFieldBuilders) {
}
}
@java.lang.Override
public Builder clear() {
super.clear();
return this;
}
@java.lang.Override
public com.google.protobuf.Descriptors.Descriptor
getDescriptorForType() {
return emu.grasscutter.net.proto.DungeonRestartReqOuterClass.internal_static_DungeonRestartReq_descriptor;
}
@java.lang.Override
public emu.grasscutter.net.proto.DungeonRestartReqOuterClass.DungeonRestartReq getDefaultInstanceForType() {
return emu.grasscutter.net.proto.DungeonRestartReqOuterClass.DungeonRestartReq.getDefaultInstance();
}
@java.lang.Override
public emu.grasscutter.net.proto.DungeonRestartReqOuterClass.DungeonRestartReq build() {
emu.grasscutter.net.proto.DungeonRestartReqOuterClass.DungeonRestartReq result = buildPartial();
if (!result.isInitialized()) {
throw newUninitializedMessageException(result);
}
return result;
}
@java.lang.Override
public emu.grasscutter.net.proto.DungeonRestartReqOuterClass.DungeonRestartReq buildPartial() {
emu.grasscutter.net.proto.DungeonRestartReqOuterClass.DungeonRestartReq result = new emu.grasscutter.net.proto.DungeonRestartReqOuterClass.DungeonRestartReq(this);
onBuilt();
return result;
}
@java.lang.Override
public Builder clone() {
return super.clone();
}
@java.lang.Override
public Builder setField(
com.google.protobuf.Descriptors.FieldDescriptor field,
java.lang.Object value) {
return super.setField(field, value);
}
@java.lang.Override
public Builder clearField(
com.google.protobuf.Descriptors.FieldDescriptor field) {
return super.clearField(field);
}
@java.lang.Override
public Builder clearOneof(
com.google.protobuf.Descriptors.OneofDescriptor oneof) {
return super.clearOneof(oneof);
}
@java.lang.Override
public Builder setRepeatedField(
com.google.protobuf.Descriptors.FieldDescriptor field,
int index, java.lang.Object value) {
return super.setRepeatedField(field, index, value);
}
@java.lang.Override
public Builder addRepeatedField(
com.google.protobuf.Descriptors.FieldDescriptor field,
java.lang.Object value) {
return super.addRepeatedField(field, value);
}
@java.lang.Override
public Builder mergeFrom(com.google.protobuf.Message other) {
if (other instanceof emu.grasscutter.net.proto.DungeonRestartReqOuterClass.DungeonRestartReq) {
return mergeFrom((emu.grasscutter.net.proto.DungeonRestartReqOuterClass.DungeonRestartReq)other);
} else {
super.mergeFrom(other);
return this;
}
}
public Builder mergeFrom(emu.grasscutter.net.proto.DungeonRestartReqOuterClass.DungeonRestartReq other) {
if (other == emu.grasscutter.net.proto.DungeonRestartReqOuterClass.DungeonRestartReq.getDefaultInstance()) return this;
this.mergeUnknownFields(other.unknownFields);
onChanged();
return this;
}
@java.lang.Override
public final boolean isInitialized() {
return true;
}
@java.lang.Override
public Builder mergeFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
emu.grasscutter.net.proto.DungeonRestartReqOuterClass.DungeonRestartReq parsedMessage = null;
try {
parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
parsedMessage = (emu.grasscutter.net.proto.DungeonRestartReqOuterClass.DungeonRestartReq) e.getUnfinishedMessage();
throw e.unwrapIOException();
} finally {
if (parsedMessage != null) {
mergeFrom(parsedMessage);
}
}
return this;
}
@java.lang.Override
public final Builder setUnknownFields(
final com.google.protobuf.UnknownFieldSet unknownFields) {
return super.setUnknownFields(unknownFields);
}
@java.lang.Override
public final Builder mergeUnknownFields(
final com.google.protobuf.UnknownFieldSet unknownFields) {
return super.mergeUnknownFields(unknownFields);
}
// @@protoc_insertion_point(builder_scope:DungeonRestartReq)
}
// @@protoc_insertion_point(class_scope:DungeonRestartReq)
private static final emu.grasscutter.net.proto.DungeonRestartReqOuterClass.DungeonRestartReq DEFAULT_INSTANCE;
static {
DEFAULT_INSTANCE = new emu.grasscutter.net.proto.DungeonRestartReqOuterClass.DungeonRestartReq();
}
public static emu.grasscutter.net.proto.DungeonRestartReqOuterClass.DungeonRestartReq getDefaultInstance() {
return DEFAULT_INSTANCE;
}
private static final com.google.protobuf.Parser<DungeonRestartReq>
PARSER = new com.google.protobuf.AbstractParser<DungeonRestartReq>() {
@java.lang.Override
public DungeonRestartReq parsePartialFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return new DungeonRestartReq(input, extensionRegistry);
}
};
public static com.google.protobuf.Parser<DungeonRestartReq> parser() {
return PARSER;
}
@java.lang.Override
public com.google.protobuf.Parser<DungeonRestartReq> getParserForType() {
return PARSER;
}
@java.lang.Override
public emu.grasscutter.net.proto.DungeonRestartReqOuterClass.DungeonRestartReq getDefaultInstanceForType() {
return DEFAULT_INSTANCE;
}
}
private static final com.google.protobuf.Descriptors.Descriptor
internal_static_DungeonRestartReq_descriptor;
private static final
com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
internal_static_DungeonRestartReq_fieldAccessorTable;
public static com.google.protobuf.Descriptors.FileDescriptor
getDescriptor() {
return descriptor;
}
private static com.google.protobuf.Descriptors.FileDescriptor
descriptor;
static {
java.lang.String[] descriptorData = {
"\n\027DungeonRestartReq.proto\"\023\n\021DungeonRest" +
"artReqB\033\n\031emu.grasscutter.net.protob\006pro" +
"to3"
};
descriptor = com.google.protobuf.Descriptors.FileDescriptor
.internalBuildGeneratedFileFrom(descriptorData,
new com.google.protobuf.Descriptors.FileDescriptor[] {
});
internal_static_DungeonRestartReq_descriptor =
getDescriptor().getMessageTypes().get(0);
internal_static_DungeonRestartReq_fieldAccessorTable = new
com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
internal_static_DungeonRestartReq_descriptor,
new java.lang.String[] { });
}
// @@protoc_insertion_point(outer_class_scope)
}

View File

@ -0,0 +1,689 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: DungeonRestartRsp.proto
package emu.grasscutter.net.proto;
public final class DungeonRestartRspOuterClass {
private DungeonRestartRspOuterClass() {}
public static void registerAllExtensions(
com.google.protobuf.ExtensionRegistryLite registry) {
}
public static void registerAllExtensions(
com.google.protobuf.ExtensionRegistry registry) {
registerAllExtensions(
(com.google.protobuf.ExtensionRegistryLite) registry);
}
public interface DungeonRestartRspOrBuilder extends
// @@protoc_insertion_point(interface_extends:DungeonRestartRsp)
com.google.protobuf.MessageOrBuilder {
/**
* <code>uint32 dungeon_id = 15;</code>
* @return The dungeonId.
*/
int getDungeonId();
/**
* <code>int32 retcode = 9;</code>
* @return The retcode.
*/
int getRetcode();
/**
* <code>uint32 point_id = 14;</code>
* @return The pointId.
*/
int getPointId();
}
/**
* <pre>
* CmdId: 929
* EnetChannelId: 0
* EnetIsReliable: true
* </pre>
*
* Protobuf type {@code DungeonRestartRsp}
*/
public static final class DungeonRestartRsp extends
com.google.protobuf.GeneratedMessageV3 implements
// @@protoc_insertion_point(message_implements:DungeonRestartRsp)
DungeonRestartRspOrBuilder {
private static final long serialVersionUID = 0L;
// Use DungeonRestartRsp.newBuilder() to construct.
private DungeonRestartRsp(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {
super(builder);
}
private DungeonRestartRsp() {
}
@java.lang.Override
@SuppressWarnings({"unused"})
protected java.lang.Object newInstance(
UnusedPrivateParameter unused) {
return new DungeonRestartRsp();
}
@java.lang.Override
public final com.google.protobuf.UnknownFieldSet
getUnknownFields() {
return this.unknownFields;
}
private DungeonRestartRsp(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
this();
if (extensionRegistry == null) {
throw new java.lang.NullPointerException();
}
com.google.protobuf.UnknownFieldSet.Builder unknownFields =
com.google.protobuf.UnknownFieldSet.newBuilder();
try {
boolean done = false;
while (!done) {
int tag = input.readTag();
switch (tag) {
case 0:
done = true;
break;
case 72: {
retcode_ = input.readInt32();
break;
}
case 112: {
pointId_ = input.readUInt32();
break;
}
case 120: {
dungeonId_ = input.readUInt32();
break;
}
default: {
if (!parseUnknownField(
input, unknownFields, extensionRegistry, tag)) {
done = true;
}
break;
}
}
}
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
throw e.setUnfinishedMessage(this);
} catch (java.io.IOException e) {
throw new com.google.protobuf.InvalidProtocolBufferException(
e).setUnfinishedMessage(this);
} finally {
this.unknownFields = unknownFields.build();
makeExtensionsImmutable();
}
}
public static final com.google.protobuf.Descriptors.Descriptor
getDescriptor() {
return emu.grasscutter.net.proto.DungeonRestartRspOuterClass.internal_static_DungeonRestartRsp_descriptor;
}
@java.lang.Override
protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
internalGetFieldAccessorTable() {
return emu.grasscutter.net.proto.DungeonRestartRspOuterClass.internal_static_DungeonRestartRsp_fieldAccessorTable
.ensureFieldAccessorsInitialized(
emu.grasscutter.net.proto.DungeonRestartRspOuterClass.DungeonRestartRsp.class, emu.grasscutter.net.proto.DungeonRestartRspOuterClass.DungeonRestartRsp.Builder.class);
}
public static final int DUNGEON_ID_FIELD_NUMBER = 15;
private int dungeonId_;
/**
* <code>uint32 dungeon_id = 15;</code>
* @return The dungeonId.
*/
@java.lang.Override
public int getDungeonId() {
return dungeonId_;
}
public static final int RETCODE_FIELD_NUMBER = 9;
private int retcode_;
/**
* <code>int32 retcode = 9;</code>
* @return The retcode.
*/
@java.lang.Override
public int getRetcode() {
return retcode_;
}
public static final int POINT_ID_FIELD_NUMBER = 14;
private int pointId_;
/**
* <code>uint32 point_id = 14;</code>
* @return The pointId.
*/
@java.lang.Override
public int getPointId() {
return pointId_;
}
private byte memoizedIsInitialized = -1;
@java.lang.Override
public final boolean isInitialized() {
byte isInitialized = memoizedIsInitialized;
if (isInitialized == 1) return true;
if (isInitialized == 0) return false;
memoizedIsInitialized = 1;
return true;
}
@java.lang.Override
public void writeTo(com.google.protobuf.CodedOutputStream output)
throws java.io.IOException {
if (retcode_ != 0) {
output.writeInt32(9, retcode_);
}
if (pointId_ != 0) {
output.writeUInt32(14, pointId_);
}
if (dungeonId_ != 0) {
output.writeUInt32(15, dungeonId_);
}
unknownFields.writeTo(output);
}
@java.lang.Override
public int getSerializedSize() {
int size = memoizedSize;
if (size != -1) return size;
size = 0;
if (retcode_ != 0) {
size += com.google.protobuf.CodedOutputStream
.computeInt32Size(9, retcode_);
}
if (pointId_ != 0) {
size += com.google.protobuf.CodedOutputStream
.computeUInt32Size(14, pointId_);
}
if (dungeonId_ != 0) {
size += com.google.protobuf.CodedOutputStream
.computeUInt32Size(15, dungeonId_);
}
size += unknownFields.getSerializedSize();
memoizedSize = size;
return size;
}
@java.lang.Override
public boolean equals(final java.lang.Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof emu.grasscutter.net.proto.DungeonRestartRspOuterClass.DungeonRestartRsp)) {
return super.equals(obj);
}
emu.grasscutter.net.proto.DungeonRestartRspOuterClass.DungeonRestartRsp other = (emu.grasscutter.net.proto.DungeonRestartRspOuterClass.DungeonRestartRsp) obj;
if (getDungeonId()
!= other.getDungeonId()) return false;
if (getRetcode()
!= other.getRetcode()) return false;
if (getPointId()
!= other.getPointId()) return false;
if (!unknownFields.equals(other.unknownFields)) return false;
return true;
}
@java.lang.Override
public int hashCode() {
if (memoizedHashCode != 0) {
return memoizedHashCode;
}
int hash = 41;
hash = (19 * hash) + getDescriptor().hashCode();
hash = (37 * hash) + DUNGEON_ID_FIELD_NUMBER;
hash = (53 * hash) + getDungeonId();
hash = (37 * hash) + RETCODE_FIELD_NUMBER;
hash = (53 * hash) + getRetcode();
hash = (37 * hash) + POINT_ID_FIELD_NUMBER;
hash = (53 * hash) + getPointId();
hash = (29 * hash) + unknownFields.hashCode();
memoizedHashCode = hash;
return hash;
}
public static emu.grasscutter.net.proto.DungeonRestartRspOuterClass.DungeonRestartRsp parseFrom(
java.nio.ByteBuffer data)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data);
}
public static emu.grasscutter.net.proto.DungeonRestartRspOuterClass.DungeonRestartRsp parseFrom(
java.nio.ByteBuffer data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data, extensionRegistry);
}
public static emu.grasscutter.net.proto.DungeonRestartRspOuterClass.DungeonRestartRsp parseFrom(
com.google.protobuf.ByteString data)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data);
}
public static emu.grasscutter.net.proto.DungeonRestartRspOuterClass.DungeonRestartRsp parseFrom(
com.google.protobuf.ByteString data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data, extensionRegistry);
}
public static emu.grasscutter.net.proto.DungeonRestartRspOuterClass.DungeonRestartRsp parseFrom(byte[] data)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data);
}
public static emu.grasscutter.net.proto.DungeonRestartRspOuterClass.DungeonRestartRsp parseFrom(
byte[] data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data, extensionRegistry);
}
public static emu.grasscutter.net.proto.DungeonRestartRspOuterClass.DungeonRestartRsp parseFrom(java.io.InputStream input)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageV3
.parseWithIOException(PARSER, input);
}
public static emu.grasscutter.net.proto.DungeonRestartRspOuterClass.DungeonRestartRsp parseFrom(
java.io.InputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageV3
.parseWithIOException(PARSER, input, extensionRegistry);
}
public static emu.grasscutter.net.proto.DungeonRestartRspOuterClass.DungeonRestartRsp parseDelimitedFrom(java.io.InputStream input)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageV3
.parseDelimitedWithIOException(PARSER, input);
}
public static emu.grasscutter.net.proto.DungeonRestartRspOuterClass.DungeonRestartRsp parseDelimitedFrom(
java.io.InputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageV3
.parseDelimitedWithIOException(PARSER, input, extensionRegistry);
}
public static emu.grasscutter.net.proto.DungeonRestartRspOuterClass.DungeonRestartRsp parseFrom(
com.google.protobuf.CodedInputStream input)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageV3
.parseWithIOException(PARSER, input);
}
public static emu.grasscutter.net.proto.DungeonRestartRspOuterClass.DungeonRestartRsp parseFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageV3
.parseWithIOException(PARSER, input, extensionRegistry);
}
@java.lang.Override
public Builder newBuilderForType() { return newBuilder(); }
public static Builder newBuilder() {
return DEFAULT_INSTANCE.toBuilder();
}
public static Builder newBuilder(emu.grasscutter.net.proto.DungeonRestartRspOuterClass.DungeonRestartRsp prototype) {
return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);
}
@java.lang.Override
public Builder toBuilder() {
return this == DEFAULT_INSTANCE
? new Builder() : new Builder().mergeFrom(this);
}
@java.lang.Override
protected Builder newBuilderForType(
com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
Builder builder = new Builder(parent);
return builder;
}
/**
* <pre>
* CmdId: 929
* EnetChannelId: 0
* EnetIsReliable: true
* </pre>
*
* Protobuf type {@code DungeonRestartRsp}
*/
public static final class Builder extends
com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements
// @@protoc_insertion_point(builder_implements:DungeonRestartRsp)
emu.grasscutter.net.proto.DungeonRestartRspOuterClass.DungeonRestartRspOrBuilder {
public static final com.google.protobuf.Descriptors.Descriptor
getDescriptor() {
return emu.grasscutter.net.proto.DungeonRestartRspOuterClass.internal_static_DungeonRestartRsp_descriptor;
}
@java.lang.Override
protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
internalGetFieldAccessorTable() {
return emu.grasscutter.net.proto.DungeonRestartRspOuterClass.internal_static_DungeonRestartRsp_fieldAccessorTable
.ensureFieldAccessorsInitialized(
emu.grasscutter.net.proto.DungeonRestartRspOuterClass.DungeonRestartRsp.class, emu.grasscutter.net.proto.DungeonRestartRspOuterClass.DungeonRestartRsp.Builder.class);
}
// Construct using emu.grasscutter.net.proto.DungeonRestartRspOuterClass.DungeonRestartRsp.newBuilder()
private Builder() {
maybeForceBuilderInitialization();
}
private Builder(
com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
super(parent);
maybeForceBuilderInitialization();
}
private void maybeForceBuilderInitialization() {
if (com.google.protobuf.GeneratedMessageV3
.alwaysUseFieldBuilders) {
}
}
@java.lang.Override
public Builder clear() {
super.clear();
dungeonId_ = 0;
retcode_ = 0;
pointId_ = 0;
return this;
}
@java.lang.Override
public com.google.protobuf.Descriptors.Descriptor
getDescriptorForType() {
return emu.grasscutter.net.proto.DungeonRestartRspOuterClass.internal_static_DungeonRestartRsp_descriptor;
}
@java.lang.Override
public emu.grasscutter.net.proto.DungeonRestartRspOuterClass.DungeonRestartRsp getDefaultInstanceForType() {
return emu.grasscutter.net.proto.DungeonRestartRspOuterClass.DungeonRestartRsp.getDefaultInstance();
}
@java.lang.Override
public emu.grasscutter.net.proto.DungeonRestartRspOuterClass.DungeonRestartRsp build() {
emu.grasscutter.net.proto.DungeonRestartRspOuterClass.DungeonRestartRsp result = buildPartial();
if (!result.isInitialized()) {
throw newUninitializedMessageException(result);
}
return result;
}
@java.lang.Override
public emu.grasscutter.net.proto.DungeonRestartRspOuterClass.DungeonRestartRsp buildPartial() {
emu.grasscutter.net.proto.DungeonRestartRspOuterClass.DungeonRestartRsp result = new emu.grasscutter.net.proto.DungeonRestartRspOuterClass.DungeonRestartRsp(this);
result.dungeonId_ = dungeonId_;
result.retcode_ = retcode_;
result.pointId_ = pointId_;
onBuilt();
return result;
}
@java.lang.Override
public Builder clone() {
return super.clone();
}
@java.lang.Override
public Builder setField(
com.google.protobuf.Descriptors.FieldDescriptor field,
java.lang.Object value) {
return super.setField(field, value);
}
@java.lang.Override
public Builder clearField(
com.google.protobuf.Descriptors.FieldDescriptor field) {
return super.clearField(field);
}
@java.lang.Override
public Builder clearOneof(
com.google.protobuf.Descriptors.OneofDescriptor oneof) {
return super.clearOneof(oneof);
}
@java.lang.Override
public Builder setRepeatedField(
com.google.protobuf.Descriptors.FieldDescriptor field,
int index, java.lang.Object value) {
return super.setRepeatedField(field, index, value);
}
@java.lang.Override
public Builder addRepeatedField(
com.google.protobuf.Descriptors.FieldDescriptor field,
java.lang.Object value) {
return super.addRepeatedField(field, value);
}
@java.lang.Override
public Builder mergeFrom(com.google.protobuf.Message other) {
if (other instanceof emu.grasscutter.net.proto.DungeonRestartRspOuterClass.DungeonRestartRsp) {
return mergeFrom((emu.grasscutter.net.proto.DungeonRestartRspOuterClass.DungeonRestartRsp)other);
} else {
super.mergeFrom(other);
return this;
}
}
public Builder mergeFrom(emu.grasscutter.net.proto.DungeonRestartRspOuterClass.DungeonRestartRsp other) {
if (other == emu.grasscutter.net.proto.DungeonRestartRspOuterClass.DungeonRestartRsp.getDefaultInstance()) return this;
if (other.getDungeonId() != 0) {
setDungeonId(other.getDungeonId());
}
if (other.getRetcode() != 0) {
setRetcode(other.getRetcode());
}
if (other.getPointId() != 0) {
setPointId(other.getPointId());
}
this.mergeUnknownFields(other.unknownFields);
onChanged();
return this;
}
@java.lang.Override
public final boolean isInitialized() {
return true;
}
@java.lang.Override
public Builder mergeFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
emu.grasscutter.net.proto.DungeonRestartRspOuterClass.DungeonRestartRsp parsedMessage = null;
try {
parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
parsedMessage = (emu.grasscutter.net.proto.DungeonRestartRspOuterClass.DungeonRestartRsp) e.getUnfinishedMessage();
throw e.unwrapIOException();
} finally {
if (parsedMessage != null) {
mergeFrom(parsedMessage);
}
}
return this;
}
private int dungeonId_ ;
/**
* <code>uint32 dungeon_id = 15;</code>
* @return The dungeonId.
*/
@java.lang.Override
public int getDungeonId() {
return dungeonId_;
}
/**
* <code>uint32 dungeon_id = 15;</code>
* @param value The dungeonId to set.
* @return This builder for chaining.
*/
public Builder setDungeonId(int value) {
dungeonId_ = value;
onChanged();
return this;
}
/**
* <code>uint32 dungeon_id = 15;</code>
* @return This builder for chaining.
*/
public Builder clearDungeonId() {
dungeonId_ = 0;
onChanged();
return this;
}
private int retcode_ ;
/**
* <code>int32 retcode = 9;</code>
* @return The retcode.
*/
@java.lang.Override
public int getRetcode() {
return retcode_;
}
/**
* <code>int32 retcode = 9;</code>
* @param value The retcode to set.
* @return This builder for chaining.
*/
public Builder setRetcode(int value) {
retcode_ = value;
onChanged();
return this;
}
/**
* <code>int32 retcode = 9;</code>
* @return This builder for chaining.
*/
public Builder clearRetcode() {
retcode_ = 0;
onChanged();
return this;
}
private int pointId_ ;
/**
* <code>uint32 point_id = 14;</code>
* @return The pointId.
*/
@java.lang.Override
public int getPointId() {
return pointId_;
}
/**
* <code>uint32 point_id = 14;</code>
* @param value The pointId to set.
* @return This builder for chaining.
*/
public Builder setPointId(int value) {
pointId_ = value;
onChanged();
return this;
}
/**
* <code>uint32 point_id = 14;</code>
* @return This builder for chaining.
*/
public Builder clearPointId() {
pointId_ = 0;
onChanged();
return this;
}
@java.lang.Override
public final Builder setUnknownFields(
final com.google.protobuf.UnknownFieldSet unknownFields) {
return super.setUnknownFields(unknownFields);
}
@java.lang.Override
public final Builder mergeUnknownFields(
final com.google.protobuf.UnknownFieldSet unknownFields) {
return super.mergeUnknownFields(unknownFields);
}
// @@protoc_insertion_point(builder_scope:DungeonRestartRsp)
}
// @@protoc_insertion_point(class_scope:DungeonRestartRsp)
private static final emu.grasscutter.net.proto.DungeonRestartRspOuterClass.DungeonRestartRsp DEFAULT_INSTANCE;
static {
DEFAULT_INSTANCE = new emu.grasscutter.net.proto.DungeonRestartRspOuterClass.DungeonRestartRsp();
}
public static emu.grasscutter.net.proto.DungeonRestartRspOuterClass.DungeonRestartRsp getDefaultInstance() {
return DEFAULT_INSTANCE;
}
private static final com.google.protobuf.Parser<DungeonRestartRsp>
PARSER = new com.google.protobuf.AbstractParser<DungeonRestartRsp>() {
@java.lang.Override
public DungeonRestartRsp parsePartialFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return new DungeonRestartRsp(input, extensionRegistry);
}
};
public static com.google.protobuf.Parser<DungeonRestartRsp> parser() {
return PARSER;
}
@java.lang.Override
public com.google.protobuf.Parser<DungeonRestartRsp> getParserForType() {
return PARSER;
}
@java.lang.Override
public emu.grasscutter.net.proto.DungeonRestartRspOuterClass.DungeonRestartRsp getDefaultInstanceForType() {
return DEFAULT_INSTANCE;
}
}
private static final com.google.protobuf.Descriptors.Descriptor
internal_static_DungeonRestartRsp_descriptor;
private static final
com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
internal_static_DungeonRestartRsp_fieldAccessorTable;
public static com.google.protobuf.Descriptors.FileDescriptor
getDescriptor() {
return descriptor;
}
private static com.google.protobuf.Descriptors.FileDescriptor
descriptor;
static {
java.lang.String[] descriptorData = {
"\n\027DungeonRestartRsp.proto\"J\n\021DungeonRest" +
"artRsp\022\022\n\ndungeon_id\030\017 \001(\r\022\017\n\007retcode\030\t " +
"\001(\005\022\020\n\010point_id\030\016 \001(\rB\033\n\031emu.grasscutter" +
".net.protob\006proto3"
};
descriptor = com.google.protobuf.Descriptors.FileDescriptor
.internalBuildGeneratedFileFrom(descriptorData,
new com.google.protobuf.Descriptors.FileDescriptor[] {
});
internal_static_DungeonRestartRsp_descriptor =
getDescriptor().getMessageTypes().get(0);
internal_static_DungeonRestartRsp_fieldAccessorTable = new
com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
internal_static_DungeonRestartRsp_descriptor,
new java.lang.String[] { "DungeonId", "Retcode", "PointId", });
}
// @@protoc_insertion_point(outer_class_scope)
}

View File

@ -0,0 +1,621 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: DungeonReviseLevelNotify.proto
package emu.grasscutter.net.proto;
public final class DungeonReviseLevelNotifyOuterClass {
private DungeonReviseLevelNotifyOuterClass() {}
public static void registerAllExtensions(
com.google.protobuf.ExtensionRegistryLite registry) {
}
public static void registerAllExtensions(
com.google.protobuf.ExtensionRegistry registry) {
registerAllExtensions(
(com.google.protobuf.ExtensionRegistryLite) registry);
}
public interface DungeonReviseLevelNotifyOrBuilder extends
// @@protoc_insertion_point(interface_extends:DungeonReviseLevelNotify)
com.google.protobuf.MessageOrBuilder {
/**
* <code>uint32 revise_level = 7;</code>
* @return The reviseLevel.
*/
int getReviseLevel();
/**
* <code>uint32 dungeon_id = 14;</code>
* @return The dungeonId.
*/
int getDungeonId();
}
/**
* <pre>
* CmdId: 968
* EnetChannelId: 0
* EnetIsReliable: true
* IsAllowClient: true
* </pre>
*
* Protobuf type {@code DungeonReviseLevelNotify}
*/
public static final class DungeonReviseLevelNotify extends
com.google.protobuf.GeneratedMessageV3 implements
// @@protoc_insertion_point(message_implements:DungeonReviseLevelNotify)
DungeonReviseLevelNotifyOrBuilder {
private static final long serialVersionUID = 0L;
// Use DungeonReviseLevelNotify.newBuilder() to construct.
private DungeonReviseLevelNotify(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {
super(builder);
}
private DungeonReviseLevelNotify() {
}
@java.lang.Override
@SuppressWarnings({"unused"})
protected java.lang.Object newInstance(
UnusedPrivateParameter unused) {
return new DungeonReviseLevelNotify();
}
@java.lang.Override
public final com.google.protobuf.UnknownFieldSet
getUnknownFields() {
return this.unknownFields;
}
private DungeonReviseLevelNotify(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
this();
if (extensionRegistry == null) {
throw new java.lang.NullPointerException();
}
com.google.protobuf.UnknownFieldSet.Builder unknownFields =
com.google.protobuf.UnknownFieldSet.newBuilder();
try {
boolean done = false;
while (!done) {
int tag = input.readTag();
switch (tag) {
case 0:
done = true;
break;
case 56: {
reviseLevel_ = input.readUInt32();
break;
}
case 112: {
dungeonId_ = input.readUInt32();
break;
}
default: {
if (!parseUnknownField(
input, unknownFields, extensionRegistry, tag)) {
done = true;
}
break;
}
}
}
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
throw e.setUnfinishedMessage(this);
} catch (java.io.IOException e) {
throw new com.google.protobuf.InvalidProtocolBufferException(
e).setUnfinishedMessage(this);
} finally {
this.unknownFields = unknownFields.build();
makeExtensionsImmutable();
}
}
public static final com.google.protobuf.Descriptors.Descriptor
getDescriptor() {
return emu.grasscutter.net.proto.DungeonReviseLevelNotifyOuterClass.internal_static_DungeonReviseLevelNotify_descriptor;
}
@java.lang.Override
protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
internalGetFieldAccessorTable() {
return emu.grasscutter.net.proto.DungeonReviseLevelNotifyOuterClass.internal_static_DungeonReviseLevelNotify_fieldAccessorTable
.ensureFieldAccessorsInitialized(
emu.grasscutter.net.proto.DungeonReviseLevelNotifyOuterClass.DungeonReviseLevelNotify.class, emu.grasscutter.net.proto.DungeonReviseLevelNotifyOuterClass.DungeonReviseLevelNotify.Builder.class);
}
public static final int REVISE_LEVEL_FIELD_NUMBER = 7;
private int reviseLevel_;
/**
* <code>uint32 revise_level = 7;</code>
* @return The reviseLevel.
*/
@java.lang.Override
public int getReviseLevel() {
return reviseLevel_;
}
public static final int DUNGEON_ID_FIELD_NUMBER = 14;
private int dungeonId_;
/**
* <code>uint32 dungeon_id = 14;</code>
* @return The dungeonId.
*/
@java.lang.Override
public int getDungeonId() {
return dungeonId_;
}
private byte memoizedIsInitialized = -1;
@java.lang.Override
public final boolean isInitialized() {
byte isInitialized = memoizedIsInitialized;
if (isInitialized == 1) return true;
if (isInitialized == 0) return false;
memoizedIsInitialized = 1;
return true;
}
@java.lang.Override
public void writeTo(com.google.protobuf.CodedOutputStream output)
throws java.io.IOException {
if (reviseLevel_ != 0) {
output.writeUInt32(7, reviseLevel_);
}
if (dungeonId_ != 0) {
output.writeUInt32(14, dungeonId_);
}
unknownFields.writeTo(output);
}
@java.lang.Override
public int getSerializedSize() {
int size = memoizedSize;
if (size != -1) return size;
size = 0;
if (reviseLevel_ != 0) {
size += com.google.protobuf.CodedOutputStream
.computeUInt32Size(7, reviseLevel_);
}
if (dungeonId_ != 0) {
size += com.google.protobuf.CodedOutputStream
.computeUInt32Size(14, dungeonId_);
}
size += unknownFields.getSerializedSize();
memoizedSize = size;
return size;
}
@java.lang.Override
public boolean equals(final java.lang.Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof emu.grasscutter.net.proto.DungeonReviseLevelNotifyOuterClass.DungeonReviseLevelNotify)) {
return super.equals(obj);
}
emu.grasscutter.net.proto.DungeonReviseLevelNotifyOuterClass.DungeonReviseLevelNotify other = (emu.grasscutter.net.proto.DungeonReviseLevelNotifyOuterClass.DungeonReviseLevelNotify) obj;
if (getReviseLevel()
!= other.getReviseLevel()) return false;
if (getDungeonId()
!= other.getDungeonId()) return false;
if (!unknownFields.equals(other.unknownFields)) return false;
return true;
}
@java.lang.Override
public int hashCode() {
if (memoizedHashCode != 0) {
return memoizedHashCode;
}
int hash = 41;
hash = (19 * hash) + getDescriptor().hashCode();
hash = (37 * hash) + REVISE_LEVEL_FIELD_NUMBER;
hash = (53 * hash) + getReviseLevel();
hash = (37 * hash) + DUNGEON_ID_FIELD_NUMBER;
hash = (53 * hash) + getDungeonId();
hash = (29 * hash) + unknownFields.hashCode();
memoizedHashCode = hash;
return hash;
}
public static emu.grasscutter.net.proto.DungeonReviseLevelNotifyOuterClass.DungeonReviseLevelNotify parseFrom(
java.nio.ByteBuffer data)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data);
}
public static emu.grasscutter.net.proto.DungeonReviseLevelNotifyOuterClass.DungeonReviseLevelNotify parseFrom(
java.nio.ByteBuffer data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data, extensionRegistry);
}
public static emu.grasscutter.net.proto.DungeonReviseLevelNotifyOuterClass.DungeonReviseLevelNotify parseFrom(
com.google.protobuf.ByteString data)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data);
}
public static emu.grasscutter.net.proto.DungeonReviseLevelNotifyOuterClass.DungeonReviseLevelNotify parseFrom(
com.google.protobuf.ByteString data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data, extensionRegistry);
}
public static emu.grasscutter.net.proto.DungeonReviseLevelNotifyOuterClass.DungeonReviseLevelNotify parseFrom(byte[] data)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data);
}
public static emu.grasscutter.net.proto.DungeonReviseLevelNotifyOuterClass.DungeonReviseLevelNotify parseFrom(
byte[] data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data, extensionRegistry);
}
public static emu.grasscutter.net.proto.DungeonReviseLevelNotifyOuterClass.DungeonReviseLevelNotify parseFrom(java.io.InputStream input)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageV3
.parseWithIOException(PARSER, input);
}
public static emu.grasscutter.net.proto.DungeonReviseLevelNotifyOuterClass.DungeonReviseLevelNotify parseFrom(
java.io.InputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageV3
.parseWithIOException(PARSER, input, extensionRegistry);
}
public static emu.grasscutter.net.proto.DungeonReviseLevelNotifyOuterClass.DungeonReviseLevelNotify parseDelimitedFrom(java.io.InputStream input)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageV3
.parseDelimitedWithIOException(PARSER, input);
}
public static emu.grasscutter.net.proto.DungeonReviseLevelNotifyOuterClass.DungeonReviseLevelNotify parseDelimitedFrom(
java.io.InputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageV3
.parseDelimitedWithIOException(PARSER, input, extensionRegistry);
}
public static emu.grasscutter.net.proto.DungeonReviseLevelNotifyOuterClass.DungeonReviseLevelNotify parseFrom(
com.google.protobuf.CodedInputStream input)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageV3
.parseWithIOException(PARSER, input);
}
public static emu.grasscutter.net.proto.DungeonReviseLevelNotifyOuterClass.DungeonReviseLevelNotify parseFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageV3
.parseWithIOException(PARSER, input, extensionRegistry);
}
@java.lang.Override
public Builder newBuilderForType() { return newBuilder(); }
public static Builder newBuilder() {
return DEFAULT_INSTANCE.toBuilder();
}
public static Builder newBuilder(emu.grasscutter.net.proto.DungeonReviseLevelNotifyOuterClass.DungeonReviseLevelNotify prototype) {
return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);
}
@java.lang.Override
public Builder toBuilder() {
return this == DEFAULT_INSTANCE
? new Builder() : new Builder().mergeFrom(this);
}
@java.lang.Override
protected Builder newBuilderForType(
com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
Builder builder = new Builder(parent);
return builder;
}
/**
* <pre>
* CmdId: 968
* EnetChannelId: 0
* EnetIsReliable: true
* IsAllowClient: true
* </pre>
*
* Protobuf type {@code DungeonReviseLevelNotify}
*/
public static final class Builder extends
com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements
// @@protoc_insertion_point(builder_implements:DungeonReviseLevelNotify)
emu.grasscutter.net.proto.DungeonReviseLevelNotifyOuterClass.DungeonReviseLevelNotifyOrBuilder {
public static final com.google.protobuf.Descriptors.Descriptor
getDescriptor() {
return emu.grasscutter.net.proto.DungeonReviseLevelNotifyOuterClass.internal_static_DungeonReviseLevelNotify_descriptor;
}
@java.lang.Override
protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
internalGetFieldAccessorTable() {
return emu.grasscutter.net.proto.DungeonReviseLevelNotifyOuterClass.internal_static_DungeonReviseLevelNotify_fieldAccessorTable
.ensureFieldAccessorsInitialized(
emu.grasscutter.net.proto.DungeonReviseLevelNotifyOuterClass.DungeonReviseLevelNotify.class, emu.grasscutter.net.proto.DungeonReviseLevelNotifyOuterClass.DungeonReviseLevelNotify.Builder.class);
}
// Construct using emu.grasscutter.net.proto.DungeonReviseLevelNotifyOuterClass.DungeonReviseLevelNotify.newBuilder()
private Builder() {
maybeForceBuilderInitialization();
}
private Builder(
com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
super(parent);
maybeForceBuilderInitialization();
}
private void maybeForceBuilderInitialization() {
if (com.google.protobuf.GeneratedMessageV3
.alwaysUseFieldBuilders) {
}
}
@java.lang.Override
public Builder clear() {
super.clear();
reviseLevel_ = 0;
dungeonId_ = 0;
return this;
}
@java.lang.Override
public com.google.protobuf.Descriptors.Descriptor
getDescriptorForType() {
return emu.grasscutter.net.proto.DungeonReviseLevelNotifyOuterClass.internal_static_DungeonReviseLevelNotify_descriptor;
}
@java.lang.Override
public emu.grasscutter.net.proto.DungeonReviseLevelNotifyOuterClass.DungeonReviseLevelNotify getDefaultInstanceForType() {
return emu.grasscutter.net.proto.DungeonReviseLevelNotifyOuterClass.DungeonReviseLevelNotify.getDefaultInstance();
}
@java.lang.Override
public emu.grasscutter.net.proto.DungeonReviseLevelNotifyOuterClass.DungeonReviseLevelNotify build() {
emu.grasscutter.net.proto.DungeonReviseLevelNotifyOuterClass.DungeonReviseLevelNotify result = buildPartial();
if (!result.isInitialized()) {
throw newUninitializedMessageException(result);
}
return result;
}
@java.lang.Override
public emu.grasscutter.net.proto.DungeonReviseLevelNotifyOuterClass.DungeonReviseLevelNotify buildPartial() {
emu.grasscutter.net.proto.DungeonReviseLevelNotifyOuterClass.DungeonReviseLevelNotify result = new emu.grasscutter.net.proto.DungeonReviseLevelNotifyOuterClass.DungeonReviseLevelNotify(this);
result.reviseLevel_ = reviseLevel_;
result.dungeonId_ = dungeonId_;
onBuilt();
return result;
}
@java.lang.Override
public Builder clone() {
return super.clone();
}
@java.lang.Override
public Builder setField(
com.google.protobuf.Descriptors.FieldDescriptor field,
java.lang.Object value) {
return super.setField(field, value);
}
@java.lang.Override
public Builder clearField(
com.google.protobuf.Descriptors.FieldDescriptor field) {
return super.clearField(field);
}
@java.lang.Override
public Builder clearOneof(
com.google.protobuf.Descriptors.OneofDescriptor oneof) {
return super.clearOneof(oneof);
}
@java.lang.Override
public Builder setRepeatedField(
com.google.protobuf.Descriptors.FieldDescriptor field,
int index, java.lang.Object value) {
return super.setRepeatedField(field, index, value);
}
@java.lang.Override
public Builder addRepeatedField(
com.google.protobuf.Descriptors.FieldDescriptor field,
java.lang.Object value) {
return super.addRepeatedField(field, value);
}
@java.lang.Override
public Builder mergeFrom(com.google.protobuf.Message other) {
if (other instanceof emu.grasscutter.net.proto.DungeonReviseLevelNotifyOuterClass.DungeonReviseLevelNotify) {
return mergeFrom((emu.grasscutter.net.proto.DungeonReviseLevelNotifyOuterClass.DungeonReviseLevelNotify)other);
} else {
super.mergeFrom(other);
return this;
}
}
public Builder mergeFrom(emu.grasscutter.net.proto.DungeonReviseLevelNotifyOuterClass.DungeonReviseLevelNotify other) {
if (other == emu.grasscutter.net.proto.DungeonReviseLevelNotifyOuterClass.DungeonReviseLevelNotify.getDefaultInstance()) return this;
if (other.getReviseLevel() != 0) {
setReviseLevel(other.getReviseLevel());
}
if (other.getDungeonId() != 0) {
setDungeonId(other.getDungeonId());
}
this.mergeUnknownFields(other.unknownFields);
onChanged();
return this;
}
@java.lang.Override
public final boolean isInitialized() {
return true;
}
@java.lang.Override
public Builder mergeFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
emu.grasscutter.net.proto.DungeonReviseLevelNotifyOuterClass.DungeonReviseLevelNotify parsedMessage = null;
try {
parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
parsedMessage = (emu.grasscutter.net.proto.DungeonReviseLevelNotifyOuterClass.DungeonReviseLevelNotify) e.getUnfinishedMessage();
throw e.unwrapIOException();
} finally {
if (parsedMessage != null) {
mergeFrom(parsedMessage);
}
}
return this;
}
private int reviseLevel_ ;
/**
* <code>uint32 revise_level = 7;</code>
* @return The reviseLevel.
*/
@java.lang.Override
public int getReviseLevel() {
return reviseLevel_;
}
/**
* <code>uint32 revise_level = 7;</code>
* @param value The reviseLevel to set.
* @return This builder for chaining.
*/
public Builder setReviseLevel(int value) {
reviseLevel_ = value;
onChanged();
return this;
}
/**
* <code>uint32 revise_level = 7;</code>
* @return This builder for chaining.
*/
public Builder clearReviseLevel() {
reviseLevel_ = 0;
onChanged();
return this;
}
private int dungeonId_ ;
/**
* <code>uint32 dungeon_id = 14;</code>
* @return The dungeonId.
*/
@java.lang.Override
public int getDungeonId() {
return dungeonId_;
}
/**
* <code>uint32 dungeon_id = 14;</code>
* @param value The dungeonId to set.
* @return This builder for chaining.
*/
public Builder setDungeonId(int value) {
dungeonId_ = value;
onChanged();
return this;
}
/**
* <code>uint32 dungeon_id = 14;</code>
* @return This builder for chaining.
*/
public Builder clearDungeonId() {
dungeonId_ = 0;
onChanged();
return this;
}
@java.lang.Override
public final Builder setUnknownFields(
final com.google.protobuf.UnknownFieldSet unknownFields) {
return super.setUnknownFields(unknownFields);
}
@java.lang.Override
public final Builder mergeUnknownFields(
final com.google.protobuf.UnknownFieldSet unknownFields) {
return super.mergeUnknownFields(unknownFields);
}
// @@protoc_insertion_point(builder_scope:DungeonReviseLevelNotify)
}
// @@protoc_insertion_point(class_scope:DungeonReviseLevelNotify)
private static final emu.grasscutter.net.proto.DungeonReviseLevelNotifyOuterClass.DungeonReviseLevelNotify DEFAULT_INSTANCE;
static {
DEFAULT_INSTANCE = new emu.grasscutter.net.proto.DungeonReviseLevelNotifyOuterClass.DungeonReviseLevelNotify();
}
public static emu.grasscutter.net.proto.DungeonReviseLevelNotifyOuterClass.DungeonReviseLevelNotify getDefaultInstance() {
return DEFAULT_INSTANCE;
}
private static final com.google.protobuf.Parser<DungeonReviseLevelNotify>
PARSER = new com.google.protobuf.AbstractParser<DungeonReviseLevelNotify>() {
@java.lang.Override
public DungeonReviseLevelNotify parsePartialFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return new DungeonReviseLevelNotify(input, extensionRegistry);
}
};
public static com.google.protobuf.Parser<DungeonReviseLevelNotify> parser() {
return PARSER;
}
@java.lang.Override
public com.google.protobuf.Parser<DungeonReviseLevelNotify> getParserForType() {
return PARSER;
}
@java.lang.Override
public emu.grasscutter.net.proto.DungeonReviseLevelNotifyOuterClass.DungeonReviseLevelNotify getDefaultInstanceForType() {
return DEFAULT_INSTANCE;
}
}
private static final com.google.protobuf.Descriptors.Descriptor
internal_static_DungeonReviseLevelNotify_descriptor;
private static final
com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
internal_static_DungeonReviseLevelNotify_fieldAccessorTable;
public static com.google.protobuf.Descriptors.FileDescriptor
getDescriptor() {
return descriptor;
}
private static com.google.protobuf.Descriptors.FileDescriptor
descriptor;
static {
java.lang.String[] descriptorData = {
"\n\036DungeonReviseLevelNotify.proto\"D\n\030Dung" +
"eonReviseLevelNotify\022\024\n\014revise_level\030\007 \001" +
"(\r\022\022\n\ndungeon_id\030\016 \001(\rB\033\n\031emu.grasscutte" +
"r.net.protob\006proto3"
};
descriptor = com.google.protobuf.Descriptors.FileDescriptor
.internalBuildGeneratedFileFrom(descriptorData,
new com.google.protobuf.Descriptors.FileDescriptor[] {
});
internal_static_DungeonReviseLevelNotify_descriptor =
getDescriptor().getMessageTypes().get(0);
internal_static_DungeonReviseLevelNotify_fieldAccessorTable = new
com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
internal_static_DungeonReviseLevelNotify_descriptor,
new java.lang.String[] { "ReviseLevel", "DungeonId", });
}
// @@protoc_insertion_point(outer_class_scope)
}

View File

@ -1,5 +1,8 @@
package emu.grasscutter;
import java.time.DayOfWeek;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import emu.grasscutter.utils.Position;
@ -24,6 +27,14 @@ public final class GameConstants {
public static final int BATTLE_PASS_POINT_PER_WEEK = 10000;
public static final int BATTLE_PASS_LEVEL_PRICE = 150;
public static final int BATTLE_PASS_CURRENT_INDEX = 2;
public static final String TIME_ZONE = "Asia/Shanghai";
public static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
public static final ZoneId ZONE_ID = ZoneId.of(TIME_ZONE);
public static final DayOfWeek WEEKLY_BOSS_RESIN_DISCOUNT_REFRESH_DAY = DayOfWeek.MONDAY;
public static final int WEEKLY_BOSS_RESIN_DISCOUNT_REFRESH_DAY_INTERVAL = 7;
public static final int REFRESH_HOUR = 4;
public static final int WEEKLY_BOSS_RESIN_DISCOUNT_COUNT = 3;
public static final float WEEKLY_BOSS_RESIN_DISCOUNT_VALUE = 0.5f;
// Default entity ability hashes.
public static final String[] DEFAULT_ABILITY_STRINGS = {

View File

@ -82,8 +82,8 @@ public final class SetConstCommand implements CommandHandler {
World world = player.getWorld();
Scene scene = player.getScene();
Position pos = player.getPosition();
world.transferPlayerToScene(player, 1, pos);
world.transferPlayerToScene(player, scene.getId(), pos);
world.transferPlayerToScene(player, 1, pos, null);
world.transferPlayerToScene(player, scene.getId(), pos, null);
scene.broadcastPacket(new PacketSceneEntityAppearNotify(player));
}
}

View File

@ -23,7 +23,7 @@ public final class TeleportAllCommand implements CommandHandler {
if (player.equals(targetPlayer))
continue;
player.getWorld().transferPlayerToScene(player, targetPlayer.getSceneId(), TeleportType.COMMAND, targetPlayer.getPosition());
player.getWorld().transferPlayerToScene(player, targetPlayer.getSceneId(), TeleportType.COMMAND, targetPlayer.getPosition(), null);
}
CommandHandler.sendMessage(sender, translate(sender, "commands.teleportAll.success"));

View File

@ -54,7 +54,7 @@ public final class TeleportCommand implements CommandHandler {
}
Position target_pos = new Position(x, y, z);
boolean result = targetPlayer.getWorld().transferPlayerToScene(targetPlayer, sceneId, TeleportType.COMMAND, target_pos);
boolean result = targetPlayer.getWorld().transferPlayerToScene(targetPlayer, sceneId, TeleportType.COMMAND, target_pos, null);
if (!result) {
CommandHandler.sendMessage(sender, translate(sender, "commands.teleport.exists_error"));

View File

@ -14,6 +14,7 @@ import emu.grasscutter.data.binout.config.ConfigEntityGadget;
import emu.grasscutter.data.binout.config.ConfigEntityMonster;
import emu.grasscutter.data.binout.config.ConfigGlobalCombat;
import emu.grasscutter.data.binout.config.ConfigLevelEntity;
import emu.grasscutter.game.dungeons.dungeon_entry.DungeonEntries;
import emu.grasscutter.data.common.quest.MainQuestData;
import emu.grasscutter.data.common.quest.SubQuestData;
import emu.grasscutter.data.binout.routes.Route;
@ -59,6 +60,7 @@ public class GameData {
@Getter private static final Map<String, ConfigEntityMonster> monsterConfigData = new HashMap<>();
@Getter private static final Map<String, OpenConfigEntry> openConfigEntries = new HashMap<>();
@Deprecated(forRemoval = true) @Getter private static final Map<String, ScenePointEntry> scenePointEntries = new HashMap<>();
@Getter private static final Int2ObjectMap<DungeonEntries> dungeonEntriesMap = new Int2ObjectOpenHashMap<>();
protected static final Map<String, AbilityData> abilityDataMap = new HashMap<>();
protected static final Int2ObjectMap<ScenePointEntry> scenePointEntryMap = new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<MainQuestData> mainQuestData = new Int2ObjectOpenHashMap<>();
@ -110,6 +112,8 @@ public class GameData {
@Getter private static final Int2ObjectMap<DungeonData> dungeonDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<DungeonElementChallengeData> dungeonElementChallengeDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<DungeonEntryData> dungeonEntryDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<DungeonRosterData> dungeonRosterDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<DungeonSerialData> dungeonSerialDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<EnvAnimalGatherConfigData> envAnimalGatherConfigDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<EquipAffixData> equipAffixDataMap = new Int2ObjectOpenHashMap<>();
@Getter private static final Int2ObjectMap<MonsterAffixData> monsterAffixDataMap = new Int2ObjectOpenHashMap<>();

View File

@ -3,12 +3,12 @@ package emu.grasscutter.data;
import com.google.gson.annotations.SerializedName;
import com.google.gson.reflect.TypeToken;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.Loggers;
import emu.grasscutter.data.binout.*;
import emu.grasscutter.data.binout.AbilityModifier.AbilityModifierAction;
import emu.grasscutter.data.binout.config.*;
import emu.grasscutter.data.binout.config.fields.ConfigAbilityData;
import emu.grasscutter.game.dungeons.dungeon_entry.DungeonEntries;
import emu.grasscutter.data.common.quest.MainQuestData;
import emu.grasscutter.data.common.quest.SubQuestData;
import emu.grasscutter.data.binout.routes.SceneRoutes;
@ -23,11 +23,13 @@ import emu.grasscutter.data.server.MonsterMapping;
import emu.grasscutter.data.server.SubfieldMapping;
import emu.grasscutter.game.ability.Ability;
import emu.grasscutter.game.dungeons.DungeonDrop;
import emu.grasscutter.game.dungeons.enums.DungeonType;
import emu.grasscutter.game.managers.blossom.BlossomConfig;
import emu.grasscutter.game.quest.QuestEncryptionKey;
import emu.grasscutter.game.quest.RewindData;
import emu.grasscutter.game.quest.TeleportData;
import emu.grasscutter.game.quest.enums.QuestCond;
import emu.grasscutter.game.quest.enums.QuestContent;
import emu.grasscutter.game.world.GroupReplacementData;
import emu.grasscutter.game.world.SpawnDataEntry;
import emu.grasscutter.game.world.SpawnDataEntry.GridBlockId;
@ -53,12 +55,11 @@ import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.regex.Pattern;
import java.util.stream.Stream;
import java.util.stream.Collectors;
import java.util.Map.Entry;
import javax.script.Bindings;
import javax.script.CompiledScript;
import static emu.grasscutter.utils.FileUtils.getDataPath;
import static emu.grasscutter.utils.FileUtils.getResourcePath;
@ -129,6 +130,7 @@ public class ResourceLoader {
loadDungeonDrops();
// Load scene points - must be done AFTER resources are loaded
loadScenePoints();
loadDungeonEntryAndExitPoints();
// Load default home layout
loadHomeworldDefaultSaveData();
loadNpcBornData();
@ -248,13 +250,15 @@ public class ResourceLoader {
val scenePoints = new IntArrayList();
config.points.forEach((pointId, pointData) -> {
val scenePoint = new ScenePointEntry(sceneId, pointData);
scenePoints.add(pointId);
scenePoints.add(pointId.intValue());
pointData.setId(pointId);
pointData.setSceneId(sceneId);
GameData.getScenePointIdList().add(pointId);
GameData.getScenePointIdList().add(pointId.intValue());
GameData.getScenePointEntries().put(scenePoint.getName(), scenePoint);
GameData.scenePointEntryMap.put((sceneId << 16) + pointId, scenePoint);
pointData.onLoad();
pointData.updateDailyDungeon();
});
GameData.getScenePointsPerScene().put(sceneId, scenePoints);
@ -264,6 +268,56 @@ public class ResourceLoader {
}
}
/**
* Pre-make dungeon entries and exits using existing map for easier information retrieve
* Some dungeon exits not included like trial avatar activity and mist trial activity, player
* should transfer back to where they were
* TODO there are 2 special dungeon entries not included so far, which is amber dungeon(2002) and one of summerV2 event dungeon(4038)
* */
private static void loadDungeonEntryAndExitPoints() {
val tempEntriesMap = GameData.getDungeonEntriesMap();
val tempExitHolderMap = GameData.scenePointEntryMap.values().stream().parallel().map(ScenePointEntry::getPointData)
.filter(pointData -> pointData.getType().equals("DungeonExit")).filter(pointData -> pointData.getEntryPointId() > 0)
.collect(Collectors.toMap(pointData -> (pointData.getSceneId() << 16) + pointData.getEntryPointId(), pointData -> pointData));
GameData.scenePointEntryMap.values().stream().map(ScenePointEntry::getPointData)
.filter(pointData -> pointData.getType().equals("DungeonEntry"))
.forEach(pointData -> {
val loadedDungeonIds = new AtomicBoolean(false);
Optional.ofNullable(pointData.getAllDungeonIds()).stream().flatMap(List::stream).forEach(dungeonId -> {
loadedDungeonIds.set(true);
tempEntriesMap.putIfAbsent(dungeonId, DungeonEntries.create(dungeonId, pointData, tempExitHolderMap));
});
if (loadedDungeonIds.get()) return;
val dungeonType = switch (pointData.getDungeonEntryType()) {
case "Tower" -> DungeonType.DUNGEON_TOWER;
case "RogueDiary" -> DungeonType.DUNGEON_ROGUELIKE;
case "Effigy" -> DungeonType.DUNGEON_EFFIGY;
default -> DungeonType.DUNGEON_NONE;
};
GameData.getDungeonDataMap().values().stream().filter(dungeonData -> dungeonData.getType() == dungeonType)
.forEach(dungeonData -> tempEntriesMap.putIfAbsent(
dungeonData.getId(), DungeonEntries.create(dungeonData.getId(), pointData, tempExitHolderMap)));
});
GameData.getQuestDataMap().values().forEach(data -> Optional.ofNullable(data.getGuide())
.map(SubQuestData.Guide::getGuideScene).ifPresent(sceneId -> data.getFinishCond().stream()
.filter(c -> c.getType() == QuestContent.QUEST_CONTENT_ENTER_DUNGEON)
.filter(c -> !tempEntriesMap.containsKey(c.getParam()[0])).forEach(cond -> {
val scenePointEntry = GameData.getScenePointEntryById(sceneId == 0 ? 3 : sceneId, cond.getParam()[1]);
if (scenePointEntry == null) {
// Grasscutter.getLogger().info("MainQuest: {}, SubQuest: {}", data.getMainId(), data.getSubId());
// Grasscutter.getLogger().info("SceneId: {}, PointId: {}, dungeonId: {}", sceneId, cond.getParam()[1], cond.getParam()[0]);
return;
}
tempEntriesMap.putIfAbsent(cond.getParam()[0],
DungeonEntries.create(cond.getParam()[0], scenePointEntry.getPointData(), tempExitHolderMap));
})));
}
private static void cacheTalentLevelSets() {
// All known levels, keyed by proudSkillGroupId
GameData.getProudSkillDataMap().forEach((id, data) ->

View File

@ -5,54 +5,92 @@ import com.google.gson.annotations.SerializedName;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.excels.DailyDungeonData;
import emu.grasscutter.data.excels.DungeonRosterData;
import emu.grasscutter.utils.Position;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
import lombok.Getter;
import lombok.Setter;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Collection;
@Data
@EqualsAndHashCode(callSuper = false)
@SuppressWarnings(value = "SpellCheckingInspection")
public class PointData {
@Getter @Setter private int id;
private int id;
private int sceneId;
private String $type;
@Getter private Position tranPos;
@Getter private Position pos;
@Getter private Position rot;
@Getter private Position size;
private Position tranPos;
private Position tranRot;
private Position pos;
private Position rot;
private Position size;
@SerializedName(value="dungeonIds", alternate={"JHHFPGJNMIN"})
@Getter private int[] dungeonIds;
private int[] dungeonIds;
@SerializedName(value="dungeonRandomList", alternate={"OIBKFJNBLHO"})
@Getter private int[] dungeonRandomList;
private int[] dungeonRandomList;
private int[] dungeonRosterList;
@SerializedName(value="groupIDs", alternate={"HFOBOOHKBGF"})
@Getter private int[] groupIDs;
private int[] groupIds;
@SerializedName(value="tranSceneId", alternate={"JHBICGBAPIH"})
@Getter @Setter private int tranSceneId;
private int tranSceneId;
private int entryPointId;
@SerializedName(value="dungeonEntryType", alternate={"EJFPAJGPEBH"})
private String dungeonEntryType;
// all dungeons that should appear in this entry, regardless of showing conditions
private List<Integer> allDungeonIds;
public String getType() {
return $type;
return this.$type;
}
public void onLoad() {
if (this.dungeonEntryType == null) {
this.dungeonEntryType = "";
}
if (this.dungeonRandomList != null && this.dungeonRandomList.length > 0) {
this.allDungeonIds = Arrays.stream(this.dungeonRandomList)
.mapToObj(GameData.getDailyDungeonDataMap()::get).filter(Objects::nonNull)
.map(DailyDungeonData::getMap).map(Map::values)
.flatMap(Collection::stream).flatMapToInt(Arrays::stream)
.distinct().boxed().toList();
}
if (this.dungeonRosterList != null && this.dungeonRosterList.length > 0) {
this.allDungeonIds = Arrays.stream(this.dungeonRosterList)
.mapToObj(GameData.getDungeonRosterDataMap()::get).filter(Objects::nonNull)
.map(DungeonRosterData::getRosterPool).flatMap(List::stream)
.map(DungeonRosterData.RosterPool::getDungeonList).flatMapToInt(Arrays::stream)
.distinct().boxed().toList();
}
if (this.dungeonIds != null && this.dungeonIds.length > 0) {
this.allDungeonIds = Arrays.stream(this.dungeonIds).boxed().toList();
}
if (this.tranPos == null) { // should only happen for dungeon exit points
this.tranPos = this.pos;
}
if (this.tranRot == null) { // should only happen for dungeon exit points
this.tranRot = this.rot;
}
}
public void updateDailyDungeon() {
if (this.dungeonRandomList == null || this.dungeonRandomList.length == 0) {
return;
if (this.dungeonRandomList != null && this.dungeonRandomList.length > 0) {
this.dungeonIds = Arrays.stream(this.dungeonRandomList)
.mapToObj(GameData.getDailyDungeonDataMap()::get).filter(Objects::nonNull)
.map(data -> data.getDungeonsByDay(Grasscutter.getCurrentDayOfWeek()))
.flatMapToInt(Arrays::stream)
.filter(GameData.getDungeonDataMap()::containsKey)
.toArray();
}
IntList newDungeons = new IntArrayList();
int day = Grasscutter.getCurrentDayOfWeek();
for (int randomId : this.dungeonRandomList) {
DailyDungeonData data = GameData.getDailyDungeonDataMap().get(randomId);
if (data != null) {
for (int d : data.getDungeonsByDay(day)) {
newDungeons.add(d);
}
}
}
this.dungeonIds = newDungeons.toIntArray();
}
}

View File

@ -22,7 +22,7 @@ public class DailyDungeonData extends GameResource {
private int[] sunday;
private static final int[] empty = new int[0];
private final Int2ObjectMap<int[]> map;
@Getter private final Int2ObjectMap<int[]> map;
public DailyDungeonData() {
this.map = new Int2ObjectOpenHashMap<>();

View File

@ -1,70 +1,69 @@
package emu.grasscutter.data.excels;
import com.google.gson.annotations.SerializedName;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType;
import emu.grasscutter.game.dungeons.enums.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
import java.util.List;
import java.util.Optional;
@EqualsAndHashCode(callSuper = false)
@ResourceType(name = "DungeonExcelConfigData.json")
@ToString
@Data
public class DungeonData extends GameResource {
@Getter(onMethod = @__(@Override))
private int id;
@Getter private int sceneId;
@Getter private int showLevel;
private int id;
private int serialId;
private int sceneId;
private int showLevel;
private int levelRevise;
private DungeonType type;
private DungeonSubType subType;
private DungeonPlayType playType;
private DungeonInvolveType involveType;
@Getter private int limitLevel;
@Getter private int passCond;
@Getter private int reviveMaxCount;
@Getter private int settleCountdownTime;
@Getter private int failSettleCountdownTime;
@Getter private int quitSettleCountdownTime;
@Getter private List<SettleShowType> settleShows;
@Getter private int passRewardPreviewID;
@Getter private int statueCostID;
@Getter private int statueCostCount;
private int limitLevel;
private int passCond;
private int reviveMaxCount;
private int settleCountdownTime;
private int failSettleCountdownTime;
private int quitSettleCountdownTime;
private List<SettleShowType> settleShows;
@SerializedName(value = "passRewardPreviewID", alternate = {"passRewardPreviewId"})
private int passRewardPreviewId;
private int statueCostID;
private int statueCostCount;
private String stateType;
// not part of DungeonExcelConfigData
@Getter private RewardPreviewData rewardPreviewData;
private RewardPreviewData rewardPreviewData;
public DungeonType getType() {
if (type == null) {
return DungeonType.DUNGEON_NONE;
}
return type;
return Optional.ofNullable(this.type).orElse(DungeonType.DUNGEON_NONE);
}
public DungeonSubType getSubType() {
if (subType == null) {
return DungeonSubType.DUNGEON_SUB_NONE;
}
return subType;
return Optional.ofNullable(this.subType).orElse(DungeonSubType.DUNGEON_SUB_NONE);
}
public DungeonPlayType getPlayType() {
if (playType == null) {
return DungeonPlayType.DUNGEON_PLAY_TYPE_NONE;
}
return playType;
return Optional.ofNullable(this.playType).orElse(DungeonPlayType.DUNGEON_PLAY_TYPE_NONE);
}
public DungeonInvolveType getInvolveType() {
if (involveType == null) {
return DungeonInvolveType.INVOLVE_NONE;
}
return involveType;
return Optional.ofNullable(this.involveType).orElse(DungeonInvolveType.INVOLVE_NONE);
}
@Override
public void onLoad() {
if (this.passRewardPreviewID > 0) {
this.rewardPreviewData = GameData.getRewardPreviewDataMap().get(this.passRewardPreviewID);
}
}
@Override
public void onLoad() {
Optional.ofNullable(GameData.getRewardPreviewDataMap().get(this.passRewardPreviewId))
.ifPresent(d -> this.rewardPreviewData = d);
}
}

View File

@ -6,14 +6,14 @@ import emu.grasscutter.game.dungeons.enums.DungeonEntrySatisfiedConditionType;
import emu.grasscutter.game.dungeons.enums.DungunEntryType;
import emu.grasscutter.game.quest.enums.LogicType;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@ResourceType(name = "DungeonEntryExcelConfigData.json")
@Getter
@Setter // TODO: remove this next API break
@EqualsAndHashCode(callSuper = false)
@Data // TODO: remove this next API break
public class DungeonEntryData extends GameResource {
@Getter(onMethod = @__(@Override))
private int id;
@ -28,7 +28,7 @@ public class DungeonEntryData extends GameResource {
@Data
public static class SatisfiedCond{
DungeonEntrySatisfiedConditionType type;
int param1;
private DungeonEntrySatisfiedConditionType type;
private int param1;
}
}

View File

@ -0,0 +1,46 @@
package emu.grasscutter.data.excels;
import emu.grasscutter.GameConstants;
import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import java.time.ZonedDateTime;
import java.util.List;
import java.util.Optional;
@ResourceType(name = "DungeonRosterConfigData.json")
@Data
@EqualsAndHashCode(callSuper = false)
public class DungeonRosterData extends GameResource {
@Getter(onMethod = @__(@Override))
private int id;
private String openTimeStr;
private int cycleTime; // in hours
private String cycleType;
private List<RosterPool> rosterPool;
@Override
public void onLoad() {
this.rosterPool = this.rosterPool.stream()
.filter(pool -> Optional.ofNullable(pool.dungeonList).filter(l -> l.length > 0).isPresent())
.toList();
}
public boolean nowIsAfterOpenTime() {
return ZonedDateTime.now(GameConstants.ZONE_ID).isAfter(ZonedDateTime.parse(
this.openTimeStr, GameConstants.TIME_FORMATTER.withZone(GameConstants.ZONE_ID)));
}
public int getNextPool(int previousPool) {
return (previousPool + 1) % this.rosterPool.size();
}
@Data
public static class RosterPool {
int[] dungeonList;
}
}

View File

@ -0,0 +1,17 @@
package emu.grasscutter.data.excels;
import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Getter;
@ResourceType(name = "DungeonSerialConfigData.json")
@Data
@EqualsAndHashCode(callSuper = false)
public class DungeonSerialData extends GameResource {
@Getter(onMethod = @__(@Override))
private int id;
private int maxTakeNum;
private int takeCost;
}

View File

@ -3,9 +3,11 @@ package emu.grasscutter.game.activity.trialavatar;
import com.esotericsoftware.reflectasm.ConstructorAccess;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.excels.RewardData;
import emu.grasscutter.data.excels.ActivityWatcherData;
import emu.grasscutter.data.excels.TrialAvatarActivityDataData;
import emu.grasscutter.game.activity.ActivityWatcher;
import emu.grasscutter.game.activity.DefaultWatcher;
import emu.grasscutter.game.dungeons.settle_listeners.TrialAvatarDungeonSettleListener;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.ActionReason;
import emu.grasscutter.game.props.WatcherTriggerType;
@ -14,44 +16,40 @@ import emu.grasscutter.game.activity.GameActivity;
import emu.grasscutter.game.activity.PlayerActivityData;
import emu.grasscutter.game.props.ActivityType;
import emu.grasscutter.net.proto.ActivityInfoOuterClass.ActivityInfo;
import emu.grasscutter.net.proto.TrialAvatarGrantRecordOuterClass.TrialAvatarGrantRecord.GrantReason;
import emu.grasscutter.server.packet.send.PacketActivityInfoNotify;
import emu.grasscutter.server.packet.send.PacketScenePlayerLocationNotify;
import emu.grasscutter.utils.JsonUtils;
import java.util.*;
import java.util.stream.*;
import lombok.*;
import org.jetbrains.annotations.NotNull;
@GameActivity(ActivityType.NEW_ACTIVITY_TRIAL_AVATAR)
public class TrialAvatarActivityHandler extends ActivityHandler {
@Getter @Setter private int selectedTrialAvatarIndex;
@Getter private int selectedTrialAvatarIndex;
private static final WatcherTriggerType triggerType = WatcherTriggerType.TRIGGER_FINISH_CHALLENGE;
private static final TrialAvatarDungeonSettleListener TRIAL_AVATAR_DUNGEON_SETTLE_LISTENER = new TrialAvatarDungeonSettleListener();
@Override
public void onInitPlayerActivityData(@NotNull PlayerActivityData playerActivityData) {
TrialAvatarPlayerData trialAvatarPlayerData = TrialAvatarPlayerData.create(getActivityConfigItem().getScheduleId());
playerActivityData.setDetail(trialAvatarPlayerData);
public void onInitPlayerActivityData(@NonNull PlayerActivityData playerActivityData) {
playerActivityData.setDetail(TrialAvatarPlayerData.create(getActivityConfigItem().getScheduleId()));
}
@Override
public void onProtoBuild(PlayerActivityData playerActivityData, @NotNull ActivityInfo.Builder activityInfo) {
TrialAvatarPlayerData trialAvatarPlayerData = getTrialAvatarPlayerData(playerActivityData);
activityInfo.setTrialAvatarInfo(trialAvatarPlayerData.toProto());
public void onProtoBuild(PlayerActivityData playerActivityData, @NonNull ActivityInfo.Builder activityInfo) {
activityInfo.setTrialAvatarInfo(getTrialAvatarPlayerData(playerActivityData).toProto());
}
@Override
public void initWatchers(@NotNull Map<WatcherTriggerType, ConstructorAccess<?>> activityWatcherTypeMap) {
var watcherType = activityWatcherTypeMap.get(WatcherTriggerType.TRIGGER_FINISH_CHALLENGE);
ActivityWatcher watcher = watcherType == null ? new DefaultWatcher() : (ActivityWatcher) watcherType.newInstance();
public void initWatchers(@NonNull Map<WatcherTriggerType, ConstructorAccess<?>> activityWatcherTypeMap) {
val watcher = Optional.ofNullable(activityWatcherTypeMap.get(triggerType))
.map(ConstructorAccess::newInstance).filter(ActivityWatcher.class::isInstance)
.map(ActivityWatcher.class::cast).orElse(new DefaultWatcher());
watcher.setActivityHandler(this);
getWatchersMap().computeIfAbsent(WatcherTriggerType.TRIGGER_FINISH_CHALLENGE, k -> new ArrayList<>());
getWatchersMap().get(WatcherTriggerType.TRIGGER_FINISH_CHALLENGE).add(watcher);
getWatchersMap().computeIfAbsent(triggerType, k -> new ArrayList<>()).add(watcher);
}
public TrialAvatarPlayerData getTrialAvatarPlayerData(@NotNull PlayerActivityData playerActivityData) {
public TrialAvatarPlayerData getTrialAvatarPlayerData(@NonNull PlayerActivityData playerActivityData) {
if (playerActivityData.getDetail() == null || playerActivityData.getDetail().isBlank()) {
onInitPlayerActivityData(playerActivityData);
playerActivityData.save();
@ -60,49 +58,50 @@ public class TrialAvatarActivityHandler extends ActivityHandler {
return JsonUtils.decode(playerActivityData.getDetail(), TrialAvatarPlayerData.class);
}
private Optional<TrialAvatarActivityDataData> getActivityData(int trialAvatarIndexId) {
return Optional.ofNullable(GameData.getTrialAvatarActivityDataByAvatarIndex(trialAvatarIndexId));
}
public int getTrialActivityDungeonId(int trialAvatarIndexId) {
val data = GameData.getTrialAvatarActivityDataByAvatarIndex(trialAvatarIndexId);
return data != null ? data.getDungeonId() : -1;
return getActivityData(trialAvatarIndexId).map(TrialAvatarActivityDataData::getDungeonId).orElse(-1);
}
public List<String> getTriggerParamList() {
val data = GameData.getTrialAvatarActivityDataByAvatarIndex(getSelectedTrialAvatarIndex());
return data != null ? data.getTriggerConfig().getParamList() : Collections.emptyList();
return getActivityData(this.selectedTrialAvatarIndex).map(TrialAvatarActivityDataData::getTriggerConfig)
.map(ActivityWatcherData.WatcherTrigger::getParamList).orElse(List.of());
}
public boolean enterTrialDungeon(@NotNull Player player, int trialAvatarIndexId, int enterPointId) {
public boolean enterTrialDungeon(@NonNull Player player, int trialAvatarIndexId, int enterPointId) {
// TODO, not sure if this will cause problem in MP, since we are entering trial activity dungeon
player.sendPacket(new PacketScenePlayerLocationNotify(player.getScene())); // official does send this
if (!player.getServer().getDungeonSystem().enterDungeon(
player,
enterPointId,
getTrialActivityDungeonId(trialAvatarIndexId))) return false;
getTrialActivityDungeonId(trialAvatarIndexId),
TRIAL_AVATAR_DUNGEON_SETTLE_LISTENER)) return false;
setSelectedTrialAvatarIndex(trialAvatarIndexId);
this.selectedTrialAvatarIndex = trialAvatarIndexId;
return true;
}
public List<Integer> getBattleAvatarsList() {
val activityData = GameData.getTrialAvatarActivityDataByAvatarIndex(getSelectedTrialAvatarIndex());
if (activityData == null || activityData.getBattleAvatarsList().isBlank()) return List.of();
return Stream.of(activityData.getBattleAvatarsList().split(",")).map(Integer::parseInt).toList();
return getActivityData(this.selectedTrialAvatarIndex).map(TrialAvatarActivityDataData::getBattleAvatarsList)
.filter(avatarStr -> !avatarStr.isBlank()).map(avatarStr -> avatarStr.split(",")).stream()
.flatMap(Arrays::stream).map(Integer::parseInt).toList();
}
public boolean getReward(@NotNull Player player, int trialAvatarIndexId) {
public boolean getReward(@NonNull Player player, int trialAvatarIndexId) {
val playerActivityData = player.getActivityManager()
.getPlayerActivityDataByActivityType(ActivityType.NEW_ACTIVITY_TRIAL_AVATAR);
if(playerActivityData.isEmpty()){
return false;
}
if(playerActivityData.isEmpty()) return false;
TrialAvatarPlayerData trialAvatarPlayerData = getTrialAvatarPlayerData(playerActivityData.get());
TrialAvatarPlayerData.RewardInfoItem rewardInfo = trialAvatarPlayerData.getRewardInfo(trialAvatarIndexId);
val trialAvatarPlayerData = getTrialAvatarPlayerData(playerActivityData.get());
val rewardInfo = trialAvatarPlayerData.getRewardInfo(trialAvatarIndexId);
if (rewardInfo == null) return false;
RewardData rewardParam = GameData.getRewardDataMap().get(rewardInfo.getRewardId());
val rewardParam = GameData.getRewardDataMap().get(rewardInfo.getRewardId());
if (rewardParam == null) return false;
player.getInventory().addItemParamDatas(rewardParam.getRewardItemList(), ActionReason.TrialAvatarActivityFirstPassReward);
@ -113,14 +112,14 @@ public class TrialAvatarActivityHandler extends ActivityHandler {
}
public void setPassDungeon(PlayerActivityData playerActivityData) {
TrialAvatarPlayerData trialAvatarPlayerData = getTrialAvatarPlayerData(playerActivityData);
TrialAvatarPlayerData.RewardInfoItem rewardInfo = trialAvatarPlayerData.getRewardInfo(getSelectedTrialAvatarIndex());
val trialAvatarPlayerData = getTrialAvatarPlayerData(playerActivityData);
val rewardInfo = trialAvatarPlayerData.getRewardInfo(this.selectedTrialAvatarIndex);
if (rewardInfo == null) return;
rewardInfo.setPassedDungeon(true);
playerActivityData.setDetail(trialAvatarPlayerData);
playerActivityData.save();
Player player = Grasscutter.getGameServer().getPlayerByUid(playerActivityData.getUid());
val player = Grasscutter.getGameServer().getPlayerByUid(playerActivityData.getUid());
player.sendPacket(new PacketActivityInfoNotify(toProto(playerActivityData, player.getActivityManager().getConditionExecutor())));
}
}

View File

@ -1,19 +0,0 @@
package emu.grasscutter.game.dungeons;
import emu.grasscutter.game.dungeons.dungeon_results.BaseDungeonResult;
import emu.grasscutter.server.packet.send.PacketDungeonSettleNotify;
import lombok.val;
public class BasicDungeonSettleListener implements DungeonSettleListener {
@Override
public void onDungeonSettle(DungeonManager dungeonManager, BaseDungeonResult.DungeonEndReason endReason) {
val scene = dungeonManager.getScene();
val dungeonData = dungeonManager.getDungeonData();
val time = scene.getSceneTimeSeconds() - dungeonManager.getStartSceneTime() ;
// TODO time taken and chests handling
DungeonEndStats stats = new DungeonEndStats(scene.getKilledMonsterCount(), time, 0, endReason);
scene.broadcastPacket(new PacketDungeonSettleNotify(new BaseDungeonResult(dungeonData, stats)));
}
}

View File

@ -3,16 +3,6 @@ package emu.grasscutter.game.dungeons;
import emu.grasscutter.game.dungeons.dungeon_results.BaseDungeonResult;
import lombok.Getter;
public class DungeonEndStats {
@Getter private int killedMonsters;
@Getter private int timeTaken;
@Getter private int openChestCount;
@Getter private BaseDungeonResult.DungeonEndReason dungeonResult;
public DungeonEndStats(int killedMonsters, int timeTaken, int openChestCount, BaseDungeonResult.DungeonEndReason dungeonResult){
this.killedMonsters = killedMonsters;
this.timeTaken = timeTaken;
this.dungeonResult = dungeonResult;
this.openChestCount = openChestCount;
}
public record DungeonEndStats(@Getter int killedMonsters, @Getter int timeTaken, @Getter int openChestCount,
@Getter BaseDungeonResult.DungeonEndReason dungeonResult) {
}

View File

@ -2,8 +2,10 @@ package emu.grasscutter.game.dungeons;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.common.ItemParamData;
import emu.grasscutter.data.binout.ScenePointEntry;
import emu.grasscutter.data.common.PointData;
import emu.grasscutter.data.excels.DungeonData;
import emu.grasscutter.data.excels.DungeonElementChallengeData;
import emu.grasscutter.data.excels.DungeonPassConfigData;
import emu.grasscutter.game.activity.trialavatar.TrialAvatarActivityHandler;
import emu.grasscutter.game.dungeons.dungeon_results.BaseDungeonResult;
@ -17,8 +19,11 @@ import emu.grasscutter.game.quest.enums.LogicType;
import emu.grasscutter.game.quest.enums.QuestContent;
import emu.grasscutter.game.world.Scene;
import emu.grasscutter.net.proto.TrialAvatarGrantRecordOuterClass.TrialAvatarGrantRecord.GrantReason;
import emu.grasscutter.net.proto.WeeklyBossResinDiscountInfoOuterClass.WeeklyBossResinDiscountInfo;
import emu.grasscutter.scripts.constants.EventType;
import emu.grasscutter.scripts.data.ScriptArgs;
import emu.grasscutter.server.packet.send.PacketDungeonDataNotify;
import emu.grasscutter.server.packet.send.PacketDungeonReviseLevelNotify;
import emu.grasscutter.server.packet.send.PacketDungeonWayPointNotify;
import emu.grasscutter.server.packet.send.PacketGadgetAutoPickDropInfoNotify;
import emu.grasscutter.utils.Position;
@ -27,6 +32,7 @@ import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet;
import lombok.Getter;
import lombok.NonNull;
import lombok.Setter;
import lombok.val;
import javax.annotation.Nullable;
@ -47,124 +53,93 @@ public class DungeonManager {
@Getter private final DungeonPassConfigData passConfigData;
@Getter private final int[] finishedConditions;
private final IntSet rewardedPlayers = new IntOpenHashSet();
@Getter private final IntSet rewardedPlayers = new IntOpenHashSet();
private final Set<Integer> activeDungeonWayPoints = new HashSet<>();
private boolean ended = false;
private int newestWayPoint = 0;
@Getter private int startSceneTime = 0;
@Getter @Setter private int delayExitTaskId = -1;
public DungeonManager(@NonNull Scene scene, @NonNull DungeonData dungeonData) {
this.scene = scene;
this.dungeonData = dungeonData;
this.passConfigData = GameData.getDungeonPassConfigDataMap().get(dungeonData.getPassCond());
this.finishedConditions = new int[passConfigData.getConds().size()];
this.scene.setDungeonManager(this);
this.finishedConditions = new int[this.passConfigData.getConds().size()];
}
public void triggerEvent(DungeonPassConditionType conditionType, int... params) {
if (ended) {
return;
}
for (int i = 0; i < passConfigData.getConds().size(); i++) {
var cond = passConfigData.getConds().get(i);
if (conditionType == cond.getCondType()) {
if (getScene().getWorld().getServer().getDungeonSystem().triggerCondition(cond, params)) {
finishedConditions[i] = 1;
}
if (this.ended) return;
}
}
if (isFinishedSuccessfully()) {
finishDungeon();
}
this.passConfigData.getConds().stream().filter(cond -> cond.getCondType() == conditionType)
.filter(cond -> getScene().getWorld().getServer().getDungeonSystem().triggerCondition(cond, params))
.forEach(cond -> this.finishedConditions[this.passConfigData.getConds().indexOf(cond)] = 1);
if (isFinishedSuccessfully()) finishDungeon();
}
public boolean isFinishedSuccessfully() {
return LogicType.calculate(passConfigData.getLogicType(), finishedConditions);
return LogicType.calculate(this.passConfigData.getLogicType(), this.finishedConditions);
}
public int getLevelForMonster(int id) {
//TODO should use levelConfigMap? and how?
return dungeonData.getShowLevel();
return this.dungeonData.getShowLevel();
}
public boolean activateRespawnPoint(int pointId) {
val respawnPoint = GameData.getScenePointEntryById(scene.getId(), pointId);
val respawnPoint = GameData.getScenePointEntryById(this.scene.getId(), pointId);
if (respawnPoint == null) {
Grasscutter.getLogger().warn("trying to activate unknown respawn point {}", pointId);
return false;
}
scene.broadcastPacket(new PacketDungeonWayPointNotify(activeDungeonWayPoints.add(pointId), activeDungeonWayPoints));
newestWayPoint = pointId;
this.scene.broadcastPacket(new PacketDungeonWayPointNotify(this.activeDungeonWayPoints.add(pointId), this.activeDungeonWayPoints));
this.newestWayPoint = pointId;
Grasscutter.getLogger().debug("[unimplemented respawn] activated respawn point {}", pointId);
return true;
}
@Nullable
public Position getRespawnLocation() {
if (newestWayPoint == 0) { // validity is checked before setting it, so if != 0 its always valid
return null;
}
val pointData = GameData.getScenePointEntryById(scene.getId(), newestWayPoint).getPointData();
return pointData.getTranPos() != null ? pointData.getTranPos() : pointData.getPos();
// validity is checked before setting it, so if != 0 its always valid
return Optional.ofNullable(GameData.getScenePointEntryById(this.scene.getId(), this.newestWayPoint))
.map(ScenePointEntry::getPointData).map(PointData::getTranPos).orElse(null);
}
public Position getRespawnRotation() {
if (newestWayPoint == 0) { // validity is checked before setting it, so if != 0 its always valid
return null;
}
val pointData = GameData.getScenePointEntryById(scene.getId(), newestWayPoint).getPointData();
return pointData.getRot() != null ? pointData.getRot() : null;
// validity is checked before setting it, so if != 0 its always valid
return Optional.ofNullable(GameData.getScenePointEntryById(this.scene.getId(), this.newestWayPoint))
.map(ScenePointEntry::getPointData).map(PointData::getRot).orElse(null);
}
public boolean getStatueDrops(Player player, boolean useCondensed, int groupId) {
if (!isFinishedSuccessfully() || dungeonData.getRewardPreviewData() == null || dungeonData.getRewardPreviewData().getPreviewItems().length == 0) {
return false;
}
// Already rewarded
if (rewardedPlayers.contains(player.getUid())) {
return false;
}
if (!handleCost(player, useCondensed)) {
return false;
}
if (!isFinishedSuccessfully() || Optional.ofNullable(this.dungeonData.getRewardPreviewData())
.filter(previewData -> previewData.getPreviewItems().length == 0).isPresent()
// Already rewarded
|| this.rewardedPlayers.contains(player.getUid()) || !handleCost(player, useCondensed)) return false;
// Get and roll rewards.
List<GameItem> rewards = new ArrayList<>(this.rollRewards(useCondensed));
val rewards = rollRewards(useCondensed);
// Add rewards to player and send notification.
player.getInventory().addItems(rewards, ActionReason.DungeonStatueDrop);
player.sendPacket(new PacketGadgetAutoPickDropInfoNotify(rewards));
rewardedPlayers.add(player.getUid());
scene.getScriptManager().callEvent(new ScriptArgs(groupId, EventType.EVENT_DUNGEON_REWARD_GET));
this.rewardedPlayers.add(player.getUid());
this.scene.getScriptManager().callEvent(new ScriptArgs(groupId, EventType.EVENT_DUNGEON_REWARD_GET));
player.getDungeonEntryManager().updateDungeonEntryInfo(this.dungeonData);
return true;
}
public boolean handleCost(Player player, boolean useCondensed) {
int resinCost = dungeonData.getStatueCostCount() != 0 ? dungeonData.getStatueCostCount() : 20;
if (resinCost == 0) {
return true;
}
final int resinCost = this.dungeonData.getStatueCostCount() != 0 ? this.dungeonData.getStatueCostCount() : 20;
if (useCondensed) {
// Check if condensed resin is usable here.
// For this, we use the following logic for now:
// The normal resin cost of the dungeon has to be 20.
if (resinCost != 20) {
return false;
}
// Spend the condensed resin and only proceed if the transaction succeeds.
return player.getResinManager().useCondensedResin(1);
} else if (dungeonData.getStatueCostID() == 106) {
return resinCost == 20 && player.getResinManager().useCondensedResin(1);
} else if (this.dungeonData.getStatueCostID() == 106) {
// Spend the resin and only proceed if the transaction succeeds.
return player.getResinManager().useResin(resinCost);
}
@ -172,14 +147,14 @@ public class DungeonManager {
}
private List<GameItem> rollRewards(boolean useCondensed) {
List<GameItem> rewards = new ArrayList<>();
int dungeonId = this.dungeonData.getId();
val rewards = new ArrayList<GameItem>();
final int dungeonId = this.dungeonData.getId();
// If we have specific drop data for this dungeon, we use it.
if (GameData.getDungeonDropDataMap().containsKey(dungeonId)) {
List<DungeonDropEntry> dropEntries = GameData.getDungeonDropDataMap().get(dungeonId);
val dropEntries = GameData.getDungeonDropDataMap().get(dungeonId);
// Roll for each drop group.
for (var entry : dropEntries) {
for (val entry : dropEntries) {
// Determine the number of drops we get for this entry.
int start = entry.getCounts().get(0);
int end = entry.getCounts().get(entry.getCounts().size() - 1);
@ -191,7 +166,7 @@ public class DungeonManager {
amount += Utils.drawRandomListElement(candidateAmounts, entry.getProbabilities());
}
// Double rewards in multiplay mode, if specified.
// Double rewards in multi play mode, if specified.
if (entry.isMpDouble() && this.getScene().getPlayerCount() > 1) {
amount *= 2;
}
@ -205,8 +180,6 @@ public class DungeonManager {
rewards.add(new GameItem(entry.getItems().get(0), amount));
} else {
for (int i = 0; i < amount; i++) {
// int itemIndex = ThreadLocalRandom.current().nextInt(0, entry.getItems().size());
// int itemId = entry.getItems().get(itemIndex);
int itemId = Utils.drawRandomListElement(entry.getItems(), entry.getItemProbabilities());
rewards.add(new GameItem(itemId, 1));
}
@ -216,37 +189,36 @@ public class DungeonManager {
// Otherwise, we fall back to the preview data.
else {
Grasscutter.getLogger().info("No drop data found or dungeon {}, falling back to preview data ...", dungeonId);
for (ItemParamData param : dungeonData.getRewardPreviewData().getPreviewItems()) {
rewards.add(new GameItem(param.getId(), Math.max(param.getCount(), 1)));
}
Arrays.stream(this.dungeonData.getRewardPreviewData().getPreviewItems())
.map(param -> new GameItem(param.getId(), Math.max(param.getCount(), 1)))
.forEach(rewards::add);
}
return rewards;
}
public void applyTrialTeam(Player player) {
if (getDungeonData() == null) return;
private void applyTrialTeam(Player player) {
if (this.dungeonData == null) return;
switch (getDungeonData().getType()) {
// case DUNGEON_PLOT is handled by quest execs
switch (this.dungeonData.getType()) {
// case DUNGEON_PLOT is handled by quest execs
case DUNGEON_ACTIVITY -> {
switch (getDungeonData().getPlayType()) {
case DUNGEON_PLAY_TYPE_TRIAL_AVATAR -> {
switch (this.dungeonData.getPlayType()) {
case DUNGEON_PLAY_TYPE_TRIAL_AVATAR ->
player.getActivityManager().getActivityHandlerAs(
ActivityType.NEW_ACTIVITY_TRIAL_AVATAR, TrialAvatarActivityHandler.class)
.ifPresent(handler -> player.addTrialAvatarsForDungeon(
handler.getBattleAvatarsList(), GrantReason.GRANT_REASON_BY_TRIAL_AVATAR_ACTIVITY));
}
ActivityType.NEW_ACTIVITY_TRIAL_AVATAR, TrialAvatarActivityHandler.class)
.map(TrialAvatarActivityHandler::getBattleAvatarsList)
.ifPresent(battleAvatars -> player.addTrialAvatarsForDungeon(
battleAvatars, GrantReason.GRANT_REASON_BY_TRIAL_AVATAR_ACTIVITY));
case DUNGEON_PLAY_TYPE_MIST_TRIAL -> {} // TODO
}
}
case DUNGEON_ELEMENT_CHALLENGE -> {
case DUNGEON_ELEMENT_CHALLENGE ->
Optional.ofNullable(GameData.getDungeonElementChallengeDataMap().get(getDungeonData().getId()))
.ifPresent(elementDungeonData -> {
player.addTrialAvatarsForDungeon(elementDungeonData.getTrialAvatarId(),
GrantReason.GRANT_REASON_BY_DUNGEON_ELEMENT_CHALLENGE);
});
}
.map(DungeonElementChallengeData::getTrialAvatarId)
.ifPresent(trialAvatarId -> player.addTrialAvatarsForDungeon(
trialAvatarId, GrantReason.GRANT_REASON_BY_DUNGEON_ELEMENT_CHALLENGE));
}
if (player.getTeamManager().isUseTrialTeam()){
player.getTeamManager().updateTeamEntities(false);
@ -254,9 +226,9 @@ public class DungeonManager {
}
public void startDungeon() {
this.startSceneTime = scene.getSceneTimeSeconds();
scene.getPlayers().forEach(p -> {
p.getQuestManager().queueEvent(QuestContent.QUEST_CONTENT_ENTER_DUNGEON, dungeonData.getId());
this.startSceneTime = this.scene.getSceneTimeSeconds();
this.scene.getPlayers().forEach(p -> {
p.getQuestManager().queueEvent(QuestContent.QUEST_CONTENT_ENTER_DUNGEON, this.dungeonData.getId());
applyTrialTeam(p);
});
}
@ -267,18 +239,18 @@ public class DungeonManager {
}
public void notifyEndDungeon(boolean successfully) {
scene.getPlayers().forEach(p -> {
this.scene.getPlayers().forEach(p -> {
// Quest trigger
p.getQuestManager().queueEvent(successfully ?
QuestContent.QUEST_CONTENT_FINISH_DUNGEON : QuestContent.QUEST_CONTENT_FAIL_DUNGEON,
dungeonData.getId());
this.dungeonData.getId());
// Battle pass trigger
if (dungeonData.getType().isCountsToBattlepass() && successfully) {
if (this.dungeonData.getType().isCountsToBattlepass() && successfully) {
p.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_FINISH_DUNGEON);
}
});
scene.getScriptManager().callEvent(new ScriptArgs(0, EventType.EVENT_DUNGEON_SETTLE, successfully ? 1 : 0));
this.scene.getScriptManager().callEvent(new ScriptArgs(0, EventType.EVENT_DUNGEON_SETTLE, successfully ? 1 : 0));
}
public void quitDungeon() {
@ -292,12 +264,17 @@ public class DungeonManager {
}
public void endDungeon(BaseDungeonResult.DungeonEndReason endReason) {
if (scene.getDungeonSettleListeners() != null) {
scene.getDungeonSettleListeners().forEach(o -> o.onDungeonSettle(this, endReason));
}
ended = true;
Optional.ofNullable(this.scene.getDungeonSettleListeners()).stream()
.flatMap(List::stream)
.forEach(o -> o.onDungeonSettle(this, endReason));
this.ended = true;
}
public void sendDungeonInfoPacket() {
this.scene.broadcastPacket(new PacketDungeonReviseLevelNotify(this.dungeonData));
// TODO, this probably has something to do with level config map
this.scene.broadcastPacket(new PacketDungeonDataNotify(this.dungeonData));
}
public void restartDungeon() {
this.scene.setKilledMonsterCount(0);
this.rewardedPlayers.clear();
@ -310,4 +287,13 @@ public class DungeonManager {
this.scene.setDungeonManager(null);
this.scene.setKilledMonsterCount(0);
}
/**
* Get weekly boss chest information for qualified player
* */
public Map<Integer, WeeklyBossResinDiscountInfo> getWeeklyBossUidInfo() {
return this.scene.getPlayers().stream()
.filter(p -> p.getDungeonEntryManager().getWeeklyBossDiscountInfo(this.dungeonData) != null)
.collect(Collectors.toMap(Player::getUid, p -> p.getDungeonEntryManager().getWeeklyBossDiscountInfo(this.dungeonData)));
}
}

View File

@ -3,29 +3,28 @@ package emu.grasscutter.game.dungeons;
import emu.grasscutter.GameConstants;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.binout.ScenePointEntry;
import emu.grasscutter.data.excels.DungeonData;
import emu.grasscutter.data.common.PointData;
import emu.grasscutter.data.excels.DungeonPassConfigData;
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
import emu.grasscutter.game.dungeons.dungeon_entry.DungeonEntries;
import emu.grasscutter.game.dungeons.handlers.DungeonBaseHandler;
import emu.grasscutter.game.dungeons.pass_condition.BaseCondition;
import emu.grasscutter.game.dungeons.settle_listeners.BasicDungeonSettleListener;
import emu.grasscutter.game.dungeons.settle_listeners.DungeonSettleListener;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.SceneType;
import emu.grasscutter.game.world.Scene;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.server.game.BaseGameSystem;
import emu.grasscutter.server.game.GameServer;
import emu.grasscutter.server.packet.send.PacketDungeonEntryInfoRsp;
import emu.grasscutter.server.packet.send.PacketPlayerEnterDungeonRsp;
import emu.grasscutter.utils.Position;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import lombok.val;
import org.reflections.Reflections;
import java.util.List;
import java.util.Optional;
public class DungeonSystem extends BaseGameSystem {
private static final BasicDungeonSettleListener basicDungeonSettleObserver = new BasicDungeonSettleListener();
private static final BasicDungeonSettleListener BASIC_DUNGEON_SETTLE_LISTENER = new BasicDungeonSettleListener();
private final Int2ObjectMap<DungeonBaseHandler> passCondHandlers;
public DungeonSystem(GameServer server) {
@ -35,128 +34,120 @@ public class DungeonSystem extends BaseGameSystem {
}
public void registerHandlers() {
this.registerHandlers(this.passCondHandlers, "emu.grasscutter.game.dungeons.pass_condition", DungeonBaseHandler.class);
registerHandlers(this.passCondHandlers, BaseCondition.class.getPackageName(), DungeonBaseHandler.class);
}
public <T> void registerHandlers(Int2ObjectMap<T> map, String packageName, Class<T> clazz) {
Reflections reflections = new Reflections(packageName);
var handlerClasses = reflections.getSubTypesOf(clazz);
for (var obj : handlerClasses) {
this.registerPacketHandler(map, obj);
}
new Reflections(packageName).getSubTypesOf(clazz).forEach(obj -> registerPacketHandler(map, obj));
}
public <T> void registerPacketHandler(Int2ObjectMap<T> map, Class<? extends T> handlerClass) {
try {
DungeonValue opcode = handlerClass.getAnnotation(DungeonValue.class);
if (opcode == null || opcode.value() == null) {
return;
}
map.put(opcode.value().ordinal(), handlerClass.getDeclaredConstructor().newInstance());
} catch (Exception e) {
e.printStackTrace();
}
}
public void getEntryInfo(Player player, int pointId) {
ScenePointEntry entry = GameData.getScenePointEntryById(player.getScene().getId(), pointId);
if (entry == null) {
// Error
player.sendPacket(new PacketDungeonEntryInfoRsp());
return;
}
player.sendPacket(new PacketDungeonEntryInfoRsp(player, entry.getPointData()));
Optional.ofNullable(handlerClass.getAnnotation(DungeonValue.class))
.map(DungeonValue::value)
.ifPresent(value -> {
try {
map.put(value.ordinal(), handlerClass.getDeclaredConstructor().newInstance());
} catch (Exception e) {
Grasscutter.getLogger().error("Cannot load handler for {}", value, e);
}
});
}
public boolean triggerCondition(DungeonPassConfigData.DungeonPassCondition condition, int... params) {
var handler = passCondHandlers.get(condition.getCondType().ordinal());
val handler = this.passCondHandlers.get(condition.getCondType().ordinal());
if (handler == null) {
Grasscutter.getLogger().debug("Could not trigger condition {} at {}", condition.getCondType(), params);
return false;
}
return handler.execute(condition, params);
}
public boolean enterDungeon(Player player, int pointId, int dungeonId) {
DungeonData data = GameData.getDungeonDataMap().get(dungeonId);
if (data == null) {
return false;
}
Grasscutter.getLogger().info("{}({}) is trying to enter dungeon {}" ,player.getNickname(),player.getUid(),dungeonId);
int sceneId = data.getSceneId();
var scene = player.getScene();
scene.setPrevScene(sceneId);
if (player.getWorld().transferPlayerToScene(player, sceneId, data)) {
scene = player.getScene();
var dungeonManager = new DungeonManager(scene, data);
scene.addDungeonSettleObserver(basicDungeonSettleObserver);
}
scene.setPrevScenePoint(pointId);
return true;
return enterDungeon(player, pointId, dungeonId, BASIC_DUNGEON_SETTLE_LISTENER);
}
/**
* used in tower dungeons handoff
*/
public boolean handoffDungeon(Player player, int dungeonId, List<DungeonSettleListener> dungeonSettleListeners) {
DungeonData data = GameData.getDungeonDataMap().get(dungeonId);
* TODO record also player's position for dungeon that does not have entries and exits,
* like trial avatar activity and mist trial activity
* */
public boolean enterDungeon(Player player, int pointId, int dungeonId, DungeonSettleListener dungeonSettleListeners) {
val data = GameData.getDungeonDataMap().get(dungeonId);
if (data == null) {
Grasscutter.getLogger().error("No resource found for this dungeon: {}", dungeonId);
return false;
}
Grasscutter.getLogger().info("{}({}) is trying to enter tower dungeon {}" ,player.getNickname(),player.getUid(),dungeonId);
Grasscutter.getLogger().info("{}({}) is trying to enter {}({})", player.getNickname(), player.getUid(), data.getType(), dungeonId);
player.getScene().setPrevScene(player.getSceneId());
if (player.getWorld().transferPlayerToScene(player, data.getSceneId(), data)) {
dungeonSettleListeners.forEach(player.getScene()::addDungeonSettleObserver);
player.getScene().setDungeonManager(new DungeonManager(player.getScene(), data));
player.getScene().addDungeonSettleObserver(dungeonSettleListeners);
}
player.getScene().setPrevScenePoint(Optional.ofNullable(GameData.getDungeonEntriesMap().get(dungeonId))
.map(DungeonEntries::getEntryPoint).map(PointData::getId).orElse(pointId));
return true;
}
public void exitDungeon(Player player) {
Scene scene = player.getScene();
// TODO check, modify it to work on multiplayer
public void restartDungeon(Player player) {
val scene = player.getScene();
if (scene == null || scene.getDungeonManager() == null) return;
if (scene==null || scene.getSceneType() != SceneType.SCENE_DUNGEON) {
return;
}
scene.getScriptManager().onDestroy();
scene.getWorld().deregisterScene(scene);
enterDungeon(player, 0, scene.getDungeonManager().getDungeonData().getId());
}
// Get previous scene
int prevScene = scene.getPrevScene() > 0 ? scene.getPrevScene() : 3;
/**
* Remove player from dungeon
* */
public void exitDungeon(Player player, boolean isQuitImmediately) {
val scene = player.getScene();
if (scene == null || scene.getSceneType() != SceneType.SCENE_DUNGEON) return;
// Get previous position
val dungeonManager = scene.getDungeonManager();
DungeonData dungeonData = dungeonManager != null ? dungeonManager.getDungeonData() : null;
Position prevPos = new Position(GameConstants.START_POSITION);
val dungeonData = Optional.ofNullable(dungeonManager).map(DungeonManager::getDungeonData).orElse(null);
// Get dungeon exit point
val exitPoint = Optional.ofNullable(dungeonData).map(data -> GameData.getDungeonEntriesMap().get(data.getId()))
.map(DungeonEntries::getExitPoint);
val newPos = exitPoint.map(PointData::getTranPos).orElse(new Position(GameConstants.START_POSITION));
val newRot = exitPoint.map(PointData::getTranRot).orElse(null);
int pointId = exitPoint.map(PointData::getId).orElse(0);
int delayExitTime = -1;
if (dungeonData != null) {
ScenePointEntry entry = GameData.getScenePointEntryById(prevScene, scene.getPrevScenePoint());
if (entry != null) {
prevPos.set(entry.getPointData().getTranPos());
}
if(!dungeonManager.isFinishedSuccessfully()){
if(dungeonData != null && !dungeonManager.isFinishedSuccessfully() && dungeonManager.getDelayExitTaskId() < 0) {
// fail challenges if exist
val challenge = Optional.ofNullable(scene.getChallenge()).filter(WorldChallenge::inProgress);
challenge.ifPresent(WorldChallenge::fail);
if (challenge.isPresent()) {
delayExitTime = dungeonData.getFailSettleCountdownTime();
dungeonManager.failDungeon();
} else {
delayExitTime = dungeonData.getQuitSettleCountdownTime();
dungeonManager.quitDungeon();
}
}
// clean temp team if it has
player.getTeamManager().cleanTemporaryTeam();
player.getTowerManager().clearEntry();
// remove any existing transfer task before scheduling new one
Optional.ofNullable(dungeonManager).filter(m -> m.getDelayExitTaskId() > 0).ifPresent(m -> {
Grasscutter.getGameServer().getScheduler().cancelTask(m.getDelayExitTaskId());
m.setDelayExitTaskId(-1);
});
Runnable transferTask = () -> {
scene.setPrevScene(scene.getId());
player.getWorld().transferPlayerToScene(player, exitPoint.map(PointData::getSceneId).orElse(3), newPos, newRot);
player.getScene().setPrevScenePoint(pointId);
};
// Transfer player back to world
player.getWorld().transferPlayerToScene(player, prevScene, prevPos);
}
public void updateDailyDungeons() {
GameData.getScenePointEntries().forEach((id, entry) -> entry.getPointData().updateDailyDungeon());
if (isQuitImmediately) {
transferTask.run();
} else {
int delayTaskId = Grasscutter.getGameServer().getScheduler().scheduleDelayedTask(transferTask, delayExitTime);
Optional.ofNullable(dungeonManager).ifPresent(m -> m.setDelayExitTaskId(delayTaskId));
}
}
}

View File

@ -0,0 +1,33 @@
package emu.grasscutter.game.dungeons.dungeon_entry;
import emu.grasscutter.data.common.PointData;
import lombok.Builder;
import lombok.Getter;
import lombok.ToString;
import java.util.Map;
/**
* Records the entry and exit trans pos and rot for dungeon/domains
* */
@Getter
@ToString
@Builder(builderMethodName = "of", builderClassName = "Builder", setterPrefix = "set")
public class DungeonEntries {
private final int dungeonId;
private final PointData entryPoint;
private final PointData exitPoint;
public static DungeonEntries create(int dungeonId, PointData pointData, Map<Integer, PointData> exitPointMap) {
return DungeonEntries.of()
.setDungeonId(dungeonId)
.setEntryPoint(pointData)
.setExitPoint(exitPointMap.getOrDefault((pointData.getSceneId() << 16) + pointData.getId(), pointData))
.build();
}
public int getEntryKey() {
return (this.entryPoint.getSceneId() << 16) + this.entryPoint.getId();
}
}

View File

@ -0,0 +1,84 @@
package emu.grasscutter.game.dungeons.dungeon_entry;
import dev.morphia.annotations.Entity;
import emu.grasscutter.GameConstants;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.excels.DungeonData;
import emu.grasscutter.data.excels.DungeonRosterData;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import lombok.Getter;
import lombok.val;
import java.time.*;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
/**
* Holds dungeon entry information, including weekly boss discount information
* */
@Entity
@Getter
public class DungeonEntryItem {
private final Set<Integer> passedDungeons = new TreeSet<>();
/**
* entry: [dungeon serial id, boss record]
* */
private final Map<Integer, WeeklyBossRecord> bossRecordMap = new Int2ObjectOpenHashMap<>();
public void addDungeon(int dungeonId) {
this.passedDungeons.add(dungeonId);
}
public void updateWeeklyBossInfo(int dungeonSerialId) {
val selectedDungeon = this.bossRecordMap.get(dungeonSerialId);
if (selectedDungeon == null || !selectedDungeon.canTakeReward()) return;
selectedDungeon.update();
this.bossRecordMap.values().forEach(WeeklyBossRecord::sync);
}
public void checkForNewBoss() {
if (!this.bossRecordMap.keySet().containsAll(GameData.getDungeonSerialDataMap().keySet())) {
GameData.getDungeonDataMap().values().stream().filter(data -> data.getSerialId() > 0)
.map(data -> GameData.getDungeonSerialDataMap().get(data.getSerialId())).filter(Objects::nonNull)
.forEach(serialData -> this.bossRecordMap.putIfAbsent(
serialData.getId(), WeeklyBossRecord.create(serialData)));
}
}
public void buildRosterDungeon() {
GameData.getDungeonRosterDataMap().values().stream().filter(DungeonRosterData::nowIsAfterOpenTime)
.forEach(data -> data.getRosterPool().stream().map(DungeonRosterData.RosterPool::getDungeonList)
.flatMapToInt(Arrays::stream).mapToObj(GameData.getDungeonDataMap()::get).map(DungeonData::getSerialId)
.map(this.bossRecordMap::get).filter(Objects::nonNull).filter(record -> record.getRosterCycleRecord() == null)
.forEach(record -> record.buildRosterRecord(data.getId())));
}
public void resetWeeklyBoss(){
this.bossRecordMap.values().stream().filter(record -> shouldReset(
ZonedDateTime.now(GameConstants.ZONE_ID), toZonedDateTime(record.getLastCycledTime())))
.forEach(WeeklyBossRecord::reset);
}
private static boolean shouldReset(ZonedDateTime currentDateTime, ZonedDateTime lastRefreshDateTime){
val lastMonday = currentDateTime.with(TemporalAdjusters.previous(GameConstants.WEEKLY_BOSS_RESIN_DISCOUNT_REFRESH_DAY))
.with(LocalTime.of(GameConstants.REFRESH_HOUR, 0, 0));
return lastRefreshDateTime == null || Duration.between(lastRefreshDateTime, lastMonday)
.toDays() >= GameConstants.WEEKLY_BOSS_RESIN_DISCOUNT_REFRESH_DAY_INTERVAL;
}
/**
* Convert string to ZoneDateTime,
* string should be in this format: yyyy-MM-dd HH:mm:ss
* */
private static ZonedDateTime toZonedDateTime(String timeStr) {
return ZonedDateTime.parse(timeStr, GameConstants.TIME_FORMATTER.withZone(GameConstants.ZONE_ID));
}
static String getLastRefreshTimeStr(){
return ZonedDateTime.now(GameConstants.ZONE_ID)
.with(TemporalAdjusters.previous(GameConstants.WEEKLY_BOSS_RESIN_DISCOUNT_REFRESH_DAY))
.with(LocalTime.of(GameConstants.REFRESH_HOUR, 0, 0)).format(GameConstants.TIME_FORMATTER);
}
}

View File

@ -0,0 +1,125 @@
package emu.grasscutter.game.dungeons.dungeon_entry;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.binout.ScenePointEntry;
import emu.grasscutter.data.common.PointData;
import emu.grasscutter.data.common.quest.SubQuestData;
import emu.grasscutter.data.excels.DungeonData;
import emu.grasscutter.data.excels.DungeonRosterData;
import emu.grasscutter.data.excels.DungeonSerialData;
import emu.grasscutter.game.player.BasePlayerManager;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.quest.GameMainQuest;
import emu.grasscutter.game.quest.GameQuest;
import emu.grasscutter.game.quest.enums.QuestContent;
import emu.grasscutter.game.quest.enums.QuestState;
import emu.grasscutter.net.proto.DungeonEntryInfoOuterClass.DungeonEntryInfo;
import emu.grasscutter.net.proto.WeeklyBossResinDiscountInfoOuterClass.WeeklyBossResinDiscountInfo;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import lombok.NonNull;
import lombok.val;
import java.util.*;
import java.util.stream.Stream;
/**
* TODO sync resin usage with statue drops
* */
public class DungeonEntryManager extends BasePlayerManager {
/**
* entry: [(sceneId << 16) + pointId, dungeonId]
* */
private final Map<Integer, List<Integer>> plotDungeonEntries = new Int2ObjectOpenHashMap<>();
public DungeonEntryManager(@NonNull Player player) {
super(player);
}
private DungeonEntryItem getDungeonEntryItem() {
return this.player.getDungeonEntryItem();
}
private Map<Integer, WeeklyBossRecord> getBossRecordMap() {
return Optional.ofNullable(getDungeonEntryItem()).map(DungeonEntryItem::getBossRecordMap).orElse(Map.of());
}
public void onLogin() {
// check if player needs quest dungeon entry
this.player.getQuestManager().getMainQuests().values().stream()
.map(GameMainQuest::getChildQuests).map(Map::values).flatMap(Collection::stream)
.filter(quest -> quest.getState() == QuestState.QUEST_STATE_UNFINISHED)
.map(GameQuest::getQuestData).map(SubQuestData::getFinishCond).flatMap(List::stream)
.filter(cond -> cond.getType() == QuestContent.QUEST_CONTENT_ENTER_DUNGEON)
.map(cond -> GameData.getDungeonEntriesMap().get(cond.getParam()[0]))
.forEach(entries -> this.plotDungeonEntries.computeIfAbsent(
entries.getEntryKey(), f -> new ArrayList<>()).add(entries.getDungeonId()));
// builds weekly boss information if its missing
getDungeonEntryItem().checkForNewBoss();
getDungeonEntryItem().buildRosterDungeon();
getDungeonEntryItem().resetWeeklyBoss();
}
public DungeonEntryInfo toProto(DungeonData data) {
val proto = DungeonEntryInfo.newBuilder();
Optional.ofNullable(GameData.getDungeonSerialDataMap().get(data.getSerialId()))
.map(DungeonSerialData::getId).map(getBossRecordMap()::get)
.ifPresent(bossRecord -> proto.setWeeklyBossResinDiscountInfo(bossRecord.toProto())
.setBossChestNum(bossRecord.getTakeNum())
.setMaxBossChestNum(bossRecord.getMaxTakeNumLimit())
.setNextRefreshTime(bossRecord.getNextRefreshTime()));
return proto.setDungeonId(data.getId())
.setIsPassed(getDungeonEntryItem().getPassedDungeons().contains(data.getId()))
.build();
}
/**
* Record weekly boss information after completing dungeon
* */
public void updateDungeonEntryInfo(DungeonData dungeonData){
getDungeonEntryItem().addDungeon(dungeonData.getId());
getDungeonEntryItem().updateWeeklyBossInfo(dungeonData.getSerialId());
}
public List<Integer> getPlotDungeonById(int sceneId, int pointId){
return this.plotDungeonEntries.get((sceneId << 16) + pointId);
}
public WeeklyBossResinDiscountInfo getWeeklyBossDiscountInfo(DungeonData dungeonData) {
return Optional.ofNullable(getBossRecordMap().get(dungeonData.getSerialId()))
.filter(WeeklyBossRecord::canTakeReward).map(WeeklyBossRecord::toProto)
.orElse(null);
}
/**
* Get dungeon information for specific entries
* */
public List<DungeonData> getDungeonEntries(int sceneId, int pointId) {
// basic dungeon entries including daily domains and weekly bosses, not including Azhdaha here
val basicDungeons = Optional.ofNullable(GameData.getScenePointEntryById(sceneId, pointId))
.map(ScenePointEntry::getPointData).map(PointData::getDungeonIds).stream().parallel()
.flatMapToInt(Arrays::stream).mapToObj(GameData.getDungeonDataMap()::get)
.filter(Objects::nonNull).toList();
// quest entries
val plotDungeons = Optional.ofNullable(getPlotDungeonById(sceneId, pointId)).stream().parallel()
.flatMap(List::stream).map(dungeonId -> GameData.getDungeonDataMap().get(dungeonId.intValue()))
.filter(Objects::nonNull).toList();
// dungeon that will rotate regularly, like Azhdaha weekly boss
val rosterDungeons = Optional.ofNullable(GameData.getScenePointEntryById(sceneId, pointId))
.map(ScenePointEntry::getPointData).map(PointData::getDungeonRosterList).stream().parallel()
.flatMapToInt(Arrays::stream).mapToObj(GameData.getDungeonRosterDataMap()::get).filter(Objects::nonNull)
.map(rosterData -> getBossRecordMap().values().stream().parallel().map(WeeklyBossRecord::getRosterCycleRecord)
.filter(Objects::nonNull).map(RosterCycleRecord::getSelectedPool)
.map(rosterData.getRosterPool()::get).filter(Objects::nonNull).toList())
.flatMap(List::stream).map(DungeonRosterData.RosterPool::getDungeonList).flatMapToInt(Arrays::stream)
.mapToObj(GameData.getDungeonDataMap()::get).toList();
return Stream.of(basicDungeons, plotDungeons, rosterDungeons).flatMap(Collection::stream)
.filter(data -> this.player.getLevel() >= data.getLimitLevel())
.filter(data -> data.getId() != 69) // TODO, this dungeon is causing problem, find out why
.toList();
}
}

View File

@ -0,0 +1,31 @@
package emu.grasscutter.game.dungeons.dungeon_entry;
import dev.morphia.annotations.Entity;
import emu.grasscutter.data.GameData;
import lombok.Builder;
import lombok.Getter;
import java.util.Optional;
@Entity
@Builder(builderMethodName = "of")
@Getter
public class RosterCycleRecord {
private int rosterId;
private int selectedPool;
private String lastCycledTime;
public static RosterCycleRecord create(int rosterId) {
return RosterCycleRecord.of()
.rosterId(rosterId)
.lastCycledTime(DungeonEntryItem.getLastRefreshTimeStr())
.selectedPool(0)
.build();
}
public void reset() {
Optional.ofNullable(GameData.getDungeonRosterDataMap().get(this.rosterId))
.ifPresent(data -> this.selectedPool = data.getNextPool(this.selectedPool));
this.lastCycledTime = DungeonEntryItem.getLastRefreshTimeStr();
}
}

View File

@ -0,0 +1,88 @@
package emu.grasscutter.game.dungeons.dungeon_entry;
import dev.morphia.annotations.Entity;
import emu.grasscutter.GameConstants;
import emu.grasscutter.data.excels.DungeonSerialData;
import emu.grasscutter.net.proto.WeeklyBossResinDiscountInfoOuterClass;
import lombok.Builder;
import lombok.Getter;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalTime;
import java.time.ZonedDateTime;
import java.time.temporal.TemporalAdjusters;
import java.util.Optional;
@Entity
@Builder(builderMethodName = "of")
@Getter
public class WeeklyBossRecord {
private int serialId;
private int discountNum;
private int discountNumLimit;
private int resinCost;
private int originalResinCost;
private String lastCycledTime;
private int takeNum;
private int maxTakeNumLimit;
private RosterCycleRecord rosterCycleRecord;
public static WeeklyBossRecord create(DungeonSerialData serialData) {
return WeeklyBossRecord.of()
.serialId(serialData.getId())
.discountNum(0)
.discountNumLimit(GameConstants.WEEKLY_BOSS_RESIN_DISCOUNT_COUNT)
.originalResinCost(serialData.getTakeCost())
.resinCost((int) (serialData.getTakeCost() * GameConstants.WEEKLY_BOSS_RESIN_DISCOUNT_VALUE))
.takeNum(0)
.maxTakeNumLimit(serialData.getMaxTakeNum())
.lastCycledTime(DungeonEntryItem.getLastRefreshTimeStr())
.build();
}
public void buildRosterRecord(int rosterId) {
this.rosterCycleRecord = RosterCycleRecord.create(rosterId);
}
public int getNextRefreshTime(){
if (this.lastCycledTime == null || this.lastCycledTime.isBlank()) return 0;
// Get the current date and time in the specified time zone
ZonedDateTime now = ZonedDateTime.now(GameConstants.ZONE_ID);
ZonedDateTime nextMonday = now.with(TemporalAdjusters.next(GameConstants.WEEKLY_BOSS_RESIN_DISCOUNT_REFRESH_DAY))
.with(LocalTime.of(GameConstants.REFRESH_HOUR, 0, 0));
return (int) Instant.now().plus(Duration.between(now, nextMonday)).getEpochSecond();
}
void update() {
if (canTakeReward()) this.takeNum += 1;
}
void sync() {
if(this.discountNum < this.discountNumLimit) this.discountNum += 1;
}
public void reset() {
this.discountNum = 0;
this.takeNum = 0;
this.lastCycledTime = DungeonEntryItem.getLastRefreshTimeStr();
Optional.ofNullable(this.rosterCycleRecord).ifPresent(RosterCycleRecord::reset);
}
private int getResinCost() {
return this.discountNum < this.discountNumLimit ? this.resinCost : this.originalResinCost;
}
public boolean canTakeReward() {
return this.takeNum < this.maxTakeNumLimit;
}
public WeeklyBossResinDiscountInfoOuterClass.WeeklyBossResinDiscountInfo toProto() {
return WeeklyBossResinDiscountInfoOuterClass.WeeklyBossResinDiscountInfo.newBuilder()
.setDiscountNum(this.discountNum)
.setDiscountNumLimit(this.discountNumLimit)
.setResinCost(getResinCost())
.setOriginalResinCost(this.originalResinCost)
.build();
}
}

View File

@ -1,64 +1,120 @@
package emu.grasscutter.game.dungeons.dungeon_results;
import emu.grasscutter.data.excels.DungeonData;
import emu.grasscutter.game.avatar.Avatar;
import emu.grasscutter.game.dungeons.DungeonEndStats;
import emu.grasscutter.game.entity.EntityAvatar;
import emu.grasscutter.game.inventory.GameItem;
import emu.grasscutter.game.inventory.ItemType;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.net.proto.DungeonSettleNotifyOuterClass.DungeonSettleNotify;
import emu.grasscutter.net.proto.ParamListOuterClass;
import emu.grasscutter.net.proto.ParamListOuterClass.ParamList;
import emu.grasscutter.net.proto.StrengthenPointDataOuterClass.StrengthenPointData;
import emu.grasscutter.utils.Utils;
import lombok.Builder;
import lombok.Getter;
import lombok.val;
import java.util.*;
import java.util.stream.Collectors;
import static emu.grasscutter.game.dungeons.enums.DungeonInvolveType.INVOLVE_SINGLE_MULTIPLE;
/**
* Shows dungeon results
* */
public class BaseDungeonResult {
@Getter DungeonData dungeonData;
@Getter
DungeonEndStats dungeonStats;
private final DungeonData dungeonData;
@Getter private final DungeonEndStats dungeonStats;
private final Player player;
public BaseDungeonResult(DungeonData dungeonData, DungeonEndStats dungeonStats){
@Builder(builderMethodName = "BaseBuilder", setterPrefix = "set")
protected BaseDungeonResult(DungeonData dungeonData, DungeonEndStats dungeonStats, Player player){
this.dungeonData = dungeonData;
this.dungeonStats = dungeonStats;
this.player = player;
}
protected void onProto(DungeonSettleNotify.Builder builder){ }
/**
* Could be different depending on dungeon types
* */
protected void onProto(DungeonSettleNotify.Builder builder){
}
/**
* Show player's area to improve, not completed
* */
private void getStrengthenPointData(DungeonSettleNotify.Builder builder) {
if (this.dungeonStats.dungeonResult().isSuccess() ||
this.dungeonData.getInvolveType() != INVOLVE_SINGLE_MULTIPLE) return;
val playerActiveTeam = this.player.getTeamManager().getActiveTeam();
builder.putAllStrengthenPointDataMap(Arrays.stream(StrengthenPointType.values()).collect(
Collectors.toMap(StrengthenPointType::getValue, type -> switch (type){
case LEVEL -> StrengthenPointData.newBuilder()
.setBasePoint(playerActiveTeam.size() * 90)
.setCurPoint(playerActiveTeam.stream()
.map(EntityAvatar::getAvatar).map(Avatar::getLevel)
.reduce(0, Integer::sum))
.build();
case WEAPON -> StrengthenPointData.newBuilder()
.setBasePoint(playerActiveTeam.size() * 90)
.setCurPoint(playerActiveTeam.stream()
.map(EntityAvatar::getAvatar).map(Avatar::getEquips)
.map(Map::values).flatMap(Collection::stream)
.filter(item -> item.getItemType() == ItemType.ITEM_WEAPON)
.map(GameItem::getLevel)
.reduce(0, Integer::sum))
.build();
case TALENT -> StrengthenPointData.newBuilder()
.setBasePoint(100000).setCurPoint(50000).build();
case ARTIFACT -> StrengthenPointData.newBuilder()
.setBasePoint(playerActiveTeam.size() * 20)
.setCurPoint(playerActiveTeam.stream()
.map(EntityAvatar::getAvatar).map(Avatar::getEquips)
.map(Map::values).flatMap(Collection::stream)
.filter(item -> item.getItemType() == ItemType.ITEM_RELIQUARY)
.map(GameItem::getLevel)
.reduce(0, Integer::sum))
.build();
})));
}
public final DungeonSettleNotify.Builder getProto(){
var success = dungeonStats.getDungeonResult().isSuccess();
var builder = DungeonSettleNotify.newBuilder()
.setDungeonId(dungeonData.getId())
val success = this.dungeonStats.getDungeonResult().isSuccess();
val builder = DungeonSettleNotify.newBuilder()
.setUseTime(this.dungeonStats.getTimeTaken())
.setDungeonId(this.dungeonData.getId())
.setIsSuccess(success)
.setCloseTime(getCloseTime())
.setResult(success ? 1 : 0);
.setResult(success ? 1 : 3)
.setCreatePlayerUid(this.player.getUid());
// TODO check
if(dungeonData.getSettleShows()!=null) {
for (int i = 0; i < dungeonData.getSettleShows().size(); i++) {
var settle = dungeonData.getSettleShows().get(i);
builder.putSettleShow(i + 1,switch (settle) {
case SETTLE_SHOW_TIME_COST -> ParamListOuterClass.ParamList.newBuilder()
.addParamList(settle.getId())
.addParamList(dungeonStats.getTimeTaken())
.build();
case SETTLE_SHOW_KILL_MONSTER_COUNT -> ParamListOuterClass.ParamList.newBuilder()
.addParamList(settle.getId())
.addParamList(dungeonStats.getKilledMonsters())
.build();
default -> ParamListOuterClass.ParamList.newBuilder()
.addParamList(settle.getId())
.build();
});
}
}
val tempSettleMap = new HashMap<Integer, ParamList.Builder>();
Optional.ofNullable(this.dungeonData.getSettleShows()).stream()
.flatMap(List::stream)
.forEach(showType -> tempSettleMap.computeIfAbsent(showType.getId(), f -> ParamList.newBuilder())
.addParamList(switch (showType) {
case SETTLE_SHOW_TIME_COST -> this.dungeonStats.getTimeTaken();
case SETTLE_SHOW_KILL_MONSTER_COUNT -> this.dungeonStats.getKilledMonsters();
case SETTLE_SHOW_OPEN_CHEST_COUNT -> this.dungeonStats.getOpenChestCount();
default -> 0;
}));
//TODO handle settle show
builder.putAllSettleShow(tempSettleMap.entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().build())));
getStrengthenPointData(builder);
onProto(builder);
return builder;
}
public int getCloseTime(){
return Utils.getCurrentSeconds() + switch (dungeonStats.getDungeonResult()){
case COMPLETED -> dungeonData.getSettleCountdownTime();
case FAILED -> dungeonData.getFailSettleCountdownTime();
case QUIT -> dungeonData.getQuitSettleCountdownTime();
private int getCloseTime(){
return Utils.getCurrentSeconds() + switch (this.dungeonStats.getDungeonResult()){
case COMPLETED -> this.dungeonData.getSettleCountdownTime();
case FAILED -> this.dungeonData.getFailSettleCountdownTime();
case QUIT -> this.dungeonData.getQuitSettleCountdownTime();
};
}
@ -71,4 +127,17 @@ public class BaseDungeonResult {
return this == COMPLETED;
}
}
@Getter
private enum StrengthenPointType {
LEVEL(1),
WEAPON(2),
ARTIFACT(3),
TALENT(4);
private final int value;
StrengthenPointType (int value){
this.value = value;
}
}
}

View File

@ -4,7 +4,6 @@ import emu.grasscutter.data.excels.DungeonData;
import emu.grasscutter.game.dungeons.DungeonEndStats;
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
import emu.grasscutter.game.tower.TowerManager;
import emu.grasscutter.net.proto.DungeonSettleExhibitionInfoOuterClass;
import emu.grasscutter.net.proto.DungeonSettleNotifyOuterClass;
import emu.grasscutter.net.proto.ItemParamOuterClass;
import emu.grasscutter.net.proto.TowerLevelEndNotifyOuterClass.TowerLevelEndNotify.ContinueStateType;
@ -16,11 +15,11 @@ public class TowerResult extends BaseDungeonResult{
boolean hasNextLevel;
int nextFloorId;
public TowerResult(DungeonData dungeonData, DungeonEndStats dungeonStats, TowerManager towerManager, WorldChallenge challenge) {
super(dungeonData, dungeonStats);
super(dungeonData, dungeonStats, challenge.getScene().getWorld().getHost());
this.challenge = challenge;
this.canJump = towerManager.hasNextFloor();
this.hasNextLevel = towerManager.hasNextLevel();
this.nextFloorId = hasNextLevel ? 0 : towerManager.getNextFloorId();
this.nextFloorId = this.hasNextLevel ? 0 : towerManager.getNextFloorId();
}
@Override

View File

@ -2,22 +2,25 @@ package emu.grasscutter.game.dungeons.dungeon_results;
import emu.grasscutter.data.excels.DungeonData;
import emu.grasscutter.game.dungeons.DungeonEndStats;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.net.proto.DungeonSettleNotifyOuterClass;
import emu.grasscutter.net.proto.TrialAvatarFirstPassDungeonNotifyOuterClass.TrialAvatarFirstPassDungeonNotify;
import lombok.Builder;
public class TrialAvatarDungeonResult extends BaseDungeonResult {
int trialCharacterIndexId;
public TrialAvatarDungeonResult(DungeonData dungeonData, DungeonEndStats dungeonStats, int trialCharacterIndexId) {
super(dungeonData, dungeonStats);
@Builder(builderMethodName = "TrialAvatarBuilder", setterPrefix = "set")
private TrialAvatarDungeonResult(DungeonData dungeonData, DungeonEndStats dungeonStats, Player player, int trialCharacterIndexId) {
super(dungeonData, dungeonStats, player);
this.trialCharacterIndexId = trialCharacterIndexId;
}
@Override
protected void onProto(DungeonSettleNotifyOuterClass.DungeonSettleNotify.Builder builder) {
if (dungeonStats.getDungeonResult() == DungeonEndReason.COMPLETED) { //TODO check if its the first pass(?)
if (getDungeonStats().dungeonResult() == DungeonEndReason.COMPLETED) { // TODO check if it's the first pass(?)
builder.setTrialAvatarFirstPassDungeonNotify(TrialAvatarFirstPassDungeonNotify.newBuilder()
.setTrialAvatarIndexId(trialCharacterIndexId));
.setTrialAvatarIndexId(this.trialCharacterIndexId));
}
}
}

View File

@ -0,0 +1,23 @@
package emu.grasscutter.game.dungeons.settle_listeners;
import emu.grasscutter.game.dungeons.DungeonEndStats;
import emu.grasscutter.game.dungeons.DungeonManager;
import emu.grasscutter.game.dungeons.dungeon_results.BaseDungeonResult;
import emu.grasscutter.server.packet.send.PacketDungeonSettleNotify;
import lombok.val;
public class BasicDungeonSettleListener implements DungeonSettleListener {
@Override
public void onDungeonSettle(DungeonManager dungeonManager, BaseDungeonResult.DungeonEndReason endReason) {
val scene = dungeonManager.getScene();
val time = scene.getSceneTimeSeconds() - dungeonManager.getStartSceneTime();
scene.broadcastPacket(new PacketDungeonSettleNotify(BaseDungeonResult.BaseBuilder()
.setDungeonData(dungeonManager.getDungeonData())
.setDungeonStats(new DungeonEndStats(
scene.getKilledMonsterCount(), time, scene.getKillChestCount(), endReason))
.setPlayer(scene.getWorld().getHost()) // creator of the world, should be the host then
.build()));
}
}

View File

@ -1,5 +1,6 @@
package emu.grasscutter.game.dungeons;
package emu.grasscutter.game.dungeons.settle_listeners;
import emu.grasscutter.game.dungeons.DungeonManager;
import emu.grasscutter.game.dungeons.dungeon_results.BaseDungeonResult;
public interface DungeonSettleListener {

View File

@ -1,7 +1,9 @@
package emu.grasscutter.game.dungeons;
package emu.grasscutter.game.dungeons.settle_listeners;
import emu.grasscutter.game.dungeons.DungeonEndStats;
import emu.grasscutter.game.dungeons.DungeonManager;
import emu.grasscutter.game.dungeons.dungeon_results.BaseDungeonResult.DungeonEndReason;
import emu.grasscutter.game.world.SceneGroupInstance;
import emu.grasscutter.game.dungeons.settle_listeners.DungeonSettleListener;
import emu.grasscutter.game.dungeons.dungeon_results.TowerResult;
import emu.grasscutter.server.packet.send.PacketDungeonSettleNotify;
import emu.grasscutter.server.packet.send.PacketTowerFloorRecordChangeNotify;

View File

@ -0,0 +1,31 @@
package emu.grasscutter.game.dungeons.settle_listeners;
import emu.grasscutter.game.activity.trialavatar.TrialAvatarActivityHandler;
import emu.grasscutter.game.dungeons.DungeonEndStats;
import emu.grasscutter.game.dungeons.DungeonManager;
import emu.grasscutter.game.dungeons.dungeon_results.BaseDungeonResult;
import emu.grasscutter.game.dungeons.dungeon_results.TrialAvatarDungeonResult;
import emu.grasscutter.server.packet.send.PacketDungeonSettleNotify;
import lombok.val;
import java.util.Optional;
import static emu.grasscutter.game.props.ActivityType.NEW_ACTIVITY_TRIAL_AVATAR;
public class TrialAvatarDungeonSettleListener implements DungeonSettleListener{
@Override
public void onDungeonSettle(DungeonManager dungeonManager, BaseDungeonResult.DungeonEndReason endReason) {
val scene = dungeonManager.getScene();
val hostPlayer = scene.getWorld().getHost();
val time = scene.getSceneTimeSeconds() - dungeonManager.getStartSceneTime();
hostPlayer.sendPacket(new PacketDungeonSettleNotify(TrialAvatarDungeonResult.TrialAvatarBuilder()
.setDungeonData(dungeonManager.getDungeonData())
.setDungeonStats(new DungeonEndStats(scene.getKilledMonsterCount(), time, 0, endReason))
.setPlayer(hostPlayer)
.setTrialCharacterIndexId(hostPlayer.getActivityManager()
.getActivityHandlerAs(NEW_ACTIVITY_TRIAL_AVATAR, TrialAvatarActivityHandler.class)
.map(TrialAvatarActivityHandler::getSelectedTrialAvatarIndex).orElse(0))
.build()));
}
}

View File

@ -1,6 +1,7 @@
package emu.grasscutter.game.entity.gadget;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.game.dungeons.DungeonManager;
import emu.grasscutter.game.entity.EntityGadget;
import emu.grasscutter.game.entity.gadget.chest.BossChestInteractHandler;
import emu.grasscutter.game.player.Player;
@ -15,6 +16,8 @@ import emu.grasscutter.scripts.constants.ScriptGadgetState;
import emu.grasscutter.server.packet.send.PacketGadgetInteractRsp;
import lombok.val;
import java.util.ArrayList;
import java.util.Map;
import java.util.Optional;
public class GadgetChest extends GadgetContent {
@ -50,17 +53,34 @@ public class GadgetChest extends GadgetContent {
}
}
/**
* Builds proto information for gadgets, note that
* it will override the gadget's properties even if the builder is empty
* */
public void onBuildProto(SceneGadgetInfo.Builder gadgetInfo) {
val playersUid = getGadget().getScene().getPlayers().stream().map(Player::getUid).toList();
Optional.ofNullable(getGadget().getMetaGadget())
.map(g -> g.boss_chest)
.ifPresent(bossChest -> gadgetInfo.setBossChest(BossChestInfo.newBuilder()
.setMonsterConfigId(bossChest.monster_config_id)
.setResin(bossChest.resin)
.addAllQualifyUidList(playersUid)
.addAllRemainUidList(playersUid)
.build()));
.ifPresent(bossChest -> {
val chestProto = BossChestInfo.newBuilder()
.setMonsterConfigId(bossChest.monster_config_id)
.setResin(bossChest.resin);
// removing instead of creating new list directly below is because
// it also has to consider normal cases
val qualifiedUids = new ArrayList<>(playersUid);
// don't allow player to take again if he has taken weekly boss already
Optional.ofNullable(getGadget().getScene().getDungeonManager())
.map(DungeonManager::getWeeklyBossUidInfo).map(chestProto::putAllUidDiscountMap)
.map(BossChestInfo.Builder::getUidDiscountMapMap).map(Map::keySet)
.ifPresent(qualifiedUids::retainAll);
gadgetInfo.setBossChest(chestProto
.addAllQualifyUidList(playersUid)
.addAllRemainUidList(qualifiedUids)
.build());
});
Optional.ofNullable(getGadget().getScene().getWorld().getHost().getBlossomManager()
.getChestInfo(getGadget().getConfigId(), playersUid))

View File

@ -1,32 +1,41 @@
package emu.grasscutter.game.entity.gadget;
import emu.grasscutter.game.dungeons.challenge.DungeonChallenge;
import emu.grasscutter.game.entity.EntityGadget;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.net.proto.GadgetInteractReqOuterClass.GadgetInteractReq;
import emu.grasscutter.net.proto.InterOpTypeOuterClass.InterOpType;
import emu.grasscutter.net.proto.InteractTypeOuterClass.InteractType;
import emu.grasscutter.net.proto.ResinCostTypeOuterClass;
import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo;
import emu.grasscutter.net.proto.StatueGadgetInfoOuterClass.StatueGadgetInfo;
import emu.grasscutter.server.packet.send.PacketGadgetInteractRsp;
import lombok.val;
import static emu.grasscutter.net.proto.ResinCostTypeOuterClass.ResinCostType.RESIN_COST_TYPE_CONDENSE;
import java.util.Optional;
public class GadgetRewardStatue extends GadgetContent {
public GadgetRewardStatue(EntityGadget gadget) {
super(gadget);
}
public GadgetRewardStatue(EntityGadget gadget) {
super(gadget);
}
public boolean onInteract(Player player, GadgetInteractReq req) {
if (player.getScene().getDungeonManager() != null || player.getScene().getChallenge() instanceof DungeonChallenge dungeonChallenge) {
var useCondensed = req.getResinCostType() == ResinCostTypeOuterClass.ResinCostType.RESIN_COST_TYPE_CONDENSE;
player.getScene().getDungeonManager().getStatueDrops(player, useCondensed, getGadget().getGroupId());
}
public boolean onInteract(Player player, GadgetInteractReq req) {
if (req.getOpType() == InterOpType.INTER_OP_TYPE_FINISH) {
val useCondense = req.getResinCostType() == RESIN_COST_TYPE_CONDENSE;
Optional.ofNullable(player.getScene().getDungeonManager()).ifPresent(m ->
m.getStatueDrops(player, useCondense, getGadget().getGroupId()));
}
player.sendPacket(new PacketGadgetInteractRsp(getGadget(), InteractType.INTERACT_TYPE_OPEN_STATUE));
player.sendPacket(new PacketGadgetInteractRsp(getGadget(), InteractType.INTERACT_TYPE_OPEN_STATUE, req.getOpType()));
return false;
}
return false;
}
public void onBuildProto(SceneGadgetInfo.Builder gadgetInfo) {
val proto = StatueGadgetInfo.newBuilder();
Optional.ofNullable(getGadget().getScene().getDungeonManager())
.ifPresent(m -> proto.addAllOpenedStatueUidList(m.getRewardedPlayers()));
public void onBuildProto(SceneGadgetInfo.Builder gadgetInfo) {
}
gadgetInfo.setStatueGadget(proto.build());
}
}

View File

@ -76,7 +76,7 @@ public class MapMarksManager extends BasePlayerManager {
}
Position pos = mapMark.getPosition();
player.getWorld().transferPlayerToScene(player, mapMark.getSceneId(), TeleportType.MAP, new Position(pos.getX(), y, pos.getZ()));
player.getWorld().transferPlayerToScene(player, mapMark.getSceneId(), TeleportType.MAP, new Position(pos.getX(), y, pos.getZ()), null);
player.getScene().broadcastPacket(new PacketSceneEntityAppearNotify(player));
}
}

View File

@ -16,6 +16,8 @@ import emu.grasscutter.game.avatar.Avatar;
import emu.grasscutter.game.avatar.AvatarStorage;
import emu.grasscutter.game.avatar.TrialAvatar;
import emu.grasscutter.game.battlepass.BattlePassManager;
import emu.grasscutter.game.dungeons.dungeon_entry.DungeonEntryItem;
import emu.grasscutter.game.dungeons.dungeon_entry.DungeonEntryManager;
import emu.grasscutter.game.entity.EntityAvatar;
import emu.grasscutter.game.entity.GameEntity;
import emu.grasscutter.game.expedition.ExpeditionInfo;
@ -172,6 +174,7 @@ public class Player {
@Getter private transient PlayerBuffManager buffManager;
@Getter private transient PlayerProgressManager progressManager;
@Getter private transient BlossomManager blossomManager;
@Getter private transient DungeonEntryManager dungeonEntryManager;
@Getter @Setter private transient Position lastCheckedPosition = null;
@ -211,6 +214,7 @@ public class Player {
@Getter private long playerGameTime = 540;
@Getter private PlayerProgress playerProgress;
@Getter private final DungeonEntryItem dungeonEntryItem;
@Getter private Set<Integer> activeQuestTimers;
@Deprecated
@ -257,6 +261,7 @@ public class Player {
this.unlockedScenePoints = new HashMap<>();
this.chatEmojiIdList = new ArrayList<>();
this.playerProgress = new PlayerProgress();
this.dungeonEntryItem = new DungeonEntryItem();
this.activeQuestTimers = new HashSet<>();
this.attackResults = new LinkedBlockingQueue<>();
@ -284,6 +289,7 @@ public class Player {
this.cookingManager = new CookingManager(this);
this.cookingCompoundManager=new CookingCompoundManager(this);
this.blossomManager = new BlossomManager(this);
this.dungeonEntryManager = new DungeonEntryManager(this);
}
// On player creation
@ -320,6 +326,7 @@ public class Player {
this.cookingManager = new CookingManager(this);
this.cookingCompoundManager=new CookingCompoundManager(this);
this.blossomManager = new BlossomManager(this);
this.dungeonEntryManager = new DungeonEntryManager(this);
}
public void updatePlayerGameTime(long gameTime){
@ -1365,6 +1372,9 @@ public class Player {
// Rewind active quests, and put the player to a rewind position it finds (if any) of an active quest
getQuestManager().onLogin();
// find out any new dungeon plot entries
getDungeonEntryManager().onLogin();
// Packets
session.send(new PacketPlayerDataNotify(this)); // Player data
session.send(new PacketStoreWeightLimitNotify());
@ -1428,8 +1438,8 @@ public class Player {
// stop stamina calculation
getStaminaManager().stopSustainedStaminaHandler();
// force to leave the dungeon (inside has a "if")
this.getServer().getDungeonSystem().exitDungeon(this);
// force to leave the dungeon (inside has an "if")
this.getServer().getDungeonSystem().exitDungeon(this, true);
// Leave world
if (this.getWorld() != null) {

View File

@ -2,8 +2,8 @@ package emu.grasscutter.game.tower;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.excels.TowerLevelData;
import emu.grasscutter.game.dungeons.DungeonSettleListener;
import emu.grasscutter.game.dungeons.TowerDungeonSettleListener;
import emu.grasscutter.game.dungeons.settle_listeners.DungeonSettleListener;
import emu.grasscutter.game.dungeons.settle_listeners.TowerDungeonSettleListener;
import emu.grasscutter.game.player.BasePlayerManager;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.server.packet.send.*;
@ -36,7 +36,7 @@ public class TowerManager extends BasePlayerManager {
public int getCurrentLevel() {
return getTowerData().currentLevel + 1;
}
private static final List<DungeonSettleListener> towerDungeonSettleListener = List.of(new TowerDungeonSettleListener());
private static final DungeonSettleListener towerDungeonSettleListener = new TowerDungeonSettleListener();
public Map<Integer, TowerLevelRecord> getRecordMap() {
Map<Integer, TowerLevelRecord> recordMap = getTowerData().recordMap;
@ -74,8 +74,7 @@ public class TowerManager extends BasePlayerManager {
notifyCurLevelRecordChange();
// use team user choose
player.getTeamManager().useTemporaryTeam(0);
player.getServer().getDungeonSystem().handoffDungeon(player, dungeonId,
towerDungeonSettleListener);
player.getServer().getDungeonSystem().enterDungeon(player, dungeonId, enterPointId, towerDungeonSettleListener);
// make sure user can exit dungeon correctly
player.getScene().setPrevScene(getTowerData().entryScene);

View File

@ -8,7 +8,7 @@ import emu.grasscutter.data.binout.routes.Route;
import emu.grasscutter.data.excels.*;
import emu.grasscutter.game.avatar.Avatar;
import emu.grasscutter.game.dungeons.DungeonManager;
import emu.grasscutter.game.dungeons.DungeonSettleListener;
import emu.grasscutter.game.dungeons.settle_listeners.DungeonSettleListener;
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
import emu.grasscutter.game.dungeons.enums.DungeonPassConditionType;
import emu.grasscutter.game.entity.*;
@ -72,6 +72,7 @@ public class Scene {
@Getter @Setter private int prevScene; // id of the previous scene
@Getter @Setter private int prevScenePoint;
@Getter @Setter private int killedMonsterCount;
@Getter @Setter private int killChestCount;
private Set<SceneNpcBornEntry> npcBornEntrySet = ConcurrentHashMap.newKeySet();
@Getter private boolean finishedLoading = false;
@Getter private int tickCount = 0;
@ -365,10 +366,7 @@ public class Scene {
avatarAttacker.getPlayer().getCodex().checkAnimal(target, CodexAnimalData.CountType.CODEX_COUNT_TYPE_KILL);
}
// Reward drop, don't really want to give reward if attacker is null
if (target instanceof EntityMonster && getSceneType() != SceneType.SCENE_DUNGEON) {
this.world.getServer().getDropSystem().callDrop((EntityMonster) target);
}
}
// Packet
@ -379,7 +377,17 @@ public class Scene {
// Death event
target.onDeath(attackerId);
triggerDungeonEvent(DungeonPassConditionType.DUNGEON_COND_KILL_MONSTER_COUNT, ++this.killedMonsterCount);
// Reward drop
if (target instanceof EntityMonster monster) {
if (getSceneType() != SceneType.SCENE_DUNGEON && attacker != null) {
getWorld().getServer().getDropSystem().callDrop(monster);
}
triggerDungeonEvent(DungeonPassConditionType.DUNGEON_COND_KILL_MONSTER_COUNT, ++this.killedMonsterCount);
} else if (target instanceof EntityGadget gadget) {
Optional.ofNullable(gadget.getGadgetData())
.filter(data -> data.getType() == EntityType.Chest)
.ifPresent(data -> this.killChestCount++);
}
}
public void onTick() {
@ -446,10 +454,14 @@ public class Scene {
// todo should probably respawn the player at the last valid location
return this.world.transferPlayerToScene(player, TeleportProperties.builder()
.sceneId(getId())
.prevSceneId(getId())
.prevPos(player.getPosition())
.teleportTo(getRespawnLocation(player))
.teleportRot(getRespawnRotation(player))
.teleportType(PlayerTeleportEvent.TeleportType.INTERNAL)
.worldType(Optional.ofNullable(this.dungeonManager).map(data -> 13).orElse(14))
.enterType(EnterTypeOuterClass.EnterType.ENTER_TYPE_GOTO)
.dungeonId(Optional.ofNullable(this.dungeonManager).map(DungeonManager::getDungeonData).map(DungeonData::getId).orElse(0))
.enterReason(this.dungeonManager != null ? EnterReason.DungeonReviveOnWaypoint : EnterReason.Revival)
.build());
}

View File

@ -26,11 +26,7 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import lombok.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.*;
import java.util.stream.Collectors;
import static emu.grasscutter.server.event.player.PlayerTeleportEvent.TeleportType.SCRIPT;
@ -224,43 +220,46 @@ public class World implements Iterable<Player> {
this.getScenes().values().forEach(Scene::saveGroups);
}
public boolean transferPlayerToScene(Player player, int sceneId, Position pos) {
return this.transferPlayerToScene(player, sceneId, TeleportType.INTERNAL, null, pos);
public boolean transferPlayerToScene(Player player, int sceneId, Position pos, Position rot) {
return this.transferPlayerToScene(player, sceneId, TeleportType.INTERNAL, null, pos, rot);
}
public boolean transferPlayerToScene(Player player, int sceneId, TeleportType teleportType, Position pos) {
return this.transferPlayerToScene(player, sceneId, teleportType, null, pos);
public boolean transferPlayerToScene(Player player, int sceneId, TeleportType teleportType, Position pos, Position rot) {
return this.transferPlayerToScene(player, sceneId, teleportType, null, pos, rot);
}
public boolean transferPlayerToScene(Player player, int sceneId, DungeonData data) {
return this.transferPlayerToScene(player, sceneId, TeleportType.DUNGEON, data, null);
return this.transferPlayerToScene(player, sceneId, TeleportType.DUNGEON, data, null, null);
}
public boolean transferPlayerToScene(Player player, int sceneId, TeleportType teleportType, DungeonData dungeonData, Position teleportTo) {
public boolean transferPlayerToScene(Player player, int sceneId, TeleportType teleportType, DungeonData dungeonData, Position teleportTo, Position newRot) {
EnterReason enterReason = switch (teleportType) {
// shouldn't affect the teleportation, but its clearer when inspecting the packets
// TODO add more conditions for different reason.
case INTERNAL -> EnterReason.TransPoint;
case WAYPOINT -> EnterReason.TransPoint;
case MAP -> EnterReason.TransPoint;
case INTERNAL, WAYPOINT, MAP -> EnterReason.TransPoint;
case COMMAND -> EnterReason.Gm;
case SCRIPT -> EnterReason.Lua;
case CLIENT -> EnterReason.ClientTransmit;
case DUNGEON -> EnterReason.DungeonEnter;
default -> EnterReason.None;
};
return transferPlayerToScene(player, sceneId, teleportType, enterReason, dungeonData, teleportTo);
return transferPlayerToScene(player, sceneId, teleportType, enterReason, dungeonData, teleportTo, newRot);
}
public boolean transferPlayerToScene(Player player, int sceneId, TeleportType teleportType, EnterReason enterReason, DungeonData dungeonData, Position teleportTo) {
public boolean transferPlayerToScene(Player player, int sceneId, TeleportType teleportType, EnterReason enterReason, DungeonData dungeonData, Position teleportTo, Position newRot) {
// Get enter types
val teleportProps = TeleportProperties.builder()
.sceneId(sceneId)
.teleportType(teleportType)
.enterReason(enterReason)
.teleportTo(teleportTo)
.enterType(EnterType.ENTER_TYPE_JUMP);
.teleportRot(newRot)
.enterType(EnterType.ENTER_TYPE_JUMP)
.dungeonId(Optional.ofNullable(dungeonData).map(DungeonData::getId).orElse(0))
.prevPos(player.getPosition())
.prevSceneId(player.getSceneId())
.worldType(Optional.ofNullable(dungeonData).map(data -> 13).orElse(14)); // TODO find out more
val sceneData = GameData.getSceneDataMap().get(sceneId);
if (dungeonData != null) {
@ -312,21 +311,13 @@ public class World implements Iterable<Player> {
// }
SceneConfig config = newScene.getScriptManager().getConfig();
if (teleportProperties.getTeleportTo() == null && config != null) {
if (config.born_pos != null) {
teleportProperties.setTeleportTo(newScene.getScriptManager().getConfig().born_pos);
}
if (config.born_rot != null) {
teleportProperties.setTeleportRot(config.born_rot);
}
Optional.ofNullable(config.born_pos).ifPresent(teleportProperties::setTeleportTo);
Optional.ofNullable(config.born_rot).ifPresent(teleportProperties::setTeleportRot);
}
// Set player position and rotation
if(teleportProperties.getTeleportTo() != null) {
player.getPosition().set(teleportProperties.getTeleportTo());
}
if(teleportProperties.getTeleportRot()!=null) {
player.getRotation().set(teleportProperties.getTeleportRot());
}
Optional.ofNullable(teleportProperties.getTeleportTo()).ifPresent(player.getPosition()::set);
Optional.ofNullable(teleportProperties.getTeleportRot()).ifPresent(player.getRotation()::set);
if (oldScene != null && newScene != oldScene) {
newScene.setPrevScene(oldScene.getId());

View File

@ -16,4 +16,8 @@ public class TeleportProperties {
private Position teleportTo;
private Position teleportRot;
private EnterTypeOuterClass.EnterType enterType;
private int dungeonId;
private Position prevPos;
private int prevSceneId;
private int worldType;
}

View File

@ -39,7 +39,7 @@ public final class PlayerHook {
* @param sceneId The scene to send the player to.
*/
public void changeScenes(int sceneId) {
this.player.getWorld().transferPlayerToScene(this.player, sceneId, this.player.getPosition());
this.player.getWorld().transferPlayerToScene(this.player, sceneId, this.player.getPosition(), null);
}
/**

View File

@ -5,15 +5,16 @@ import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.DungeonEntryInfoReqOuterClass.DungeonEntryInfoReq;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketDungeonEntryInfoRsp;
import lombok.val;
@Opcodes(PacketOpcodes.DungeonEntryInfoReq)
public class HandlerDungeonEntryInfoReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
DungeonEntryInfoReq req = DungeonEntryInfoReq.parseFrom(payload);
val req = DungeonEntryInfoReq.parseFrom(payload);
session.getServer().getDungeonSystem().getEntryInfo(session.getPlayer(), req.getPointId());
session.getPlayer().sendPacket(new PacketDungeonEntryInfoRsp(session.getPlayer(), req.getSceneId(), req.getPointId()));
}
}

View File

@ -0,0 +1,16 @@
package emu.grasscutter.server.packet.recv;
import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketDungeonRestartRsp;
@Opcodes(PacketOpcodes.DungeonRestartReq)
public class HandlerDungeonRestartReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
session.getServer().getDungeonSystem().restartDungeon(session.getPlayer());
session.send(new PacketDungeonRestartRsp());
}
}

View File

@ -1,21 +1,20 @@
package emu.grasscutter.server.packet.recv;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.GetDailyDungeonEntryInfoReqOuterClass;
import emu.grasscutter.net.proto.GetDailyDungeonEntryInfoReqOuterClass.GetDailyDungeonEntryInfoReq;
import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketGetDailyDungeonEntryInfoRsp;
import lombok.val;
@Opcodes(PacketOpcodes.GetDailyDungeonEntryInfoReq)
public class HandlerGetDailyDungeonEntryInfoReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
var req=
GetDailyDungeonEntryInfoReqOuterClass.GetDailyDungeonEntryInfoReq.parseFrom(payload);
val req = GetDailyDungeonEntryInfoReq.parseFrom(payload);
session.send(new PacketGetDailyDungeonEntryInfoRsp(req.getSceneId()));
session.send(new PacketGetDailyDungeonEntryInfoRsp(session.getPlayer(), req.getSceneId()));
}
}

View File

@ -1,37 +1,33 @@
package emu.grasscutter.server.packet.recv;
import emu.grasscutter.game.world.Scene;
import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.HomeSceneJumpReqOuterClass;
import emu.grasscutter.net.proto.HomeSceneJumpReqOuterClass.HomeSceneJumpReq;
import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketHomeSceneJumpRsp;
import emu.grasscutter.utils.Position;
import lombok.val;
@Opcodes(PacketOpcodes.HomeSceneJumpReq)
public class HandlerHomeSceneJumpReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
var req = HomeSceneJumpReqOuterClass.HomeSceneJumpReq.parseFrom(payload);
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
val req = HomeSceneJumpReq.parseFrom(payload);
int realmId = 2000 + session.getPlayer().getCurrentRealmId();
int realmId = 2000 + session.getPlayer().getCurrentRealmId();
val home = session.getPlayer().getHome();
val homeScene = home.getHomeSceneItem(realmId);
home.save();
var home = session.getPlayer().getHome();
var homeScene = home.getHomeSceneItem(realmId);
home.save();
// the function should be able to get pos and rot from scriptManager config
session.getPlayer().getWorld().transferPlayerToScene(
session.getPlayer(),
req.getIsEnterRoomScene() ? homeScene.getRoomSceneId() : realmId,
null, null
);
Scene scene = session.getPlayer().getWorld().getSceneById(req.getIsEnterRoomScene() ? homeScene.getRoomSceneId() : realmId);
Position pos = scene.getScriptManager().getConfig().born_pos;
session.getPlayer().getWorld().transferPlayerToScene(
session.getPlayer(),
req.getIsEnterRoomScene() ? homeScene.getRoomSceneId() : realmId,
pos
);
session.send(new PacketHomeSceneJumpRsp(req.getIsEnterRoomScene()));
}
session.send(new PacketHomeSceneJumpRsp(req.getIsEnterRoomScene()));
}
}

View File

@ -8,7 +8,9 @@ import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.PersonalSceneJumpReqOuterClass.PersonalSceneJumpReq;
import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketPersonalSceneJumpRsp;
import emu.grasscutter.utils.Position;
import lombok.val;
import java.util.Optional;
@Opcodes(PacketOpcodes.PersonalSceneJumpReq)
@ -16,17 +18,19 @@ public class HandlerPersonalSceneJumpReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
PersonalSceneJumpReq req = PersonalSceneJumpReq.parseFrom(payload);
var player = session.getPlayer();
val req = PersonalSceneJumpReq.parseFrom(payload);
val player = session.getPlayer();
// get the scene point
ScenePointEntry scenePointEntry = GameData.getScenePointEntryById(player.getSceneId(), req.getPointId());
val pointData = Optional.ofNullable(GameData.getScenePointEntryById(player.getSceneId(), req.getPointId()))
.map(ScenePointEntry::getPointData).orElse(null);
if (scenePointEntry != null) {
Position pos = scenePointEntry.getPointData().getTranPos().clone(); // This might not need cloning
int sceneId = scenePointEntry.getPointData().getTranSceneId();
if (pointData != null) {
val pos = pointData.getTranPos();
val rot = pointData.getTranRot();
int sceneId = pointData.getTranSceneId();
player.getWorld().transferPlayerToScene(player, sceneId, pos);
player.getWorld().transferPlayerToScene(player, sceneId, pos, rot);
session.send(new PacketPersonalSceneJumpRsp(sceneId, pos));
}

View File

@ -4,15 +4,16 @@ import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.PlayerQuitDungeonReqOuterClass.PlayerQuitDungeonReq;
import emu.grasscutter.server.game.GameSession;
import lombok.val;
@Opcodes(PacketOpcodes.PlayerQuitDungeonReq)
public class HandlerPlayerQuitDungeonReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
session.getPlayer().getServer().getDungeonSystem().exitDungeon(session.getPlayer());
val req = PlayerQuitDungeonReq.parseFrom(payload);
session.getPlayer().getServer().getDungeonSystem().exitDungeon(session.getPlayer(), req.getIsQuitImmediately());
session.getPlayer().sendPacket(new BasePacket(PacketOpcodes.PlayerQuitDungeonRsp));
}
}

View File

@ -1,10 +1,12 @@
package emu.grasscutter.server.packet.recv;
import emu.grasscutter.data.GameData;
import emu.grasscutter.game.quest.GameMainQuest;
import emu.grasscutter.game.quest.GameQuest;
import emu.grasscutter.game.quest.TeleportData;
import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.server.event.player.PlayerTeleportEvent.TeleportType;
import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketQuestTransmitRsp;
import emu.grasscutter.utils.Position;
@ -12,21 +14,29 @@ import emu.grasscutter.net.proto.QuestTransmitReqOuterClass.QuestTransmitReq;
import java.util.List;
import java.util.ArrayList;
import java.util.Optional;
import lombok.val;
@Opcodes(PacketOpcodes.QuestTransmitReq)
public class HandlerQuestTransmitReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
val req = QuestTransmitReq.parseFrom(payload);
GameMainQuest mainQuest = session.getPlayer().getQuestManager().getMainQuestById(req.getQuestId() / 100);
List<Position> posAndRot = new ArrayList<>();
boolean result = false;
if(mainQuest.hasTeleportPostion(req.getQuestId(), posAndRot)){
int sceneId = GameData.getTeleportDataMap().get(req.getQuestId()).getTransmit_points().get(0).getScene_id();
result = session.getPlayer().getWorld().transferPlayerToScene(session.getPlayer(), sceneId, posAndRot.get(0));
}
session.send(new PacketQuestTransmitRsp(result, req));
}
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
val req = QuestTransmitReq.parseFrom(payload);
val player = session.getPlayer();
val posAndRot = new ArrayList<Position>();
final int sceneId = Optional.ofNullable(GameData.getTeleportDataMap().get(req.getQuestId()))
.map(TeleportData::getTransmit_points).stream().flatMap(List::stream).findFirst()
.map(TeleportData.TransmitPoint::getScene_id).orElse(3);
val result = Optional.ofNullable(player.getQuestManager().getQuestById(req.getQuestId()))
.map(GameQuest::getMainQuest).filter(mainQuest -> mainQuest.hasTeleportPostion(req.getQuestId(), posAndRot))
.filter(mainQuest -> posAndRot.size() > 1) // make sure there is pos and rot
.filter(mainQuest -> player.getWorld().transferPlayerToScene(
player, sceneId, TeleportType.CLIENT, posAndRot.get(0), posAndRot.get(1)))
.isPresent();
session.send(new PacketQuestTransmitRsp(result, req));
}
}

View File

@ -1,5 +1,6 @@
package emu.grasscutter.server.packet.recv;
import emu.grasscutter.game.dungeons.DungeonManager;
import emu.grasscutter.game.player.Player.SceneLoadState;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.Opcodes;
@ -8,6 +9,8 @@ import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.*;
import java.util.Optional;
@Opcodes(PacketOpcodes.SceneInitFinishReq)
public class HandlerSceneInitFinishReq extends PacketHandler {
@ -15,6 +18,9 @@ public class HandlerSceneInitFinishReq extends PacketHandler {
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
// Info packets
session.send(new PacketServerTimeNotify());
Optional.ofNullable(session.getPlayer().getScene().getDungeonManager())
.ifPresent(DungeonManager::sendDungeonInfoPacket);
session.send(new PacketWorldPlayerInfoNotify(session.getPlayer().getWorld()));
session.send(new PacketWorldDataNotify(session.getPlayer().getWorld()));
session.send(new PacketWorldOwnerBlossomBriefInfoNotify(session.getPlayer().getWorld()));

View File

@ -9,25 +9,24 @@ import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.server.event.player.PlayerTeleportEvent.TeleportType;
import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketSceneTransToPointRsp;
import lombok.val;
import java.util.Optional;
@Opcodes(PacketOpcodes.SceneTransToPointReq)
public class HandlerSceneTransToPointReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
SceneTransToPointReq req = SceneTransToPointReq.parseFrom(payload);
var player = session.getPlayer();
val req = SceneTransToPointReq.parseFrom(payload);
val player = session.getPlayer();
val result = Optional.ofNullable(GameData.getScenePointEntryById(req.getSceneId(), req.getPointId()))
.map(ScenePointEntry::getPointData)
.filter(pointData -> player.getWorld().transferPlayerToScene(
player, req.getSceneId(), TeleportType.WAYPOINT, pointData.getTranPos(), pointData.getTranRot()))
.isPresent();
ScenePointEntry scenePointEntry = GameData.getScenePointEntryById(req.getSceneId(), req.getPointId());
if (scenePointEntry != null) {
if (player.getWorld().transferPlayerToScene(player, req.getSceneId(), TeleportType.WAYPOINT, scenePointEntry.getPointData().getTranPos().clone())) {
session.send(new PacketSceneTransToPointRsp(player, req.getPointId(), req.getSceneId()));
return;
}
}
session.send(new PacketSceneTransToPointRsp());
session.send(new PacketSceneTransToPointRsp(result, req.getPointId(), req.getSceneId()));
}
}

View File

@ -1,62 +1,53 @@
package emu.grasscutter.server.packet.recv;
import emu.grasscutter.game.home.GameHome;
import emu.grasscutter.game.world.Scene;
import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.FriendEnterHomeOptionOuterClass;
import emu.grasscutter.net.proto.RetcodeOuterClass;
import emu.grasscutter.net.proto.TryEnterHomeReqOuterClass;
import emu.grasscutter.net.proto.TryEnterHomeReqOuterClass.TryEnterHomeReq;
import emu.grasscutter.server.event.player.PlayerTeleportEvent.TeleportType;
import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketTryEnterHomeRsp;
import emu.grasscutter.utils.Position;
import lombok.val;
import static emu.grasscutter.net.proto.FriendEnterHomeOptionOuterClass.FriendEnterHomeOption.*;
import static emu.grasscutter.net.proto.RetcodeOuterClass.Retcode.*;
@Opcodes(PacketOpcodes.TryEnterHomeReq)
public class HandlerTryEnterHomeReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
var req = TryEnterHomeReqOuterClass.TryEnterHomeReq.parseFrom(payload);
var targetPlayer = session.getServer().getPlayerByUid(req.getTargetUid(), true);
val req = TryEnterHomeReq.parseFrom(payload);
val targetPlayer = session.getServer().getPlayerByUid(req.getTargetUid(), true);
if (req.getTargetUid() != session.getPlayer().getUid()) {
if (req.getTargetUid() != session.getPlayer().getUid() && targetPlayer != null) {
// I hope that tomorrow there will be a hero who can support multiplayer mode and write code like a poem
var targetHome = GameHome.getByUid(req.getTargetUid());
val targetHome = GameHome.getByUid(req.getTargetUid());
switch (targetHome.getEnterHomeOption()) {
case FriendEnterHomeOptionOuterClass.FriendEnterHomeOption.FRIEND_ENTER_HOME_OPTION_NEED_CONFIRM_VALUE:
if (!targetPlayer.isOnline()) {
session.send(new PacketTryEnterHomeRsp(RetcodeOuterClass.Retcode.RET_HOME_OWNER_OFFLINE_VALUE, req.getTargetUid()));
return;
}
break;
case FriendEnterHomeOptionOuterClass.FriendEnterHomeOption.FRIEND_ENTER_HOME_OPTION_REFUSE_VALUE:
session.send(new PacketTryEnterHomeRsp(RetcodeOuterClass.Retcode.RET_HOME_HOME_REFUSE_GUEST_ENTER_VALUE, req.getTargetUid()));
return;
case FriendEnterHomeOptionOuterClass.FriendEnterHomeOption.FRIEND_ENTER_HOME_OPTION_DIRECT_VALUE:
break;
}
case FRIEND_ENTER_HOME_OPTION_NEED_CONFIRM_VALUE -> {
if (targetPlayer.isOnline()) break;
session.send(new PacketTryEnterHomeRsp());
session.send(new PacketTryEnterHomeRsp(RET_HOME_OWNER_OFFLINE_VALUE, req.getTargetUid()));
}
case FRIEND_ENTER_HOME_OPTION_REFUSE_VALUE ->
session.send(new PacketTryEnterHomeRsp(RET_HOME_HOME_REFUSE_GUEST_ENTER_VALUE, req.getTargetUid()));
case FRIEND_ENTER_HOME_OPTION_DIRECT_VALUE -> session.send(new PacketTryEnterHomeRsp());
}
return;
}
int realmId = 2000 + session.getPlayer().getCurrentRealmId();
var home = session.getPlayer().getHome();
final int realmId = 2000 + session.getPlayer().getCurrentRealmId();
val home = session.getPlayer().getHome();
// prepare the default arrangement for first come in
var homeScene = home.getHomeSceneItem(realmId);
home.getHomeSceneItem(realmId);
home.save();
Scene scene = session.getPlayer().getWorld().getSceneById(realmId);
Position pos = scene.getScriptManager().getConfig().born_pos;
// the function should be able to get pos and rot from scriptManager config
final boolean result = session.getPlayer().getWorld().transferPlayerToScene(
session.getPlayer(), realmId, TeleportType.WAYPOINT, null, null);
boolean result = session.getPlayer().getWorld().transferPlayerToScene(
session.getPlayer(), realmId,
TeleportType.WAYPOINT, pos
);
if (result) session.send(new PacketTryEnterHomeRsp(req.getTargetUid()));
}
}

View File

@ -0,0 +1,14 @@
package emu.grasscutter.server.packet.send;
import emu.grasscutter.data.excels.DungeonData;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.DungeonDataNotifyOuterClass;
public class PacketDungeonDataNotify extends BasePacket {
public PacketDungeonDataNotify(DungeonData dungeonData) {
super(PacketOpcodes.DungeonDataNotify);
// TODO
this.setData(DungeonDataNotifyOuterClass.DungeonDataNotify.newBuilder());
}
}

View File

@ -1,39 +1,26 @@
package emu.grasscutter.server.packet.send;
import java.util.Arrays;
import java.util.Comparator;
import emu.grasscutter.data.common.PointData;
import emu.grasscutter.data.excels.DungeonData;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.DungeonEntryInfoOuterClass.DungeonEntryInfo;
import emu.grasscutter.net.proto.DungeonEntryInfoRspOuterClass.DungeonEntryInfoRsp;
import emu.grasscutter.net.proto.RetcodeOuterClass.Retcode;
import lombok.val;
public class PacketDungeonEntryInfoRsp extends BasePacket {
public PacketDungeonEntryInfoRsp(Player player, int sceneId, int pointId) {
super(PacketOpcodes.DungeonEntryInfoRsp);
public PacketDungeonEntryInfoRsp(Player player, PointData pointData) {
super(PacketOpcodes.DungeonEntryInfoRsp);
val proto = DungeonEntryInfoRsp.newBuilder().setPointId(pointId);
val entries = player.getDungeonEntryManager().getDungeonEntries(sceneId, pointId);
proto.addAllDungeonEntryList(entries.stream().map(player.getDungeonEntryManager()::toProto).toList());
DungeonEntryInfoRsp.Builder proto = DungeonEntryInfoRsp.newBuilder()
.setPointId(pointData.getId());
entries.stream().min(Comparator.comparingInt(data -> Math.abs(data.getLimitLevel() - player.getLevel())))
.map(DungeonData::getId).ifPresent(proto::setRecommendDungeonId);
if (pointData.getDungeonIds() != null) {
for (int dungeonId : pointData.getDungeonIds()) {
DungeonEntryInfo info = DungeonEntryInfo.newBuilder().setDungeonId(dungeonId).build();
proto.addDungeonEntryList(info);
}
}
this.setData(proto);
}
public PacketDungeonEntryInfoRsp() {
super(PacketOpcodes.DungeonEntryInfoRsp);
DungeonEntryInfoRsp proto = DungeonEntryInfoRsp.newBuilder()
.setRetcode(1)
.build();
this.setData(proto);
}
this.setData(proto.setRetcode(!entries.isEmpty() ? Retcode.RET_SUCC_VALUE : Retcode.RET_FAIL_VALUE));
}
}

View File

@ -0,0 +1,12 @@
package emu.grasscutter.server.packet.send;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.DungeonRestartRspOuterClass;
public class PacketDungeonRestartRsp extends BasePacket {
public PacketDungeonRestartRsp() {
super(PacketOpcodes.DungeonRestartRsp);
this.setData(DungeonRestartRspOuterClass.DungeonRestartRsp.newBuilder());
}
}

View File

@ -0,0 +1,15 @@
package emu.grasscutter.server.packet.send;
import emu.grasscutter.data.excels.DungeonData;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.DungeonReviseLevelNotifyOuterClass.DungeonReviseLevelNotify;
public class PacketDungeonReviseLevelNotify extends BasePacket {
public PacketDungeonReviseLevelNotify(DungeonData dungeonData) {
super(PacketOpcodes.DungeonReviseLevelNotify);
this.setData(DungeonReviseLevelNotify.newBuilder()
.setDungeonId(dungeonData.getId())
.setReviseLevel(dungeonData.getLevelRevise()));
}
}

View File

@ -1,43 +1,56 @@
package emu.grasscutter.server.packet.send;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.excels.DungeonEntryData;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.quest.GameQuest;
import emu.grasscutter.game.quest.enums.LogicType;
import emu.grasscutter.game.quest.enums.QuestState;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.DailyDungeonEntryInfoOuterClass;
import emu.grasscutter.net.proto.DungeonEntryInfoOuterClass;
import emu.grasscutter.net.proto.GetDailyDungeonEntryInfoRspOuterClass;
import emu.grasscutter.net.proto.DailyDungeonEntryInfoOuterClass.DailyDungeonEntryInfo;
import emu.grasscutter.net.proto.GetDailyDungeonEntryInfoRspOuterClass.GetDailyDungeonEntryInfoRsp;
import lombok.val;
import java.util.List;
import java.util.*;
public class PacketGetDailyDungeonEntryInfoRsp extends BasePacket {
public PacketGetDailyDungeonEntryInfoRsp(Integer sceneID) {
public PacketGetDailyDungeonEntryInfoRsp(Player player, int sceneId) {
super(PacketOpcodes.GetDailyDungeonEntryInfoRsp);
var resp= GetDailyDungeonEntryInfoRspOuterClass.GetDailyDungeonEntryInfoRsp.newBuilder();
for (var info : GameData.getDungeonEntryDataMap().values().parallelStream().filter(d -> d.getSceneId() == sceneID).map(this::getDungonEntryInfo).toList())
resp.addDailyDungeonInfoList(info);
this.setData(resp.build());
this.setData(GetDailyDungeonEntryInfoRsp.newBuilder()
.addAllDailyDungeonInfoList(GameData.getDungeonEntryDataMap().values().stream()
.filter(data -> data.getSceneId() == sceneId)
.filter(DungeonEntryData::isShowInAdvHandbook)
.filter(data -> isSatisfied(player, data.getCondComb(), data.getSatisfiedCond()))
.map(data -> getDungeonEntryInfo(player, data))
.filter(DailyDungeonEntryInfo::hasRecommendDungeonEntryInfo)
.sorted(Comparator.comparing(DailyDungeonEntryInfo::getDungeonEntryConfigId))
.toList()));
}
private DailyDungeonEntryInfoOuterClass.DailyDungeonEntryInfo getDungonEntryInfo(DungeonEntryData data) {
var dungeonEntryId = data.getDungeonEntryId();
var id = data.getId();
private DailyDungeonEntryInfo getDungeonEntryInfo(Player player, DungeonEntryData entryData) {
val dailyEntryInfo = DailyDungeonEntryInfo.newBuilder();
player.getDungeonEntryManager().getDungeonEntries(entryData.getSceneId(), entryData.getDungeonEntryId()).stream()
.min(Comparator.comparingInt(data -> Math.abs(data.getLimitLevel() - player.getLevel())))
.ifPresent(dungeonData -> {
dailyEntryInfo.setRecommendDungeonId(dungeonData.getId());
dailyEntryInfo.setRecommendDungeonEntryInfo(player.getDungeonEntryManager().toProto(dungeonData));
});
// TODO
DungeonEntryInfoOuterClass.DungeonEntryInfo dungeonEntryInfo
= DungeonEntryInfoOuterClass.DungeonEntryInfo.newBuilder().setDungeonId(130).build();
var builder = DailyDungeonEntryInfoOuterClass.DailyDungeonEntryInfo.newBuilder();
builder.setDungeonEntryId(dungeonEntryId);
builder.setDungeonEntryConfigId(id);
builder.setRecommendDungeonEntryInfo(dungeonEntryInfo);
return builder.build();
return dailyEntryInfo.setDungeonEntryId(entryData.getDungeonEntryId()).setDungeonEntryConfigId(entryData.getId()).build();
}
private boolean isSatisfied(Player player, LogicType condComb, List<DungeonEntryData.SatisfiedCond> conds) {
return LogicType.calculate(condComb, conds.stream()
.filter(cond -> Optional.ofNullable(cond).map(DungeonEntryData.SatisfiedCond::getType).isPresent())
.map(cond -> switch (cond.getType()) {
case DUNGEON_ENTRY_CONDITION_LEVEL -> player.getLevel() >= cond.getParam1();
case DUNGEON_ENTRY_CONDITION_QUEST -> Optional.ofNullable(player.getQuestManager().getQuestById(cond.getParam1()))
.map(GameQuest::getState).filter(state -> state == QuestState.QUEST_STATE_FINISHED).isPresent();
case DUNGEON_ENTRY_CONDITION_NONE -> true;})
.mapToInt(result -> result ? 1 : 0)
.toArray());
}
}

View File

@ -22,6 +22,7 @@ public class PacketPlayerEnterSceneNotify extends BasePacket {
player.setEnterSceneToken(Utils.randomRange(1000, 99999));
PlayerEnterSceneNotify.Builder proto = PlayerEnterSceneNotify.newBuilder()
.setIsSkipUi(true)
.setSceneId(player.getSceneId())
.setPos(player.getPosition().toProto())
.setSceneBeginTime(System.currentTimeMillis())
@ -61,17 +62,18 @@ public class PacketPlayerEnterSceneNotify extends BasePacket {
player.setEnterSceneToken(Utils.randomRange(1000, 99999));
PlayerEnterSceneNotify.Builder proto = PlayerEnterSceneNotify.newBuilder()
.setPrevSceneId(player.getSceneId())
.setPrevPos(player.getPosition().toProto())
.setPrevSceneId(teleportProperties.getPrevSceneId())
.setPrevPos(teleportProperties.getPrevPos().toProto())
.setSceneId(teleportProperties.getSceneId())
.setPos(teleportProperties.getTeleportTo().toProto())
.setSceneBeginTime(System.currentTimeMillis())
.setType(teleportProperties.getEnterType())
.setTargetUid(target.getUid())
.setEnterSceneToken(player.getEnterSceneToken())
.setWorldLevel(target.getWorld().getWorldLevel())
.setWorldLevel(teleportProperties.getDungeonId() > 0 ? target.getWorldLevel() : 0)
.setEnterReason(teleportProperties.getEnterReason().getValue())
.setWorldType(1)
.setWorldType(teleportProperties.getWorldType()) // TODO
.setDungeonId(teleportProperties.getDungeonId())
.setSceneTransaction(teleportProperties.getSceneId() + "-" + target.getUid() + "-" + (int) (System.currentTimeMillis() / 1000) + "-" + 18402);
this.setData(proto);

View File

@ -1,35 +1,19 @@
package emu.grasscutter.server.packet.send;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.binout.ScenePointEntry;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.RetcodeOuterClass;
import emu.grasscutter.net.proto.RetcodeOuterClass.Retcode;
import emu.grasscutter.net.proto.SceneTransToPointRspOuterClass.SceneTransToPointRsp;
import emu.grasscutter.utils.Position;
public class PacketSceneTransToPointRsp extends BasePacket {
public PacketSceneTransToPointRsp(Player player, int pointId, int sceneId) {
super(PacketOpcodes.SceneTransToPointRsp);
public PacketSceneTransToPointRsp(boolean result, int pointId, int sceneId) {
super(PacketOpcodes.SceneTransToPointRsp);
SceneTransToPointRsp proto = SceneTransToPointRsp.newBuilder()
.setRetcode(0)
.setPointId(pointId)
.setSceneId(sceneId)
.build();
this.setData(proto);
}
public PacketSceneTransToPointRsp() {
super(PacketOpcodes.SceneTransToPointRsp);
SceneTransToPointRsp proto = SceneTransToPointRsp.newBuilder()
.setRetcode(RetcodeOuterClass.Retcode.RET_SVR_ERROR_VALUE) // Internal server error
.build();
this.setData(proto);
}
this.setData(SceneTransToPointRsp.newBuilder()
.setRetcode(result ? Retcode.RET_SUCC_VALUE : Retcode.RET_SVR_ERROR_VALUE) // Internal server error
.setPointId(pointId)
.setSceneId(sceneId)
.build());
}
}

View File

@ -24,8 +24,6 @@ public final class ServerTask implements Runnable {
/* The amount of times the task has been run. */
@Getter private int ticks = 0;
/* Should the check consider delay? */
private boolean considerDelay = true;
/**
* Cancels the task from running the next time.
@ -41,9 +39,8 @@ public final class ServerTask implements Runnable {
public boolean shouldRun() {
// Increase tick count.
var ticks = this.ticks++;
if(this.delay != -1 && this.considerDelay) {
this.considerDelay = false;
return ticks == this.delay;
if(this.delay != -1) {
return ticks == this.delay-1;
} else if(this.period != -1)
return ticks % this.period == 0;
else return true;
@ -54,7 +51,7 @@ public final class ServerTask implements Runnable {
* @return True if the task should be canceled, false otherwise.
*/
public boolean shouldCancel() {
return this.period == -1 && ticks > delay;
return this.period == -1 && ticks >= delay;
}
/**

View File

@ -26,7 +26,7 @@ public final class ServerTaskScheduler {
*/
public void runTasks() {
// Skip if there are no tasks.
if(this.tasks.size() == 0)
if(this.tasks.isEmpty())
return;
// Run all tasks.
@ -127,7 +127,7 @@ public final class ServerTaskScheduler {
* @return The ID of the task.
*/
public int scheduleRepeatingTask(Runnable runnable, int period) {
return this.scheduleDelayedRepeatingTask(runnable, period, 0);
return this.scheduleDelayedRepeatingTask(runnable, period, -1);
}
/**