From 8efb62490ec153246d467a1a72c513781db887bf Mon Sep 17 00:00:00 2001 From: 2xsaiko Date: Thu, 8 Jul 2021 16:30:39 +0200 Subject: Entry Changes (#364) * Initial refactor: Allow EntryMapping to have null targetName, add EntryChange in favor of entry changing methods in GuiController * Fix resetting name not actually removing it, and renaming a class causing name collisions with itself Closes #246. * Use name proposer for setting default deobf name Closes #314 * Make network protocol use EntryChange directly * Handle writing other data correctly when the deobf name is null * b * Add some new abstraction stuff * Use pattern matching instanceof * Move classes out of newabstraction package * Make EntryChange final * Regenerate equals and hashCode * Convert EntryMapping to record * Make TristateChange final * Safety guard null accessModifier initialization--- enigma-server/docs/protocol.md | 164 ++++++++------------- .../cuchaz/enigma/network/ClientPacketHandler.java | 12 +- .../java/cuchaz/enigma/network/EnigmaServer.java | 9 +- .../enigma/network/packet/ChangeDocsC2SPacket.java | 64 -------- .../enigma/network/packet/ChangeDocsS2CPacket.java | 51 ------- .../network/packet/EntryChangeC2SPacket.java | 66 +++++++++ .../network/packet/EntryChangeS2CPacket.java | 42 ++++++ .../network/packet/MarkDeobfuscatedC2SPacket.java | 56 ------- .../network/packet/MarkDeobfuscatedS2CPacket.java | 47 ------ .../cuchaz/enigma/network/packet/PacketHelper.java | 130 +++++++++++----- .../enigma/network/packet/PacketRegistry.java | 16 +- .../network/packet/RemoveMappingC2SPacket.java | 56 ------- .../network/packet/RemoveMappingS2CPacket.java | 47 ------ .../enigma/network/packet/RenameC2SPacket.java | 66 --------- .../enigma/network/packet/RenameS2CPacket.java | 55 ------- .../network/packet/SyncMappingsS2CPacket.java | 41 ++---- 16 files changed, 295 insertions(+), 627 deletions(-) delete mode 100644 enigma-server/src/main/java/cuchaz/enigma/network/packet/ChangeDocsC2SPacket.java delete mode 100644 enigma-server/src/main/java/cuchaz/enigma/network/packet/ChangeDocsS2CPacket.java create mode 100644 enigma-server/src/main/java/cuchaz/enigma/network/packet/EntryChangeC2SPacket.java create mode 100644 enigma-server/src/main/java/cuchaz/enigma/network/packet/EntryChangeS2CPacket.java delete mode 100644 enigma-server/src/main/java/cuchaz/enigma/network/packet/MarkDeobfuscatedC2SPacket.java delete mode 100644 enigma-server/src/main/java/cuchaz/enigma/network/packet/MarkDeobfuscatedS2CPacket.java delete mode 100644 enigma-server/src/main/java/cuchaz/enigma/network/packet/RemoveMappingC2SPacket.java delete mode 100644 enigma-server/src/main/java/cuchaz/enigma/network/packet/RemoveMappingS2CPacket.java delete mode 100644 enigma-server/src/main/java/cuchaz/enigma/network/packet/RenameC2SPacket.java delete mode 100644 enigma-server/src/main/java/cuchaz/enigma/network/packet/RenameS2CPacket.java (limited to 'enigma-server') diff --git a/enigma-server/docs/protocol.md b/enigma-server/docs/protocol.md index c14ecb81..83ef4c01 100644 --- a/enigma-server/docs/protocol.md +++ b/enigma-server/docs/protocol.md @@ -75,21 +75,15 @@ struct Packet { The IDs for client-to-server packets are as follows: - 0: `Login` - 1: `ConfirmChange` -- 2: `Rename` -- 3: `RemoveMapping` -- 4: `ChangeDocs` -- 5: `MarkDeobfuscated` - 6: `Message` +- 7: `EntryChange` The IDs for server-to-client packets are as follows: - 0: `Kick` - 1: `SyncMappings` -- 2: `Rename` -- 3: `RemoveMapping` -- 4: `ChangeDocs` -- 5: `MarkDeobfuscated` - 6: `Message` - 7: `UserList` +- 8: `EntryChange` ### The utf struct ```c @@ -196,6 +190,45 @@ struct Message { - `entry`: The entry that was modified. - `new_name`: The new name for the entry. +### The entry_change struct +```c +typedef enum tristate_change { + TRISTATE_CHANGE_UNCHANGED = 0, + TRISTATE_CHANGE_RESET = 1, + TRISTATE_CHANGE_SET = 2 +} tristate_change_t; + +typedef enum access_modifier { + ACCESS_MODIFIER_UNCHANGED = 0, + ACCESS_MODIFIER_PUBLIC = 1, + ACCESS_MODIFIER_PROTECTED = 2, + ACCESS_MODIFIER_PRIVATE = 3 +} access_modifier_t; + +// Contains 4 packed values: +// bitmask type +// 00000011 tristate_change_t deobf_name_change; +// 00001100 tristate_change_t access_change; +// 00110000 tristate_change_t javadoc_change; +// 11000000 access_modifier_t access_modifiers; +typedef uint8_t entry_change_flags; + +struct entry_change { + Entry entry; + entry_change_flags flags; + if { + utf deobf_name; + } + if { + utf javadoc; + } +} +``` +- `entry`: The entry this change gets applied to. +- `flags`: See definition of `entry_change_flags`. +- `deobf_name`: The new deobfuscated name, if deobf_name_change == TRISTATE_CHANGE_SET +- `javadoc`: The new javadoc, if javadoc_change == TRISTATE_CHANGE_SET +- `access_modifiers`: The new access modifier, if access_change == TRISTATE_CHANGE_SET (otherwise 0) ### Login (client-to-server) ```c @@ -223,44 +256,6 @@ struct ConfirmChangeC2SPacket { ``` - `sync_id`: the sync ID to confirm. -### Rename (client-to-server) -```c -struct RenameC2SPacket { - Entry obf_entry; - utf new_name; - boolean refresh_class_tree; -} -``` -- `obf_entry`: the obfuscated name and descriptor of the entry to rename. -- `new_name`: what to rename the entry to. -- `refresh_class_tree`: whether the class tree on the sidebar of Enigma needs refreshing as a result of this change. - -### RemoveMapping (client-to-server) -```c -struct RemoveMappingC2SPacket { - Entry obf_entry; -} -``` -- `obf_entry`: the obfuscated name and descriptor of the entry to remove the mapping for. - -### ChangeDocs (client-to-server) -```c -struct ChangeDocsC2SPacket { - Entry obf_entry; - utf new_docs; -} -``` -- `obf_entry`: the obfuscated name and descriptor of the entry to change the documentation for. -- `new_docs`: the new documentation for this entry, or an empty string to remove the documentation. - -### MarkDeobfuscated (client-to-server) -```c -struct MarkDeobfuscatedC2SPacket { - Entry obf_entry; -} -``` -- `obf_entry`: the obfuscated name and descriptor of the entry to mark as deobfuscated. - ### Message (client-to-server) ```c struct MessageC2SPacket { @@ -269,6 +264,14 @@ struct MessageC2SPacket { ``` - `message`: The text message the user sent. +### EntryChange (client-to-server) +```c +struct EntryChangeC2SPacket { + entry_change change; +} +``` +- `change`: The change to apply. + ### Kick (server-to-client) ```c struct KickS2CPacket { @@ -286,13 +289,8 @@ struct SyncMappingsS2CPacket { struct MappingNode { NoParentEntry obf_entry; boolean is_named; - if { - utf name; - boolean has_javadoc; - if { - utf javadoc; - } - } + utf name; + utf javadoc; unsigned short children_count; MappingNode children[children_count]; } @@ -300,56 +298,10 @@ typedef { Entry but without the has_parent or parent fields } NoParentEntry; ``` - `roots`: The root mapping nodes, containing all the entries without parents. - `obf_entry`: The value of a node, containing the obfuscated name and descriptor of the entry. -- `name`: The deobfuscated name of the entry, if it has a mapping. -- `javadoc`: The documentation for the entry, if it is named and has documentation. +- `name`: The deobfuscated name of the entry, if it exists, otherwise the empty string. +- `javadoc`: The documentation for the entry, if it exists, otherwise the empty string. - `children`: The children of this node -### Rename (server-to-client) -```c -struct RenameS2CPacket { - unsigned short sync_id; - Entry obf_entry; - utf new_name; - boolean refresh_class_tree; -} -``` -- `sync_id`: the sync ID of the change for locking purposes. -- `obf_entry`: the obfuscated name and descriptor of the entry to rename. -- `new_name`: what to rename the entry to. -- `refresh_class_tree`: whether the class tree on the sidebar of Enigma needs refreshing as a result of this change. - -### RemoveMapping (server-to-client) -```c -struct RemoveMappingS2CPacket { - unsigned short sync_id; - Entry obf_entry; -} -``` -- `sync_id`: the sync ID of the change for locking purposes. -- `obf_entry`: the obfuscated name and descriptor of the entry to remove the mapping for. - -### ChangeDocs (server-to-client) -```c -struct ChangeDocsS2CPacket { - unsigned short sync_id; - Entry obf_entry; - utf new_docs; -} -``` -- `sync_id`: the sync ID of the change for locking purposes. -- `obf_entry`: the obfuscated name and descriptor of the entry to change the documentation for. -- `new_docs`: the new documentation for this entry, or an empty string to remove the documentation. - -### MarkDeobfuscated (server-to-client) -```c -struct MarkDeobfuscatedS2CPacket { - unsigned short sync_id; - Entry obf_entry; -} -``` -- `sync_id`: the sync ID of the change for locking purposes. -- `obf_entry`: the obfuscated name and descriptor of the entry to mark as deobfuscated. - ### Message (server-to-client) ```c struct MessageS2CPacket { @@ -364,3 +316,13 @@ struct UserListS2CPacket { utf user[len]; } ``` + +### EntryChange (server-to-client) +```c +struct EntryChangeS2CPacket { + uint16_t sync_id; + entry_change change; +} +``` +- `sync_id`: The sync ID of the change for locking purposes. +- `change`: The change to apply. \ No newline at end of file diff --git a/enigma-server/src/main/java/cuchaz/enigma/network/ClientPacketHandler.java b/enigma-server/src/main/java/cuchaz/enigma/network/ClientPacketHandler.java index 1b0191be..a651fe84 100644 --- a/enigma-server/src/main/java/cuchaz/enigma/network/ClientPacketHandler.java +++ b/enigma-server/src/main/java/cuchaz/enigma/network/ClientPacketHandler.java @@ -1,24 +1,16 @@ package cuchaz.enigma.network; -import cuchaz.enigma.analysis.EntryReference; +import cuchaz.enigma.translation.mapping.EntryChange; import cuchaz.enigma.translation.mapping.EntryMapping; import cuchaz.enigma.translation.mapping.tree.EntryTree; import cuchaz.enigma.network.packet.Packet; -import cuchaz.enigma.translation.representation.entry.Entry; -import cuchaz.enigma.utils.validation.ValidationContext; import java.util.List; public interface ClientPacketHandler { void openMappings(EntryTree mappings); - void rename(ValidationContext vc, EntryReference, Entry> reference, String newName, boolean refreshClassTree); - - void removeMapping(ValidationContext vc, EntryReference, Entry> reference); - - void changeDocs(ValidationContext vc, EntryReference, Entry> reference, String updatedDocs); - - void markAsDeobfuscated(ValidationContext vc, EntryReference, Entry> reference); + boolean applyChangeFromServer(EntryChange change); void disconnectIfConnected(String reason); diff --git a/enigma-server/src/main/java/cuchaz/enigma/network/EnigmaServer.java b/enigma-server/src/main/java/cuchaz/enigma/network/EnigmaServer.java index 75981c3b..1ce359b6 100644 --- a/enigma-server/src/main/java/cuchaz/enigma/network/EnigmaServer.java +++ b/enigma-server/src/main/java/cuchaz/enigma/network/EnigmaServer.java @@ -8,6 +8,7 @@ import java.util.*; import java.util.concurrent.CopyOnWriteArrayList; import cuchaz.enigma.network.packet.*; +import cuchaz.enigma.translation.mapping.EntryChange; import cuchaz.enigma.translation.mapping.EntryMapping; import cuchaz.enigma.translation.mapping.EntryRemapper; import cuchaz.enigma.translation.representation.entry.Entry; @@ -16,7 +17,7 @@ public abstract class EnigmaServer { // https://discordapp.com/channels/507304429255393322/566418023372816394/700292322918793347 public static final int DEFAULT_PORT = 34712; - public static final int PROTOCOL_VERSION = 0; + public static final int PROTOCOL_VERSION = 1; public static final int CHECKSUM_SIZE = 20; public static final int MAX_PASSWORD_LENGTH = 255; // length is written as a byte in the login packet @@ -234,11 +235,11 @@ public abstract class EnigmaServer { public void sendCorrectMapping(Socket client, Entry entry, boolean refreshClassTree) { EntryMapping oldMapping = mappings.getDeobfMapping(entry); - String oldName = oldMapping == null ? null : oldMapping.getTargetName(); + String oldName = oldMapping.targetName(); if (oldName == null) { - sendPacket(client, new RemoveMappingS2CPacket(DUMMY_SYNC_ID, entry)); + sendPacket(client, new EntryChangeS2CPacket(DUMMY_SYNC_ID, EntryChange.modify(entry).clearDeobfName())); } else { - sendPacket(client, new RenameS2CPacket(0, entry, oldName, refreshClassTree)); + sendPacket(client, new EntryChangeS2CPacket(0, EntryChange.modify(entry).withDeobfName(oldName))); } } diff --git a/enigma-server/src/main/java/cuchaz/enigma/network/packet/ChangeDocsC2SPacket.java b/enigma-server/src/main/java/cuchaz/enigma/network/packet/ChangeDocsC2SPacket.java deleted file mode 100644 index f3e07c2d..00000000 --- a/enigma-server/src/main/java/cuchaz/enigma/network/packet/ChangeDocsC2SPacket.java +++ /dev/null @@ -1,64 +0,0 @@ -package cuchaz.enigma.network.packet; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -import cuchaz.enigma.translation.mapping.EntryMapping; -import cuchaz.enigma.network.EnigmaServer; -import cuchaz.enigma.network.Message; -import cuchaz.enigma.network.ServerPacketHandler; -import cuchaz.enigma.translation.representation.entry.Entry; -import cuchaz.enigma.utils.validation.PrintValidatable; -import cuchaz.enigma.utils.validation.ValidationContext; - -public class ChangeDocsC2SPacket implements Packet { - private Entry entry; - private String newDocs; - - ChangeDocsC2SPacket() { - } - - public ChangeDocsC2SPacket(Entry entry, String newDocs) { - this.entry = entry; - this.newDocs = newDocs; - } - - @Override - public void read(DataInput input) throws IOException { - this.entry = PacketHelper.readEntry(input); - this.newDocs = PacketHelper.readString(input); - } - - @Override - public void write(DataOutput output) throws IOException { - PacketHelper.writeEntry(output, entry); - PacketHelper.writeString(output, newDocs); - } - - @Override - public void handle(ServerPacketHandler handler) { - ValidationContext vc = new ValidationContext(); - vc.setActiveElement(PrintValidatable.INSTANCE); - - EntryMapping mapping = handler.getServer().getMappings().getDeobfMapping(entry); - - boolean valid = handler.getServer().canModifyEntry(handler.getClient(), entry); - if (!valid) { - String oldDocs = mapping == null ? null : mapping.getJavadoc(); - handler.getServer().sendPacket(handler.getClient(), new ChangeDocsS2CPacket(EnigmaServer.DUMMY_SYNC_ID, entry, oldDocs == null ? "" : oldDocs)); - return; - } - - if (mapping == null) { - mapping = new EntryMapping(handler.getServer().getMappings().deobfuscate(entry).getName()); - } - handler.getServer().getMappings().mapFromObf(vc, entry, mapping.withDocs(newDocs.isBlank() ? null : newDocs)); - - if (!vc.canProceed()) return; - - int syncId = handler.getServer().lockEntry(handler.getClient(), entry); - handler.getServer().sendToAllExcept(handler.getClient(), new ChangeDocsS2CPacket(syncId, entry, newDocs)); - handler.getServer().sendMessage(Message.editDocs(handler.getServer().getUsername(handler.getClient()), entry)); - } -} diff --git a/enigma-server/src/main/java/cuchaz/enigma/network/packet/ChangeDocsS2CPacket.java b/enigma-server/src/main/java/cuchaz/enigma/network/packet/ChangeDocsS2CPacket.java deleted file mode 100644 index 78fa4fa9..00000000 --- a/enigma-server/src/main/java/cuchaz/enigma/network/packet/ChangeDocsS2CPacket.java +++ /dev/null @@ -1,51 +0,0 @@ -package cuchaz.enigma.network.packet; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -import cuchaz.enigma.analysis.EntryReference; -import cuchaz.enigma.network.ClientPacketHandler; -import cuchaz.enigma.translation.representation.entry.Entry; -import cuchaz.enigma.utils.validation.PrintValidatable; -import cuchaz.enigma.utils.validation.ValidationContext; - -public class ChangeDocsS2CPacket implements Packet { - private int syncId; - private Entry entry; - private String newDocs; - - ChangeDocsS2CPacket() { - } - - public ChangeDocsS2CPacket(int syncId, Entry entry, String newDocs) { - this.syncId = syncId; - this.entry = entry; - this.newDocs = newDocs; - } - - @Override - public void read(DataInput input) throws IOException { - this.syncId = input.readUnsignedShort(); - this.entry = PacketHelper.readEntry(input); - this.newDocs = PacketHelper.readString(input); - } - - @Override - public void write(DataOutput output) throws IOException { - output.writeShort(syncId); - PacketHelper.writeEntry(output, entry); - PacketHelper.writeString(output, newDocs); - } - - @Override - public void handle(ClientPacketHandler controller) { - ValidationContext vc = new ValidationContext(); - vc.setActiveElement(PrintValidatable.INSTANCE); - - controller.changeDocs(vc, new EntryReference<>(entry, entry.getName()), newDocs); - - if (!vc.canProceed()) return; - controller.sendPacket(new ConfirmChangeC2SPacket(syncId)); - } -} diff --git a/enigma-server/src/main/java/cuchaz/enigma/network/packet/EntryChangeC2SPacket.java b/enigma-server/src/main/java/cuchaz/enigma/network/packet/EntryChangeC2SPacket.java new file mode 100644 index 00000000..b97877c6 --- /dev/null +++ b/enigma-server/src/main/java/cuchaz/enigma/network/packet/EntryChangeC2SPacket.java @@ -0,0 +1,66 @@ +package cuchaz.enigma.network.packet; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +import cuchaz.enigma.network.Message; +import cuchaz.enigma.network.ServerPacketHandler; +import cuchaz.enigma.translation.mapping.EntryChange; +import cuchaz.enigma.translation.mapping.EntryUtil; +import cuchaz.enigma.utils.validation.PrintValidatable; +import cuchaz.enigma.utils.validation.ValidationContext; + +public class EntryChangeC2SPacket implements Packet { + + private EntryChange change; + + EntryChangeC2SPacket() { + } + + public EntryChangeC2SPacket(EntryChange change) { + this.change = change; + } + + @Override + public void read(DataInput input) throws IOException { + this.change = PacketHelper.readEntryChange(input); + } + + @Override + public void write(DataOutput output) throws IOException { + PacketHelper.writeEntryChange(output, change); + } + + @Override + public void handle(ServerPacketHandler handler) { + ValidationContext vc = new ValidationContext(); + vc.setActiveElement(PrintValidatable.INSTANCE); + + boolean valid = handler.getServer().canModifyEntry(handler.getClient(), this.change.getTarget()); + + if (valid) { + EntryUtil.applyChange(vc, handler.getServer().getMappings(), this.change); + valid = vc.canProceed(); + } + + if (!valid) { + handler.getServer().sendCorrectMapping(handler.getClient(), this.change.getTarget(), true); + return; + } + + int syncId = handler.getServer().lockEntry(handler.getClient(), this.change.getTarget()); + handler.getServer().sendToAllExcept(handler.getClient(), new EntryChangeS2CPacket(syncId, this.change)); + + if (this.change.getDeobfName().isSet()) { + handler.getServer().sendMessage(Message.rename(handler.getServer().getUsername(handler.getClient()), this.change.getTarget(), this.change.getDeobfName().getNewValue())); + } else if (this.change.getDeobfName().isReset()) { + handler.getServer().sendMessage(Message.removeMapping(handler.getServer().getUsername(handler.getClient()), this.change.getTarget())); + } + + if (!this.change.getJavadoc().isUnchanged()) { + handler.getServer().sendMessage(Message.editDocs(handler.getServer().getUsername(handler.getClient()), this.change.getTarget())); + } + } + +} diff --git a/enigma-server/src/main/java/cuchaz/enigma/network/packet/EntryChangeS2CPacket.java b/enigma-server/src/main/java/cuchaz/enigma/network/packet/EntryChangeS2CPacket.java new file mode 100644 index 00000000..a237b916 --- /dev/null +++ b/enigma-server/src/main/java/cuchaz/enigma/network/packet/EntryChangeS2CPacket.java @@ -0,0 +1,42 @@ +package cuchaz.enigma.network.packet; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +import cuchaz.enigma.network.ClientPacketHandler; +import cuchaz.enigma.translation.mapping.EntryChange; + +public class EntryChangeS2CPacket implements Packet { + + private int syncId; + private EntryChange change; + + public EntryChangeS2CPacket(int syncId, EntryChange change) { + this.syncId = syncId; + this.change = change; + } + + EntryChangeS2CPacket() { + } + + @Override + public void read(DataInput input) throws IOException { + this.syncId = input.readUnsignedShort(); + this.change = PacketHelper.readEntryChange(input); + } + + @Override + public void write(DataOutput output) throws IOException { + output.writeShort(this.syncId); + PacketHelper.writeEntryChange(output, this.change); + } + + @Override + public void handle(ClientPacketHandler handler) { + if (handler.applyChangeFromServer(this.change)) { + handler.sendPacket(new ConfirmChangeC2SPacket(this.syncId)); + } + } + +} diff --git a/enigma-server/src/main/java/cuchaz/enigma/network/packet/MarkDeobfuscatedC2SPacket.java b/enigma-server/src/main/java/cuchaz/enigma/network/packet/MarkDeobfuscatedC2SPacket.java deleted file mode 100644 index 732c7448..00000000 --- a/enigma-server/src/main/java/cuchaz/enigma/network/packet/MarkDeobfuscatedC2SPacket.java +++ /dev/null @@ -1,56 +0,0 @@ -package cuchaz.enigma.network.packet; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -import cuchaz.enigma.network.Message; -import cuchaz.enigma.network.ServerPacketHandler; -import cuchaz.enigma.translation.mapping.EntryMapping; -import cuchaz.enigma.translation.representation.entry.Entry; -import cuchaz.enigma.utils.validation.PrintValidatable; -import cuchaz.enigma.utils.validation.ValidationContext; - -public class MarkDeobfuscatedC2SPacket implements Packet { - private Entry entry; - - MarkDeobfuscatedC2SPacket() { - } - - public MarkDeobfuscatedC2SPacket(Entry entry) { - this.entry = entry; - } - - @Override - public void read(DataInput input) throws IOException { - this.entry = PacketHelper.readEntry(input); - } - - @Override - public void write(DataOutput output) throws IOException { - PacketHelper.writeEntry(output, entry); - } - - @Override - public void handle(ServerPacketHandler handler) { - ValidationContext vc = new ValidationContext(); - vc.setActiveElement(PrintValidatable.INSTANCE); - - boolean valid = handler.getServer().canModifyEntry(handler.getClient(), entry); - - if (!valid) { - handler.getServer().sendCorrectMapping(handler.getClient(), entry, true); - return; - } - - handler.getServer().getMappings().mapFromObf(vc, entry, new EntryMapping(handler.getServer().getMappings().deobfuscate(entry).getName())); - - if (!vc.canProceed()) return; - - handler.getServer().log(handler.getServer().getUsername(handler.getClient()) + " marked " + entry + " as deobfuscated"); - - int syncId = handler.getServer().lockEntry(handler.getClient(), entry); - handler.getServer().sendToAllExcept(handler.getClient(), new MarkDeobfuscatedS2CPacket(syncId, entry)); - handler.getServer().sendMessage(Message.markDeobf(handler.getServer().getUsername(handler.getClient()), entry)); - } -} diff --git a/enigma-server/src/main/java/cuchaz/enigma/network/packet/MarkDeobfuscatedS2CPacket.java b/enigma-server/src/main/java/cuchaz/enigma/network/packet/MarkDeobfuscatedS2CPacket.java deleted file mode 100644 index 969d13c5..00000000 --- a/enigma-server/src/main/java/cuchaz/enigma/network/packet/MarkDeobfuscatedS2CPacket.java +++ /dev/null @@ -1,47 +0,0 @@ -package cuchaz.enigma.network.packet; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -import cuchaz.enigma.analysis.EntryReference; -import cuchaz.enigma.network.ClientPacketHandler; -import cuchaz.enigma.translation.representation.entry.Entry; -import cuchaz.enigma.utils.validation.PrintValidatable; -import cuchaz.enigma.utils.validation.ValidationContext; - -public class MarkDeobfuscatedS2CPacket implements Packet { - private int syncId; - private Entry entry; - - MarkDeobfuscatedS2CPacket() { - } - - public MarkDeobfuscatedS2CPacket(int syncId, Entry entry) { - this.syncId = syncId; - this.entry = entry; - } - - @Override - public void read(DataInput input) throws IOException { - this.syncId = input.readUnsignedShort(); - this.entry = PacketHelper.readEntry(input); - } - - @Override - public void write(DataOutput output) throws IOException { - output.writeShort(syncId); - PacketHelper.writeEntry(output, entry); - } - - @Override - public void handle(ClientPacketHandler controller) { - ValidationContext vc = new ValidationContext(); - vc.setActiveElement(PrintValidatable.INSTANCE); - - controller.markAsDeobfuscated(vc, new EntryReference<>(entry, entry.getName())); - - if (!vc.canProceed()) return; - controller.sendPacket(new ConfirmChangeC2SPacket(syncId)); - } -} diff --git a/enigma-server/src/main/java/cuchaz/enigma/network/packet/PacketHelper.java b/enigma-server/src/main/java/cuchaz/enigma/network/packet/PacketHelper.java index 464606e0..2649cdc4 100644 --- a/enigma-server/src/main/java/cuchaz/enigma/network/packet/PacketHelper.java +++ b/enigma-server/src/main/java/cuchaz/enigma/network/packet/PacketHelper.java @@ -1,18 +1,17 @@ package cuchaz.enigma.network.packet; -import cuchaz.enigma.translation.representation.MethodDescriptor; -import cuchaz.enigma.translation.representation.TypeDescriptor; -import cuchaz.enigma.translation.representation.entry.ClassEntry; -import cuchaz.enigma.translation.representation.entry.Entry; -import cuchaz.enigma.translation.representation.entry.FieldEntry; -import cuchaz.enigma.translation.representation.entry.LocalVariableEntry; -import cuchaz.enigma.translation.representation.entry.MethodEntry; - import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import java.nio.charset.StandardCharsets; +import cuchaz.enigma.translation.mapping.AccessModifier; +import cuchaz.enigma.translation.mapping.EntryChange; +import cuchaz.enigma.translation.representation.MethodDescriptor; +import cuchaz.enigma.translation.representation.TypeDescriptor; +import cuchaz.enigma.translation.representation.entry.*; +import cuchaz.enigma.utils.TristateChange; + public class PacketHelper { private static final int ENTRY_CLASS = 0, ENTRY_FIELD = 1, ENTRY_METHOD = 2, ENTRY_LOCAL_VAR = 3; @@ -37,35 +36,40 @@ public class PacketHelper { } switch (type) { - case ENTRY_CLASS: { - if (parent != null && !(parent instanceof ClassEntry)) { - throw new IOException("Class requires class parent"); + case ENTRY_CLASS: { + if (parent != null && !(parent instanceof ClassEntry)) { + throw new IOException("Class requires class parent"); + } + + return new ClassEntry((ClassEntry) parent, name, javadocs); } - return new ClassEntry((ClassEntry) parent, name, javadocs); - } - case ENTRY_FIELD: { - if (!(parent instanceof ClassEntry)) { - throw new IOException("Field requires class parent"); + case ENTRY_FIELD: { + if (!(parent instanceof ClassEntry parentClass)) { + throw new IOException("Field requires class parent"); + } + + TypeDescriptor desc = new TypeDescriptor(readString(input)); + return new FieldEntry(parentClass, name, desc, javadocs); } - TypeDescriptor desc = new TypeDescriptor(readString(input)); - return new FieldEntry((ClassEntry) parent, name, desc, javadocs); - } - case ENTRY_METHOD: { - if (!(parent instanceof ClassEntry)) { - throw new IOException("Method requires class parent"); + case ENTRY_METHOD: { + if (!(parent instanceof ClassEntry parentClass)) { + throw new IOException("Method requires class parent"); + } + + MethodDescriptor desc = new MethodDescriptor(readString(input)); + return new MethodEntry(parentClass, name, desc, javadocs); } - MethodDescriptor desc = new MethodDescriptor(readString(input)); - return new MethodEntry((ClassEntry) parent, name, desc, javadocs); - } - case ENTRY_LOCAL_VAR: { - if (!(parent instanceof MethodEntry)) { - throw new IOException("Local variable requires method parent"); + case ENTRY_LOCAL_VAR: { + if (!(parent instanceof MethodEntry parentMethod)) { + throw new IOException("Local variable requires method parent"); + } + + int index = input.readUnsignedShort(); + boolean parameter = input.readBoolean(); + return new LocalVariableEntry(parentMethod, index, name, parameter, javadocs); } - int index = input.readUnsignedShort(); - boolean parameter = input.readBoolean(); - return new LocalVariableEntry((MethodEntry) parent, index, name, parameter, javadocs); - } - default: throw new IOException("Received unknown entry type " + type); + default: + throw new IOException("Received unknown entry type " + type); } } @@ -132,4 +136,64 @@ public class PacketHelper { output.write(bytes); } + public static EntryChange readEntryChange(DataInput input) throws IOException { + Entry e = readEntry(input); + EntryChange change = EntryChange.modify(e); + + int flags = input.readUnsignedByte(); + TristateChange.Type deobfNameT = TristateChange.Type.values()[flags & 0x3]; + TristateChange.Type accessT = TristateChange.Type.values()[flags >> 2 & 0x3]; + TristateChange.Type javadocT = TristateChange.Type.values()[flags >> 4 & 0x3]; + + switch (deobfNameT) { + case RESET: + change = change.clearDeobfName(); + break; + case SET: + change = change.withDeobfName(readString(input)); + break; + } + + switch (accessT) { + case RESET: + change = change.clearAccess(); + break; + case SET: + change = change.withAccess(AccessModifier.values()[flags >> 6 & 0x3]); + break; + } + + switch (javadocT) { + case RESET: + change = change.clearJavadoc(); + break; + case SET: + change = change.withJavadoc(readString(input)); + break; + } + + return change; + } + + public static void writeEntryChange(DataOutput output, EntryChange change) throws IOException { + writeEntry(output, change.getTarget()); + int flags = change.getDeobfName().getType().ordinal() | + change.getAccess().getType().ordinal() << 2 | + change.getJavadoc().getType().ordinal() << 4; + + if (change.getAccess().isSet()) { + flags |= change.getAccess().getNewValue().ordinal() << 6; + } + + output.writeByte(flags); + + if (change.getDeobfName().isSet()) { + writeString(output, change.getDeobfName().getNewValue()); + } + + if (change.getJavadoc().isSet()) { + writeString(output, change.getJavadoc().getNewValue()); + } + } + } diff --git a/enigma-server/src/main/java/cuchaz/enigma/network/packet/PacketRegistry.java b/enigma-server/src/main/java/cuchaz/enigma/network/packet/PacketRegistry.java index 3b8af81c..59999ccc 100644 --- a/enigma-server/src/main/java/cuchaz/enigma/network/packet/PacketRegistry.java +++ b/enigma-server/src/main/java/cuchaz/enigma/network/packet/PacketRegistry.java @@ -1,12 +1,12 @@ package cuchaz.enigma.network.packet; -import cuchaz.enigma.network.ClientPacketHandler; -import cuchaz.enigma.network.ServerPacketHandler; - import java.util.HashMap; import java.util.Map; import java.util.function.Supplier; +import cuchaz.enigma.network.ClientPacketHandler; +import cuchaz.enigma.network.ServerPacketHandler; + public class PacketRegistry { private static final Map>, Integer> c2sPacketIds = new HashMap<>(); @@ -27,20 +27,14 @@ public class PacketRegistry { static { registerC2S(0, LoginC2SPacket.class, LoginC2SPacket::new); registerC2S(1, ConfirmChangeC2SPacket.class, ConfirmChangeC2SPacket::new); - registerC2S(2, RenameC2SPacket.class, RenameC2SPacket::new); - registerC2S(3, RemoveMappingC2SPacket.class, RemoveMappingC2SPacket::new); - registerC2S(4, ChangeDocsC2SPacket.class, ChangeDocsC2SPacket::new); - registerC2S(5, MarkDeobfuscatedC2SPacket.class, MarkDeobfuscatedC2SPacket::new); registerC2S(6, MessageC2SPacket.class, MessageC2SPacket::new); + registerC2S(7, EntryChangeC2SPacket.class, EntryChangeC2SPacket::new); registerS2C(0, KickS2CPacket.class, KickS2CPacket::new); registerS2C(1, SyncMappingsS2CPacket.class, SyncMappingsS2CPacket::new); - registerS2C(2, RenameS2CPacket.class, RenameS2CPacket::new); - registerS2C(3, RemoveMappingS2CPacket.class, RemoveMappingS2CPacket::new); - registerS2C(4, ChangeDocsS2CPacket.class, ChangeDocsS2CPacket::new); - registerS2C(5, MarkDeobfuscatedS2CPacket.class, MarkDeobfuscatedS2CPacket::new); registerS2C(6, MessageS2CPacket.class, MessageS2CPacket::new); registerS2C(7, UserListS2CPacket.class, UserListS2CPacket::new); + registerS2C(8, EntryChangeS2CPacket.class, EntryChangeS2CPacket::new); } public static int getC2SId(Packet packet) { diff --git a/enigma-server/src/main/java/cuchaz/enigma/network/packet/RemoveMappingC2SPacket.java b/enigma-server/src/main/java/cuchaz/enigma/network/packet/RemoveMappingC2SPacket.java deleted file mode 100644 index 298e674f..00000000 --- a/enigma-server/src/main/java/cuchaz/enigma/network/packet/RemoveMappingC2SPacket.java +++ /dev/null @@ -1,56 +0,0 @@ -package cuchaz.enigma.network.packet; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -import cuchaz.enigma.network.Message; -import cuchaz.enigma.network.ServerPacketHandler; -import cuchaz.enigma.translation.representation.entry.Entry; -import cuchaz.enigma.utils.validation.PrintValidatable; -import cuchaz.enigma.utils.validation.ValidationContext; - -public class RemoveMappingC2SPacket implements Packet { - private Entry entry; - - RemoveMappingC2SPacket() { - } - - public RemoveMappingC2SPacket(Entry entry) { - this.entry = entry; - } - - @Override - public void read(DataInput input) throws IOException { - this.entry = PacketHelper.readEntry(input); - } - - @Override - public void write(DataOutput output) throws IOException { - PacketHelper.writeEntry(output, entry); - } - - @Override - public void handle(ServerPacketHandler handler) { - ValidationContext vc = new ValidationContext(); - vc.setActiveElement(PrintValidatable.INSTANCE); - - boolean valid = handler.getServer().canModifyEntry(handler.getClient(), entry); - - if (valid) { - handler.getServer().getMappings().removeByObf(vc, entry); - valid = vc.canProceed(); - } - - if (!valid) { - handler.getServer().sendCorrectMapping(handler.getClient(), entry, true); - return; - } - - handler.getServer().log(handler.getServer().getUsername(handler.getClient()) + " removed the mapping for " + entry); - - int syncId = handler.getServer().lockEntry(handler.getClient(), entry); - handler.getServer().sendToAllExcept(handler.getClient(), new RemoveMappingS2CPacket(syncId, entry)); - handler.getServer().sendMessage(Message.removeMapping(handler.getServer().getUsername(handler.getClient()), entry)); - } -} diff --git a/enigma-server/src/main/java/cuchaz/enigma/network/packet/RemoveMappingS2CPacket.java b/enigma-server/src/main/java/cuchaz/enigma/network/packet/RemoveMappingS2CPacket.java deleted file mode 100644 index e336c7b2..00000000 --- a/enigma-server/src/main/java/cuchaz/enigma/network/packet/RemoveMappingS2CPacket.java +++ /dev/null @@ -1,47 +0,0 @@ -package cuchaz.enigma.network.packet; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -import cuchaz.enigma.analysis.EntryReference; -import cuchaz.enigma.network.ClientPacketHandler; -import cuchaz.enigma.translation.representation.entry.Entry; -import cuchaz.enigma.utils.validation.PrintValidatable; -import cuchaz.enigma.utils.validation.ValidationContext; - -public class RemoveMappingS2CPacket implements Packet { - private int syncId; - private Entry entry; - - RemoveMappingS2CPacket() { - } - - public RemoveMappingS2CPacket(int syncId, Entry entry) { - this.syncId = syncId; - this.entry = entry; - } - - @Override - public void read(DataInput input) throws IOException { - this.syncId = input.readUnsignedShort(); - this.entry = PacketHelper.readEntry(input); - } - - @Override - public void write(DataOutput output) throws IOException { - output.writeShort(syncId); - PacketHelper.writeEntry(output, entry); - } - - @Override - public void handle(ClientPacketHandler controller) { - ValidationContext vc = new ValidationContext(); - vc.setActiveElement(PrintValidatable.INSTANCE); - - controller.removeMapping(vc, new EntryReference<>(entry, entry.getName())); - - if (!vc.canProceed()) return; - controller.sendPacket(new ConfirmChangeC2SPacket(syncId)); - } -} diff --git a/enigma-server/src/main/java/cuchaz/enigma/network/packet/RenameC2SPacket.java b/enigma-server/src/main/java/cuchaz/enigma/network/packet/RenameC2SPacket.java deleted file mode 100644 index 694d4321..00000000 --- a/enigma-server/src/main/java/cuchaz/enigma/network/packet/RenameC2SPacket.java +++ /dev/null @@ -1,66 +0,0 @@ -package cuchaz.enigma.network.packet; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -import cuchaz.enigma.network.Message; -import cuchaz.enigma.network.ServerPacketHandler; -import cuchaz.enigma.translation.mapping.EntryMapping; -import cuchaz.enigma.translation.representation.entry.Entry; -import cuchaz.enigma.utils.validation.PrintValidatable; -import cuchaz.enigma.utils.validation.ValidationContext; - -public class RenameC2SPacket implements Packet { - private Entry entry; - private String newName; - private boolean refreshClassTree; - - RenameC2SPacket() { - } - - public RenameC2SPacket(Entry entry, String newName, boolean refreshClassTree) { - this.entry = entry; - this.newName = newName; - this.refreshClassTree = refreshClassTree; - } - - @Override - public void read(DataInput input) throws IOException { - this.entry = PacketHelper.readEntry(input); - this.newName = PacketHelper.readString(input); - this.refreshClassTree = input.readBoolean(); - } - - @Override - public void write(DataOutput output) throws IOException { - PacketHelper.writeEntry(output, entry); - PacketHelper.writeString(output, newName); - output.writeBoolean(refreshClassTree); - } - - @Override - public void handle(ServerPacketHandler handler) { - ValidationContext vc = new ValidationContext(); - vc.setActiveElement(PrintValidatable.INSTANCE); - - boolean valid = handler.getServer().canModifyEntry(handler.getClient(), entry); - - if (valid) { - EntryMapping previous = handler.getServer().getMappings().getDeobfMapping(entry); - handler.getServer().getMappings().mapFromObf(vc, entry, previous != null ? previous.withName(newName) : new EntryMapping(newName)); - valid = vc.canProceed(); - } - - if (!valid) { - handler.getServer().sendCorrectMapping(handler.getClient(), entry, refreshClassTree); - return; - } - - handler.getServer().log(handler.getServer().getUsername(handler.getClient()) + " renamed " + entry + " to " + newName); - - int syncId = handler.getServer().lockEntry(handler.getClient(), entry); - handler.getServer().sendToAllExcept(handler.getClient(), new RenameS2CPacket(syncId, entry, newName, refreshClassTree)); - handler.getServer().sendMessage(Message.rename(handler.getServer().getUsername(handler.getClient()), entry, newName)); - } -} diff --git a/enigma-server/src/main/java/cuchaz/enigma/network/packet/RenameS2CPacket.java b/enigma-server/src/main/java/cuchaz/enigma/network/packet/RenameS2CPacket.java deleted file mode 100644 index fdf06540..00000000 --- a/enigma-server/src/main/java/cuchaz/enigma/network/packet/RenameS2CPacket.java +++ /dev/null @@ -1,55 +0,0 @@ -package cuchaz.enigma.network.packet; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -import cuchaz.enigma.analysis.EntryReference; -import cuchaz.enigma.network.ClientPacketHandler; -import cuchaz.enigma.translation.representation.entry.Entry; -import cuchaz.enigma.utils.validation.PrintValidatable; -import cuchaz.enigma.utils.validation.ValidationContext; - -public class RenameS2CPacket implements Packet { - private int syncId; - private Entry entry; - private String newName; - private boolean refreshClassTree; - - RenameS2CPacket() { - } - - public RenameS2CPacket(int syncId, Entry entry, String newName, boolean refreshClassTree) { - this.syncId = syncId; - this.entry = entry; - this.newName = newName; - this.refreshClassTree = refreshClassTree; - } - - @Override - public void read(DataInput input) throws IOException { - this.syncId = input.readUnsignedShort(); - this.entry = PacketHelper.readEntry(input); - this.newName = PacketHelper.readString(input); - this.refreshClassTree = input.readBoolean(); - } - - @Override - public void write(DataOutput output) throws IOException { - output.writeShort(syncId); - PacketHelper.writeEntry(output, entry); - PacketHelper.writeString(output, newName); - output.writeBoolean(refreshClassTree); - } - - @Override - public void handle(ClientPacketHandler controller) { - ValidationContext vc = new ValidationContext(); - vc.setActiveElement(PrintValidatable.INSTANCE); - - controller.rename(vc, new EntryReference<>(entry, entry.getName()), newName, refreshClassTree); - - if (!vc.canProceed()) return; - controller.sendPacket(new ConfirmChangeC2SPacket(syncId)); - } -} diff --git a/enigma-server/src/main/java/cuchaz/enigma/network/packet/SyncMappingsS2CPacket.java b/enigma-server/src/main/java/cuchaz/enigma/network/packet/SyncMappingsS2CPacket.java index 92a78748..6d9c0bcb 100644 --- a/enigma-server/src/main/java/cuchaz/enigma/network/packet/SyncMappingsS2CPacket.java +++ b/enigma-server/src/main/java/cuchaz/enigma/network/packet/SyncMappingsS2CPacket.java @@ -1,19 +1,19 @@ package cuchaz.enigma.network.packet; -import cuchaz.enigma.translation.mapping.EntryMapping; -import cuchaz.enigma.translation.mapping.tree.EntryTree; -import cuchaz.enigma.translation.mapping.tree.EntryTreeNode; -import cuchaz.enigma.translation.mapping.tree.HashEntryTree; -import cuchaz.enigma.network.ClientPacketHandler; -import cuchaz.enigma.network.EnigmaServer; -import cuchaz.enigma.translation.representation.entry.Entry; - import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import java.util.Collection; import java.util.List; +import cuchaz.enigma.network.ClientPacketHandler; +import cuchaz.enigma.network.EnigmaServer; +import cuchaz.enigma.translation.mapping.EntryMapping; +import cuchaz.enigma.translation.mapping.tree.EntryTree; +import cuchaz.enigma.translation.mapping.tree.EntryTreeNode; +import cuchaz.enigma.translation.mapping.tree.HashEntryTree; +import cuchaz.enigma.translation.representation.entry.Entry; + public class SyncMappingsS2CPacket implements Packet { private EntryTree mappings; @@ -35,16 +35,9 @@ public class SyncMappingsS2CPacket implements Packet { private void readEntryTreeNode(DataInput input, Entry parent) throws IOException { Entry entry = PacketHelper.readEntry(input, parent, false); - EntryMapping mapping = null; - if (input.readBoolean()) { - String name = input.readUTF(); - if (input.readBoolean()) { - String javadoc = input.readUTF(); - mapping = new EntryMapping(name, javadoc); - } else { - mapping = new EntryMapping(name); - } - } + String name = PacketHelper.readString(input); + String javadoc = PacketHelper.readString(input); + EntryMapping mapping = new EntryMapping(!name.isEmpty() ? name : null, !javadoc.isEmpty() ? javadoc : null); mappings.insert(entry, mapping); int size = input.readUnsignedShort(); for (int i = 0; i < size; i++) { @@ -64,14 +57,10 @@ public class SyncMappingsS2CPacket implements Packet { private static void writeEntryTreeNode(DataOutput output, EntryTreeNode node) throws IOException { PacketHelper.writeEntry(output, node.getEntry(), false); EntryMapping value = node.getValue(); - output.writeBoolean(value != null); - if (value != null) { - PacketHelper.writeString(output, value.getTargetName()); - output.writeBoolean(value.getJavadoc() != null); - if (value.getJavadoc() != null) { - PacketHelper.writeString(output, value.getJavadoc()); - } - } + if (value == null) value = EntryMapping.DEFAULT; + + PacketHelper.writeString(output, value.targetName() != null ? value.targetName() : ""); + PacketHelper.writeString(output, value.javadoc() != null ? value.javadoc() : ""); Collection> children = node.getChildNodes(); output.writeShort(children.size()); for (EntryTreeNode child : children) { -- cgit v1.2.3