mirror of
https://github.com/Grasscutters/Grasscutter.git
synced 2025-12-16 08:56:04 +01:00
Initial commit
This commit is contained in:
141
src/main/java/emu/grasscutter/net/packet/GenshinPacket.java
Normal file
141
src/main/java/emu/grasscutter/net/packet/GenshinPacket.java
Normal file
@@ -0,0 +1,141 @@
|
||||
package emu.grasscutter.net.packet;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import com.google.protobuf.GeneratedMessageV3;
|
||||
import emu.grasscutter.net.proto.PacketHeadOuterClass.PacketHead;
|
||||
import emu.grasscutter.utils.Crypto;
|
||||
|
||||
public class GenshinPacket {
|
||||
private static final int const1 = 17767; // 0x4567
|
||||
private static final int const2 = -30293; // 0x89ab
|
||||
|
||||
private int opcode;
|
||||
private boolean shouldBuildHeader = false;
|
||||
|
||||
private byte[] header;
|
||||
private byte[] data;
|
||||
|
||||
// Encryption
|
||||
private boolean useDispatchKey;
|
||||
public boolean shouldEncrypt = true;
|
||||
|
||||
public GenshinPacket(int opcode) {
|
||||
this.opcode = opcode;
|
||||
}
|
||||
|
||||
public GenshinPacket(int opcode, int clientSequence) {
|
||||
this.opcode = opcode;
|
||||
this.buildHeader(clientSequence);
|
||||
}
|
||||
|
||||
public GenshinPacket(int opcode, boolean buildHeader) {
|
||||
this.opcode = opcode;
|
||||
this.shouldBuildHeader = buildHeader;
|
||||
}
|
||||
|
||||
public int getOpcode() {
|
||||
return opcode;
|
||||
}
|
||||
|
||||
public void setOpcode(int opcode) {
|
||||
this.opcode = opcode;
|
||||
}
|
||||
|
||||
public boolean useDispatchKey() {
|
||||
return useDispatchKey;
|
||||
}
|
||||
|
||||
public void setUseDispatchKey(boolean useDispatchKey) {
|
||||
this.useDispatchKey = useDispatchKey;
|
||||
}
|
||||
|
||||
public byte[] getHeader() {
|
||||
return header;
|
||||
}
|
||||
|
||||
public void setHeader(byte[] header) {
|
||||
this.header = header;
|
||||
}
|
||||
|
||||
public boolean shouldBuildHeader() {
|
||||
return shouldBuildHeader;
|
||||
}
|
||||
|
||||
public byte[] getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(byte[] data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public void setData(GeneratedMessageV3 proto) {
|
||||
this.data = proto.toByteArray();
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public void setData(GeneratedMessageV3.Builder proto) {
|
||||
this.data = proto.build().toByteArray();
|
||||
}
|
||||
|
||||
public GenshinPacket buildHeader(int clientSequence) {
|
||||
if (this.getHeader() != null && clientSequence == 0) {
|
||||
return this;
|
||||
}
|
||||
setHeader(PacketHead.newBuilder().setClientSequenceId(clientSequence).setTimestamp(System.currentTimeMillis()).build().toByteArray());
|
||||
return this;
|
||||
}
|
||||
|
||||
public byte[] build() {
|
||||
if (getHeader() == null) {
|
||||
this.header = new byte[0];
|
||||
}
|
||||
|
||||
if (getData() == null) {
|
||||
this.data = new byte[0];
|
||||
}
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(2 + 2 + 2 + 4 + getHeader().length + getData().length + 2);
|
||||
|
||||
this.writeUint16(baos, const1);
|
||||
this.writeUint16(baos, opcode);
|
||||
this.writeUint16(baos, header.length);
|
||||
this.writeUint32(baos, data.length);
|
||||
this.writeBytes(baos, header);
|
||||
this.writeBytes(baos, data);
|
||||
this.writeUint16(baos, const2);
|
||||
|
||||
byte[] packet = baos.toByteArray();
|
||||
|
||||
if (this.shouldEncrypt) {
|
||||
Crypto.xor(packet, this.useDispatchKey() ? Crypto.DISPATCH_KEY : Crypto.ENCRYPT_KEY);
|
||||
}
|
||||
|
||||
return packet;
|
||||
}
|
||||
|
||||
public void writeUint16(ByteArrayOutputStream baos, int i) {
|
||||
// Unsigned short
|
||||
baos.write((byte) ((i >>> 8) & 0xFF));
|
||||
baos.write((byte) (i & 0xFF));
|
||||
}
|
||||
|
||||
public void writeUint32(ByteArrayOutputStream baos, int i) {
|
||||
// Unsigned int (long)
|
||||
baos.write((byte) ((i >>> 24) & 0xFF));
|
||||
baos.write((byte) ((i >>> 16) & 0xFF));
|
||||
baos.write((byte) ((i >>> 8) & 0xFF));
|
||||
baos.write((byte) (i & 0xFF));
|
||||
}
|
||||
|
||||
public void writeBytes(ByteArrayOutputStream baos, byte[] bytes) {
|
||||
try {
|
||||
baos.write(bytes);
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
13
src/main/java/emu/grasscutter/net/packet/Opcodes.java
Normal file
13
src/main/java/emu/grasscutter/net/packet/Opcodes.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package emu.grasscutter.net.packet;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Opcodes {
|
||||
/** Opcode for the packet/handler */
|
||||
int value();
|
||||
|
||||
/** HANDLER ONLY - will disable this handler from being registered */
|
||||
boolean disabled() default false;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package emu.grasscutter.net.packet;
|
||||
|
||||
import emu.grasscutter.server.game.GameSession;
|
||||
|
||||
public abstract class PacketHandler {
|
||||
protected static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
|
||||
|
||||
public abstract void handle(GameSession session, byte[] header, byte[] payload) throws Exception;
|
||||
}
|
||||
1211
src/main/java/emu/grasscutter/net/packet/PacketOpcodes.java
Normal file
1211
src/main/java/emu/grasscutter/net/packet/PacketOpcodes.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,44 @@
|
||||
package emu.grasscutter.net.packet;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
|
||||
public class PacketOpcodesUtil {
|
||||
private static Int2ObjectMap<String> opcodeMap;
|
||||
|
||||
static {
|
||||
opcodeMap = new Int2ObjectOpenHashMap<String>();
|
||||
|
||||
Field[] fields = PacketOpcodes.class.getFields();
|
||||
|
||||
for (Field f : fields) {
|
||||
try {
|
||||
opcodeMap.put(f.getInt(null), f.getName());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static String getOpcodeName(int opcode) {
|
||||
if (opcode <= 0) return "UNKNOWN";
|
||||
return opcodeMap.getOrDefault(opcode, "UNKNOWN");
|
||||
}
|
||||
|
||||
public static void dumpOpcodes() {
|
||||
try {
|
||||
BufferedWriter out = new BufferedWriter(new FileWriter("opcodes.ini"));
|
||||
for (Int2ObjectMap.Entry<String> entry : opcodeMap.int2ObjectEntrySet()) {
|
||||
out.write(String.format("%04X=%s%s", entry.getIntKey(), entry.getValue(), System.lineSeparator()));
|
||||
}
|
||||
out.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
177
src/main/java/emu/grasscutter/net/packet/PacketWriter.java
Normal file
177
src/main/java/emu/grasscutter/net/packet/PacketWriter.java
Normal file
@@ -0,0 +1,177 @@
|
||||
package emu.grasscutter.net.packet;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class PacketWriter {
|
||||
// Little endian
|
||||
private final ByteArrayOutputStream baos;
|
||||
|
||||
public PacketWriter() {
|
||||
this.baos = new ByteArrayOutputStream(128);
|
||||
}
|
||||
|
||||
public byte[] build() {
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
// Writers
|
||||
|
||||
public void writeEmpty(int i) {
|
||||
while (i > 0) {
|
||||
baos.write(0);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
public void writeMax(int i) {
|
||||
while (i > 0) {
|
||||
baos.write(0xFF);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
public void writeInt8(byte b) {
|
||||
baos.write(b);
|
||||
}
|
||||
|
||||
public void writeInt8(int i) {
|
||||
baos.write((byte) i);
|
||||
}
|
||||
|
||||
public void writeBoolean(boolean b) {
|
||||
baos.write(b ? 1 : 0);
|
||||
}
|
||||
|
||||
public void writeUint8(byte b) {
|
||||
// Unsigned byte
|
||||
baos.write(b & 0xFF);
|
||||
}
|
||||
|
||||
public void writeUint8(int i) {
|
||||
|
||||
baos.write((byte) i & 0xFF);
|
||||
}
|
||||
|
||||
public void writeUint16(int i) {
|
||||
// Unsigned short
|
||||
baos.write((byte) (i & 0xFF));
|
||||
baos.write((byte) ((i >>> 8) & 0xFF));
|
||||
}
|
||||
|
||||
public void writeUint24(int i) {
|
||||
// 24 bit integer
|
||||
baos.write((byte) (i & 0xFF));
|
||||
baos.write((byte) ((i >>> 8) & 0xFF));
|
||||
baos.write((byte) ((i >>> 16) & 0xFF));
|
||||
}
|
||||
|
||||
public void writeInt16(int i) {
|
||||
// Signed short
|
||||
baos.write((byte) i);
|
||||
baos.write((byte) (i >>> 8));
|
||||
}
|
||||
|
||||
public void writeUint32(int i) {
|
||||
// Unsigned int
|
||||
baos.write((byte) (i & 0xFF));
|
||||
baos.write((byte) ((i >>> 8) & 0xFF));
|
||||
baos.write((byte) ((i >>> 16) & 0xFF));
|
||||
baos.write((byte) ((i >>> 24) & 0xFF));
|
||||
}
|
||||
|
||||
public void writeInt32(int i) {
|
||||
// Signed int
|
||||
baos.write((byte) i);
|
||||
baos.write((byte) (i >>> 8));
|
||||
baos.write((byte) (i >>> 16));
|
||||
baos.write((byte) (i >>> 24));
|
||||
}
|
||||
|
||||
public void writeUint32(long i) {
|
||||
// Unsigned int (long)
|
||||
baos.write((byte) (i & 0xFF));
|
||||
baos.write((byte) ((i >>> 8) & 0xFF));
|
||||
baos.write((byte) ((i >>> 16) & 0xFF));
|
||||
baos.write((byte) ((i >>> 24) & 0xFF));
|
||||
}
|
||||
|
||||
public void writeFloat(float f){
|
||||
this.writeUint32(Float.floatToRawIntBits(f));
|
||||
}
|
||||
|
||||
public void writeUint64(long l) {
|
||||
baos.write((byte) (l & 0xFF));
|
||||
baos.write((byte) ((l >>> 8) & 0xFF));
|
||||
baos.write((byte) ((l >>> 16) & 0xFF));
|
||||
baos.write((byte) ((l >>> 24) & 0xFF));
|
||||
baos.write((byte) ((l >>> 32) & 0xFF));
|
||||
baos.write((byte) ((l >>> 40) & 0xFF));
|
||||
baos.write((byte) ((l >>> 48) & 0xFF));
|
||||
baos.write((byte) ((l >>> 56) & 0xFF));
|
||||
}
|
||||
|
||||
public void writeDouble(double d){
|
||||
long l = Double.doubleToLongBits(d);
|
||||
this.writeUint64(l);
|
||||
}
|
||||
|
||||
public void writeString16(String s) {
|
||||
if (s == null) {
|
||||
this.writeUint16(0);
|
||||
return;
|
||||
}
|
||||
|
||||
this.writeUint16(s.length() * 2);
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
char c = s.charAt(i);
|
||||
this.writeUint16((short) c);
|
||||
}
|
||||
}
|
||||
|
||||
public void writeString8(String s) {
|
||||
if (s == null) {
|
||||
this.writeUint16(0);
|
||||
return;
|
||||
}
|
||||
|
||||
this.writeUint16(s.length());
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
char c = s.charAt(i);
|
||||
this.writeUint8((byte) c);
|
||||
}
|
||||
}
|
||||
|
||||
public void writeDirectString8(String s, int expectedSize) {
|
||||
if (s == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < expectedSize; i++) {
|
||||
char c = i < s.length() ? s.charAt(i) : 0;
|
||||
this.writeUint8((byte) c);
|
||||
}
|
||||
}
|
||||
|
||||
public void writeBytes(byte[] bytes) {
|
||||
try {
|
||||
baos.write(bytes);
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void writeBytes(int[] bytes) {
|
||||
byte[] b = new byte[bytes.length];
|
||||
for (int i = 0; i < bytes.length; i++)
|
||||
b[i] = (byte)bytes[i];
|
||||
|
||||
try {
|
||||
baos.write(b);
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
6
src/main/java/emu/grasscutter/net/packet/Retcode.java
Normal file
6
src/main/java/emu/grasscutter/net/packet/Retcode.java
Normal file
@@ -0,0 +1,6 @@
|
||||
package emu.grasscutter.net.packet;
|
||||
|
||||
public class Retcode {
|
||||
public static final int SUCCESS = 0;
|
||||
public static final int FAIL = 1;
|
||||
}
|
||||
Reference in New Issue
Block a user