diff options
53 files changed, 872 insertions, 1000 deletions
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 { | |||
| 75 | The IDs for client-to-server packets are as follows: | 75 | The IDs for client-to-server packets are as follows: |
| 76 | - 0: `Login` | 76 | - 0: `Login` |
| 77 | - 1: `ConfirmChange` | 77 | - 1: `ConfirmChange` |
| 78 | - 2: `Rename` | ||
| 79 | - 3: `RemoveMapping` | ||
| 80 | - 4: `ChangeDocs` | ||
| 81 | - 5: `MarkDeobfuscated` | ||
| 82 | - 6: `Message` | 78 | - 6: `Message` |
| 79 | - 7: `EntryChange` | ||
| 83 | 80 | ||
| 84 | The IDs for server-to-client packets are as follows: | 81 | The IDs for server-to-client packets are as follows: |
| 85 | - 0: `Kick` | 82 | - 0: `Kick` |
| 86 | - 1: `SyncMappings` | 83 | - 1: `SyncMappings` |
| 87 | - 2: `Rename` | ||
| 88 | - 3: `RemoveMapping` | ||
| 89 | - 4: `ChangeDocs` | ||
| 90 | - 5: `MarkDeobfuscated` | ||
| 91 | - 6: `Message` | 84 | - 6: `Message` |
| 92 | - 7: `UserList` | 85 | - 7: `UserList` |
| 86 | - 8: `EntryChange` | ||
| 93 | 87 | ||
| 94 | ### The utf struct | 88 | ### The utf struct |
| 95 | ```c | 89 | ```c |
| @@ -196,6 +190,45 @@ struct Message { | |||
| 196 | - `entry`: The entry that was modified. | 190 | - `entry`: The entry that was modified. |
| 197 | - `new_name`: The new name for the entry. | 191 | - `new_name`: The new name for the entry. |
| 198 | 192 | ||
| 193 | ### The entry_change struct | ||
| 194 | ```c | ||
| 195 | typedef enum tristate_change { | ||
| 196 | TRISTATE_CHANGE_UNCHANGED = 0, | ||
| 197 | TRISTATE_CHANGE_RESET = 1, | ||
| 198 | TRISTATE_CHANGE_SET = 2 | ||
| 199 | } tristate_change_t; | ||
| 200 | |||
| 201 | typedef enum access_modifier { | ||
| 202 | ACCESS_MODIFIER_UNCHANGED = 0, | ||
| 203 | ACCESS_MODIFIER_PUBLIC = 1, | ||
| 204 | ACCESS_MODIFIER_PROTECTED = 2, | ||
| 205 | ACCESS_MODIFIER_PRIVATE = 3 | ||
| 206 | } access_modifier_t; | ||
| 207 | |||
| 208 | // Contains 4 packed values: | ||
| 209 | // bitmask type | ||
| 210 | // 00000011 tristate_change_t deobf_name_change; | ||
| 211 | // 00001100 tristate_change_t access_change; | ||
| 212 | // 00110000 tristate_change_t javadoc_change; | ||
| 213 | // 11000000 access_modifier_t access_modifiers; | ||
| 214 | typedef uint8_t entry_change_flags; | ||
| 215 | |||
| 216 | struct entry_change { | ||
| 217 | Entry entry; | ||
| 218 | entry_change_flags flags; | ||
| 219 | if <deobf_name_change == TRISTATE_CHANGE_SET> { | ||
| 220 | utf deobf_name; | ||
| 221 | } | ||
| 222 | if <javadoc_change == TRISTATE_CHANGE_SET> { | ||
| 223 | utf javadoc; | ||
| 224 | } | ||
| 225 | } | ||
| 226 | ``` | ||
| 227 | - `entry`: The entry this change gets applied to. | ||
| 228 | - `flags`: See definition of `entry_change_flags`. | ||
| 229 | - `deobf_name`: The new deobfuscated name, if deobf_name_change == TRISTATE_CHANGE_SET | ||
| 230 | - `javadoc`: The new javadoc, if javadoc_change == TRISTATE_CHANGE_SET | ||
| 231 | - `access_modifiers`: The new access modifier, if access_change == TRISTATE_CHANGE_SET (otherwise 0) | ||
| 199 | 232 | ||
| 200 | ### Login (client-to-server) | 233 | ### Login (client-to-server) |
| 201 | ```c | 234 | ```c |
| @@ -223,44 +256,6 @@ struct ConfirmChangeC2SPacket { | |||
| 223 | ``` | 256 | ``` |
| 224 | - `sync_id`: the sync ID to confirm. | 257 | - `sync_id`: the sync ID to confirm. |
| 225 | 258 | ||
| 226 | ### Rename (client-to-server) | ||
| 227 | ```c | ||
| 228 | struct RenameC2SPacket { | ||
| 229 | Entry obf_entry; | ||
| 230 | utf new_name; | ||
| 231 | boolean refresh_class_tree; | ||
| 232 | } | ||
| 233 | ``` | ||
| 234 | - `obf_entry`: the obfuscated name and descriptor of the entry to rename. | ||
| 235 | - `new_name`: what to rename the entry to. | ||
| 236 | - `refresh_class_tree`: whether the class tree on the sidebar of Enigma needs refreshing as a result of this change. | ||
| 237 | |||
| 238 | ### RemoveMapping (client-to-server) | ||
| 239 | ```c | ||
| 240 | struct RemoveMappingC2SPacket { | ||
| 241 | Entry obf_entry; | ||
| 242 | } | ||
| 243 | ``` | ||
| 244 | - `obf_entry`: the obfuscated name and descriptor of the entry to remove the mapping for. | ||
| 245 | |||
| 246 | ### ChangeDocs (client-to-server) | ||
| 247 | ```c | ||
| 248 | struct ChangeDocsC2SPacket { | ||
| 249 | Entry obf_entry; | ||
| 250 | utf new_docs; | ||
| 251 | } | ||
| 252 | ``` | ||
| 253 | - `obf_entry`: the obfuscated name and descriptor of the entry to change the documentation for. | ||
| 254 | - `new_docs`: the new documentation for this entry, or an empty string to remove the documentation. | ||
| 255 | |||
| 256 | ### MarkDeobfuscated (client-to-server) | ||
| 257 | ```c | ||
| 258 | struct MarkDeobfuscatedC2SPacket { | ||
| 259 | Entry obf_entry; | ||
| 260 | } | ||
| 261 | ``` | ||
| 262 | - `obf_entry`: the obfuscated name and descriptor of the entry to mark as deobfuscated. | ||
| 263 | |||
| 264 | ### Message (client-to-server) | 259 | ### Message (client-to-server) |
| 265 | ```c | 260 | ```c |
| 266 | struct MessageC2SPacket { | 261 | struct MessageC2SPacket { |
| @@ -269,6 +264,14 @@ struct MessageC2SPacket { | |||
| 269 | ``` | 264 | ``` |
| 270 | - `message`: The text message the user sent. | 265 | - `message`: The text message the user sent. |
| 271 | 266 | ||
| 267 | ### EntryChange (client-to-server) | ||
| 268 | ```c | ||
| 269 | struct EntryChangeC2SPacket { | ||
| 270 | entry_change change; | ||
| 271 | } | ||
| 272 | ``` | ||
| 273 | - `change`: The change to apply. | ||
| 274 | |||
| 272 | ### Kick (server-to-client) | 275 | ### Kick (server-to-client) |
| 273 | ```c | 276 | ```c |
| 274 | struct KickS2CPacket { | 277 | struct KickS2CPacket { |
| @@ -286,13 +289,8 @@ struct SyncMappingsS2CPacket { | |||
| 286 | struct MappingNode { | 289 | struct MappingNode { |
| 287 | NoParentEntry obf_entry; | 290 | NoParentEntry obf_entry; |
| 288 | boolean is_named; | 291 | boolean is_named; |
| 289 | if<is_named> { | 292 | utf name; |
| 290 | utf name; | 293 | utf javadoc; |
| 291 | boolean has_javadoc; | ||
| 292 | if<has_javadoc> { | ||
| 293 | utf javadoc; | ||
| 294 | } | ||
| 295 | } | ||
| 296 | unsigned short children_count; | 294 | unsigned short children_count; |
| 297 | MappingNode children[children_count]; | 295 | MappingNode children[children_count]; |
| 298 | } | 296 | } |
| @@ -300,56 +298,10 @@ typedef { Entry but without the has_parent or parent fields } NoParentEntry; | |||
| 300 | ``` | 298 | ``` |
| 301 | - `roots`: The root mapping nodes, containing all the entries without parents. | 299 | - `roots`: The root mapping nodes, containing all the entries without parents. |
| 302 | - `obf_entry`: The value of a node, containing the obfuscated name and descriptor of the entry. | 300 | - `obf_entry`: The value of a node, containing the obfuscated name and descriptor of the entry. |
| 303 | - `name`: The deobfuscated name of the entry, if it has a mapping. | 301 | - `name`: The deobfuscated name of the entry, if it exists, otherwise the empty string. |
| 304 | - `javadoc`: The documentation for the entry, if it is named and has documentation. | 302 | - `javadoc`: The documentation for the entry, if it exists, otherwise the empty string. |
| 305 | - `children`: The children of this node | 303 | - `children`: The children of this node |
| 306 | 304 | ||
| 307 | ### Rename (server-to-client) | ||
| 308 | ```c | ||
| 309 | struct RenameS2CPacket { | ||
| 310 | unsigned short sync_id; | ||
| 311 | Entry obf_entry; | ||
| 312 | utf new_name; | ||
| 313 | boolean refresh_class_tree; | ||
| 314 | } | ||
| 315 | ``` | ||
| 316 | - `sync_id`: the sync ID of the change for locking purposes. | ||
| 317 | - `obf_entry`: the obfuscated name and descriptor of the entry to rename. | ||
| 318 | - `new_name`: what to rename the entry to. | ||
| 319 | - `refresh_class_tree`: whether the class tree on the sidebar of Enigma needs refreshing as a result of this change. | ||
| 320 | |||
| 321 | ### RemoveMapping (server-to-client) | ||
| 322 | ```c | ||
| 323 | struct RemoveMappingS2CPacket { | ||
| 324 | unsigned short sync_id; | ||
| 325 | Entry obf_entry; | ||
| 326 | } | ||
| 327 | ``` | ||
| 328 | - `sync_id`: the sync ID of the change for locking purposes. | ||
| 329 | - `obf_entry`: the obfuscated name and descriptor of the entry to remove the mapping for. | ||
| 330 | |||
| 331 | ### ChangeDocs (server-to-client) | ||
| 332 | ```c | ||
| 333 | struct ChangeDocsS2CPacket { | ||
| 334 | unsigned short sync_id; | ||
| 335 | Entry obf_entry; | ||
| 336 | utf new_docs; | ||
| 337 | } | ||
| 338 | ``` | ||
| 339 | - `sync_id`: the sync ID of the change for locking purposes. | ||
| 340 | - `obf_entry`: the obfuscated name and descriptor of the entry to change the documentation for. | ||
| 341 | - `new_docs`: the new documentation for this entry, or an empty string to remove the documentation. | ||
| 342 | |||
| 343 | ### MarkDeobfuscated (server-to-client) | ||
| 344 | ```c | ||
| 345 | struct MarkDeobfuscatedS2CPacket { | ||
| 346 | unsigned short sync_id; | ||
| 347 | Entry obf_entry; | ||
| 348 | } | ||
| 349 | ``` | ||
| 350 | - `sync_id`: the sync ID of the change for locking purposes. | ||
| 351 | - `obf_entry`: the obfuscated name and descriptor of the entry to mark as deobfuscated. | ||
| 352 | |||
| 353 | ### Message (server-to-client) | 305 | ### Message (server-to-client) |
| 354 | ```c | 306 | ```c |
| 355 | struct MessageS2CPacket { | 307 | struct MessageS2CPacket { |
| @@ -364,3 +316,13 @@ struct UserListS2CPacket { | |||
| 364 | utf user[len]; | 316 | utf user[len]; |
| 365 | } | 317 | } |
| 366 | ``` | 318 | ``` |
| 319 | |||
| 320 | ### EntryChange (server-to-client) | ||
| 321 | ```c | ||
| 322 | struct EntryChangeS2CPacket { | ||
| 323 | uint16_t sync_id; | ||
| 324 | entry_change change; | ||
| 325 | } | ||
| 326 | ``` | ||
| 327 | - `sync_id`: The sync ID of the change for locking purposes. | ||
| 328 | - `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 @@ | |||
| 1 | package cuchaz.enigma.network; | 1 | package cuchaz.enigma.network; |
| 2 | 2 | ||
| 3 | import cuchaz.enigma.analysis.EntryReference; | 3 | import cuchaz.enigma.translation.mapping.EntryChange; |
| 4 | import cuchaz.enigma.translation.mapping.EntryMapping; | 4 | import cuchaz.enigma.translation.mapping.EntryMapping; |
| 5 | import cuchaz.enigma.translation.mapping.tree.EntryTree; | 5 | import cuchaz.enigma.translation.mapping.tree.EntryTree; |
| 6 | import cuchaz.enigma.network.packet.Packet; | 6 | import cuchaz.enigma.network.packet.Packet; |
| 7 | import cuchaz.enigma.translation.representation.entry.Entry; | ||
| 8 | import cuchaz.enigma.utils.validation.ValidationContext; | ||
| 9 | 7 | ||
| 10 | import java.util.List; | 8 | import java.util.List; |
| 11 | 9 | ||
| 12 | public interface ClientPacketHandler { | 10 | public interface ClientPacketHandler { |
| 13 | void openMappings(EntryTree<EntryMapping> mappings); | 11 | void openMappings(EntryTree<EntryMapping> mappings); |
| 14 | 12 | ||
| 15 | void rename(ValidationContext vc, EntryReference<Entry<?>, Entry<?>> reference, String newName, boolean refreshClassTree); | 13 | boolean applyChangeFromServer(EntryChange<?> change); |
| 16 | |||
| 17 | void removeMapping(ValidationContext vc, EntryReference<Entry<?>, Entry<?>> reference); | ||
| 18 | |||
| 19 | void changeDocs(ValidationContext vc, EntryReference<Entry<?>, Entry<?>> reference, String updatedDocs); | ||
| 20 | |||
| 21 | void markAsDeobfuscated(ValidationContext vc, EntryReference<Entry<?>, Entry<?>> reference); | ||
| 22 | 14 | ||
| 23 | void disconnectIfConnected(String reason); | 15 | void disconnectIfConnected(String reason); |
| 24 | 16 | ||
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.*; | |||
| 8 | import java.util.concurrent.CopyOnWriteArrayList; | 8 | import java.util.concurrent.CopyOnWriteArrayList; |
| 9 | 9 | ||
| 10 | import cuchaz.enigma.network.packet.*; | 10 | import cuchaz.enigma.network.packet.*; |
| 11 | import cuchaz.enigma.translation.mapping.EntryChange; | ||
| 11 | import cuchaz.enigma.translation.mapping.EntryMapping; | 12 | import cuchaz.enigma.translation.mapping.EntryMapping; |
| 12 | import cuchaz.enigma.translation.mapping.EntryRemapper; | 13 | import cuchaz.enigma.translation.mapping.EntryRemapper; |
| 13 | import cuchaz.enigma.translation.representation.entry.Entry; | 14 | import cuchaz.enigma.translation.representation.entry.Entry; |
| @@ -16,7 +17,7 @@ public abstract class EnigmaServer { | |||
| 16 | 17 | ||
| 17 | // https://discordapp.com/channels/507304429255393322/566418023372816394/700292322918793347 | 18 | // https://discordapp.com/channels/507304429255393322/566418023372816394/700292322918793347 |
| 18 | public static final int DEFAULT_PORT = 34712; | 19 | public static final int DEFAULT_PORT = 34712; |
| 19 | public static final int PROTOCOL_VERSION = 0; | 20 | public static final int PROTOCOL_VERSION = 1; |
| 20 | public static final int CHECKSUM_SIZE = 20; | 21 | public static final int CHECKSUM_SIZE = 20; |
| 21 | public static final int MAX_PASSWORD_LENGTH = 255; // length is written as a byte in the login packet | 22 | public static final int MAX_PASSWORD_LENGTH = 255; // length is written as a byte in the login packet |
| 22 | 23 | ||
| @@ -234,11 +235,11 @@ public abstract class EnigmaServer { | |||
| 234 | 235 | ||
| 235 | public void sendCorrectMapping(Socket client, Entry<?> entry, boolean refreshClassTree) { | 236 | public void sendCorrectMapping(Socket client, Entry<?> entry, boolean refreshClassTree) { |
| 236 | EntryMapping oldMapping = mappings.getDeobfMapping(entry); | 237 | EntryMapping oldMapping = mappings.getDeobfMapping(entry); |
| 237 | String oldName = oldMapping == null ? null : oldMapping.getTargetName(); | 238 | String oldName = oldMapping.targetName(); |
| 238 | if (oldName == null) { | 239 | if (oldName == null) { |
| 239 | sendPacket(client, new RemoveMappingS2CPacket(DUMMY_SYNC_ID, entry)); | 240 | sendPacket(client, new EntryChangeS2CPacket(DUMMY_SYNC_ID, EntryChange.modify(entry).clearDeobfName())); |
| 240 | } else { | 241 | } else { |
| 241 | sendPacket(client, new RenameS2CPacket(0, entry, oldName, refreshClassTree)); | 242 | sendPacket(client, new EntryChangeS2CPacket(0, EntryChange.modify(entry).withDeobfName(oldName))); |
| 242 | } | 243 | } |
| 243 | } | 244 | } |
| 244 | 245 | ||
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 @@ | |||
| 1 | package cuchaz.enigma.network.packet; | ||
| 2 | |||
| 3 | import java.io.DataInput; | ||
| 4 | import java.io.DataOutput; | ||
| 5 | import java.io.IOException; | ||
| 6 | |||
| 7 | import cuchaz.enigma.translation.mapping.EntryMapping; | ||
| 8 | import cuchaz.enigma.network.EnigmaServer; | ||
| 9 | import cuchaz.enigma.network.Message; | ||
| 10 | import cuchaz.enigma.network.ServerPacketHandler; | ||
| 11 | import cuchaz.enigma.translation.representation.entry.Entry; | ||
| 12 | import cuchaz.enigma.utils.validation.PrintValidatable; | ||
| 13 | import cuchaz.enigma.utils.validation.ValidationContext; | ||
| 14 | |||
| 15 | public class ChangeDocsC2SPacket implements Packet<ServerPacketHandler> { | ||
| 16 | private Entry<?> entry; | ||
| 17 | private String newDocs; | ||
| 18 | |||
| 19 | ChangeDocsC2SPacket() { | ||
| 20 | } | ||
| 21 | |||
| 22 | public ChangeDocsC2SPacket(Entry<?> entry, String newDocs) { | ||
| 23 | this.entry = entry; | ||
| 24 | this.newDocs = newDocs; | ||
| 25 | } | ||
| 26 | |||
| 27 | @Override | ||
| 28 | public void read(DataInput input) throws IOException { | ||
| 29 | this.entry = PacketHelper.readEntry(input); | ||
| 30 | this.newDocs = PacketHelper.readString(input); | ||
| 31 | } | ||
| 32 | |||
| 33 | @Override | ||
| 34 | public void write(DataOutput output) throws IOException { | ||
| 35 | PacketHelper.writeEntry(output, entry); | ||
| 36 | PacketHelper.writeString(output, newDocs); | ||
| 37 | } | ||
| 38 | |||
| 39 | @Override | ||
| 40 | public void handle(ServerPacketHandler handler) { | ||
| 41 | ValidationContext vc = new ValidationContext(); | ||
| 42 | vc.setActiveElement(PrintValidatable.INSTANCE); | ||
| 43 | |||
| 44 | EntryMapping mapping = handler.getServer().getMappings().getDeobfMapping(entry); | ||
| 45 | |||
| 46 | boolean valid = handler.getServer().canModifyEntry(handler.getClient(), entry); | ||
| 47 | if (!valid) { | ||
| 48 | String oldDocs = mapping == null ? null : mapping.getJavadoc(); | ||
| 49 | handler.getServer().sendPacket(handler.getClient(), new ChangeDocsS2CPacket(EnigmaServer.DUMMY_SYNC_ID, entry, oldDocs == null ? "" : oldDocs)); | ||
| 50 | return; | ||
| 51 | } | ||
| 52 | |||
| 53 | if (mapping == null) { | ||
| 54 | mapping = new EntryMapping(handler.getServer().getMappings().deobfuscate(entry).getName()); | ||
| 55 | } | ||
| 56 | handler.getServer().getMappings().mapFromObf(vc, entry, mapping.withDocs(newDocs.isBlank() ? null : newDocs)); | ||
| 57 | |||
| 58 | if (!vc.canProceed()) return; | ||
| 59 | |||
| 60 | int syncId = handler.getServer().lockEntry(handler.getClient(), entry); | ||
| 61 | handler.getServer().sendToAllExcept(handler.getClient(), new ChangeDocsS2CPacket(syncId, entry, newDocs)); | ||
| 62 | handler.getServer().sendMessage(Message.editDocs(handler.getServer().getUsername(handler.getClient()), entry)); | ||
| 63 | } | ||
| 64 | } | ||
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 @@ | |||
| 1 | package cuchaz.enigma.network.packet; | ||
| 2 | |||
| 3 | import java.io.DataInput; | ||
| 4 | import java.io.DataOutput; | ||
| 5 | import java.io.IOException; | ||
| 6 | |||
| 7 | import cuchaz.enigma.analysis.EntryReference; | ||
| 8 | import cuchaz.enigma.network.ClientPacketHandler; | ||
| 9 | import cuchaz.enigma.translation.representation.entry.Entry; | ||
| 10 | import cuchaz.enigma.utils.validation.PrintValidatable; | ||
| 11 | import cuchaz.enigma.utils.validation.ValidationContext; | ||
| 12 | |||
| 13 | public class ChangeDocsS2CPacket implements Packet<ClientPacketHandler> { | ||
| 14 | private int syncId; | ||
| 15 | private Entry<?> entry; | ||
| 16 | private String newDocs; | ||
| 17 | |||
| 18 | ChangeDocsS2CPacket() { | ||
| 19 | } | ||
| 20 | |||
| 21 | public ChangeDocsS2CPacket(int syncId, Entry<?> entry, String newDocs) { | ||
| 22 | this.syncId = syncId; | ||
| 23 | this.entry = entry; | ||
| 24 | this.newDocs = newDocs; | ||
| 25 | } | ||
| 26 | |||
| 27 | @Override | ||
| 28 | public void read(DataInput input) throws IOException { | ||
| 29 | this.syncId = input.readUnsignedShort(); | ||
| 30 | this.entry = PacketHelper.readEntry(input); | ||
| 31 | this.newDocs = PacketHelper.readString(input); | ||
| 32 | } | ||
| 33 | |||
| 34 | @Override | ||
| 35 | public void write(DataOutput output) throws IOException { | ||
| 36 | output.writeShort(syncId); | ||
| 37 | PacketHelper.writeEntry(output, entry); | ||
| 38 | PacketHelper.writeString(output, newDocs); | ||
| 39 | } | ||
| 40 | |||
| 41 | @Override | ||
| 42 | public void handle(ClientPacketHandler controller) { | ||
| 43 | ValidationContext vc = new ValidationContext(); | ||
| 44 | vc.setActiveElement(PrintValidatable.INSTANCE); | ||
| 45 | |||
| 46 | controller.changeDocs(vc, new EntryReference<>(entry, entry.getName()), newDocs); | ||
| 47 | |||
| 48 | if (!vc.canProceed()) return; | ||
| 49 | controller.sendPacket(new ConfirmChangeC2SPacket(syncId)); | ||
| 50 | } | ||
| 51 | } | ||
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 @@ | |||
| 1 | package cuchaz.enigma.network.packet; | ||
| 2 | |||
| 3 | import java.io.DataInput; | ||
| 4 | import java.io.DataOutput; | ||
| 5 | import java.io.IOException; | ||
| 6 | |||
| 7 | import cuchaz.enigma.network.Message; | ||
| 8 | import cuchaz.enigma.network.ServerPacketHandler; | ||
| 9 | import cuchaz.enigma.translation.mapping.EntryChange; | ||
| 10 | import cuchaz.enigma.translation.mapping.EntryUtil; | ||
| 11 | import cuchaz.enigma.utils.validation.PrintValidatable; | ||
| 12 | import cuchaz.enigma.utils.validation.ValidationContext; | ||
| 13 | |||
| 14 | public class EntryChangeC2SPacket implements Packet<ServerPacketHandler> { | ||
| 15 | |||
| 16 | private EntryChange<?> change; | ||
| 17 | |||
| 18 | EntryChangeC2SPacket() { | ||
| 19 | } | ||
| 20 | |||
| 21 | public EntryChangeC2SPacket(EntryChange<?> change) { | ||
| 22 | this.change = change; | ||
| 23 | } | ||
| 24 | |||
| 25 | @Override | ||
| 26 | public void read(DataInput input) throws IOException { | ||
| 27 | this.change = PacketHelper.readEntryChange(input); | ||
| 28 | } | ||
| 29 | |||
| 30 | @Override | ||
| 31 | public void write(DataOutput output) throws IOException { | ||
| 32 | PacketHelper.writeEntryChange(output, change); | ||
| 33 | } | ||
| 34 | |||
| 35 | @Override | ||
| 36 | public void handle(ServerPacketHandler handler) { | ||
| 37 | ValidationContext vc = new ValidationContext(); | ||
| 38 | vc.setActiveElement(PrintValidatable.INSTANCE); | ||
| 39 | |||
| 40 | boolean valid = handler.getServer().canModifyEntry(handler.getClient(), this.change.getTarget()); | ||
| 41 | |||
| 42 | if (valid) { | ||
| 43 | EntryUtil.applyChange(vc, handler.getServer().getMappings(), this.change); | ||
| 44 | valid = vc.canProceed(); | ||
| 45 | } | ||
| 46 | |||
| 47 | if (!valid) { | ||
| 48 | handler.getServer().sendCorrectMapping(handler.getClient(), this.change.getTarget(), true); | ||
| 49 | return; | ||
| 50 | } | ||
| 51 | |||
| 52 | int syncId = handler.getServer().lockEntry(handler.getClient(), this.change.getTarget()); | ||
| 53 | handler.getServer().sendToAllExcept(handler.getClient(), new EntryChangeS2CPacket(syncId, this.change)); | ||
| 54 | |||
| 55 | if (this.change.getDeobfName().isSet()) { | ||
| 56 | handler.getServer().sendMessage(Message.rename(handler.getServer().getUsername(handler.getClient()), this.change.getTarget(), this.change.getDeobfName().getNewValue())); | ||
| 57 | } else if (this.change.getDeobfName().isReset()) { | ||
| 58 | handler.getServer().sendMessage(Message.removeMapping(handler.getServer().getUsername(handler.getClient()), this.change.getTarget())); | ||
| 59 | } | ||
| 60 | |||
| 61 | if (!this.change.getJavadoc().isUnchanged()) { | ||
| 62 | handler.getServer().sendMessage(Message.editDocs(handler.getServer().getUsername(handler.getClient()), this.change.getTarget())); | ||
| 63 | } | ||
| 64 | } | ||
| 65 | |||
| 66 | } | ||
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 @@ | |||
| 1 | package cuchaz.enigma.network.packet; | ||
| 2 | |||
| 3 | import java.io.DataInput; | ||
| 4 | import java.io.DataOutput; | ||
| 5 | import java.io.IOException; | ||
| 6 | |||
| 7 | import cuchaz.enigma.network.ClientPacketHandler; | ||
| 8 | import cuchaz.enigma.translation.mapping.EntryChange; | ||
| 9 | |||
| 10 | public class EntryChangeS2CPacket implements Packet<ClientPacketHandler> { | ||
| 11 | |||
| 12 | private int syncId; | ||
| 13 | private EntryChange<?> change; | ||
| 14 | |||
| 15 | public EntryChangeS2CPacket(int syncId, EntryChange<?> change) { | ||
| 16 | this.syncId = syncId; | ||
| 17 | this.change = change; | ||
| 18 | } | ||
| 19 | |||
| 20 | EntryChangeS2CPacket() { | ||
| 21 | } | ||
| 22 | |||
| 23 | @Override | ||
| 24 | public void read(DataInput input) throws IOException { | ||
| 25 | this.syncId = input.readUnsignedShort(); | ||
| 26 | this.change = PacketHelper.readEntryChange(input); | ||
| 27 | } | ||
| 28 | |||
| 29 | @Override | ||
| 30 | public void write(DataOutput output) throws IOException { | ||
| 31 | output.writeShort(this.syncId); | ||
| 32 | PacketHelper.writeEntryChange(output, this.change); | ||
| 33 | } | ||
| 34 | |||
| 35 | @Override | ||
| 36 | public void handle(ClientPacketHandler handler) { | ||
| 37 | if (handler.applyChangeFromServer(this.change)) { | ||
| 38 | handler.sendPacket(new ConfirmChangeC2SPacket(this.syncId)); | ||
| 39 | } | ||
| 40 | } | ||
| 41 | |||
| 42 | } | ||
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 @@ | |||
| 1 | package cuchaz.enigma.network.packet; | ||
| 2 | |||
| 3 | import java.io.DataInput; | ||
| 4 | import java.io.DataOutput; | ||
| 5 | import java.io.IOException; | ||
| 6 | |||
| 7 | import cuchaz.enigma.network.Message; | ||
| 8 | import cuchaz.enigma.network.ServerPacketHandler; | ||
| 9 | import cuchaz.enigma.translation.mapping.EntryMapping; | ||
| 10 | import cuchaz.enigma.translation.representation.entry.Entry; | ||
| 11 | import cuchaz.enigma.utils.validation.PrintValidatable; | ||
| 12 | import cuchaz.enigma.utils.validation.ValidationContext; | ||
| 13 | |||
| 14 | public class MarkDeobfuscatedC2SPacket implements Packet<ServerPacketHandler> { | ||
| 15 | private Entry<?> entry; | ||
| 16 | |||
| 17 | MarkDeobfuscatedC2SPacket() { | ||
| 18 | } | ||
| 19 | |||
| 20 | public MarkDeobfuscatedC2SPacket(Entry<?> entry) { | ||
| 21 | this.entry = entry; | ||
| 22 | } | ||
| 23 | |||
| 24 | @Override | ||
| 25 | public void read(DataInput input) throws IOException { | ||
| 26 | this.entry = PacketHelper.readEntry(input); | ||
| 27 | } | ||
| 28 | |||
| 29 | @Override | ||
| 30 | public void write(DataOutput output) throws IOException { | ||
| 31 | PacketHelper.writeEntry(output, entry); | ||
| 32 | } | ||
| 33 | |||
| 34 | @Override | ||
| 35 | public void handle(ServerPacketHandler handler) { | ||
| 36 | ValidationContext vc = new ValidationContext(); | ||
| 37 | vc.setActiveElement(PrintValidatable.INSTANCE); | ||
| 38 | |||
| 39 | boolean valid = handler.getServer().canModifyEntry(handler.getClient(), entry); | ||
| 40 | |||
| 41 | if (!valid) { | ||
| 42 | handler.getServer().sendCorrectMapping(handler.getClient(), entry, true); | ||
| 43 | return; | ||
| 44 | } | ||
| 45 | |||
| 46 | handler.getServer().getMappings().mapFromObf(vc, entry, new EntryMapping(handler.getServer().getMappings().deobfuscate(entry).getName())); | ||
| 47 | |||
| 48 | if (!vc.canProceed()) return; | ||
| 49 | |||
| 50 | handler.getServer().log(handler.getServer().getUsername(handler.getClient()) + " marked " + entry + " as deobfuscated"); | ||
| 51 | |||
| 52 | int syncId = handler.getServer().lockEntry(handler.getClient(), entry); | ||
| 53 | handler.getServer().sendToAllExcept(handler.getClient(), new MarkDeobfuscatedS2CPacket(syncId, entry)); | ||
| 54 | handler.getServer().sendMessage(Message.markDeobf(handler.getServer().getUsername(handler.getClient()), entry)); | ||
| 55 | } | ||
| 56 | } | ||
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 @@ | |||
| 1 | package cuchaz.enigma.network.packet; | ||
| 2 | |||
| 3 | import java.io.DataInput; | ||
| 4 | import java.io.DataOutput; | ||
| 5 | import java.io.IOException; | ||
| 6 | |||
| 7 | import cuchaz.enigma.analysis.EntryReference; | ||
| 8 | import cuchaz.enigma.network.ClientPacketHandler; | ||
| 9 | import cuchaz.enigma.translation.representation.entry.Entry; | ||
| 10 | import cuchaz.enigma.utils.validation.PrintValidatable; | ||
| 11 | import cuchaz.enigma.utils.validation.ValidationContext; | ||
| 12 | |||
| 13 | public class MarkDeobfuscatedS2CPacket implements Packet<ClientPacketHandler> { | ||
| 14 | private int syncId; | ||
| 15 | private Entry<?> entry; | ||
| 16 | |||
| 17 | MarkDeobfuscatedS2CPacket() { | ||
| 18 | } | ||
| 19 | |||
| 20 | public MarkDeobfuscatedS2CPacket(int syncId, Entry<?> entry) { | ||
| 21 | this.syncId = syncId; | ||
| 22 | this.entry = entry; | ||
| 23 | } | ||
| 24 | |||
| 25 | @Override | ||
| 26 | public void read(DataInput input) throws IOException { | ||
| 27 | this.syncId = input.readUnsignedShort(); | ||
| 28 | this.entry = PacketHelper.readEntry(input); | ||
| 29 | } | ||
| 30 | |||
| 31 | @Override | ||
| 32 | public void write(DataOutput output) throws IOException { | ||
| 33 | output.writeShort(syncId); | ||
| 34 | PacketHelper.writeEntry(output, entry); | ||
| 35 | } | ||
| 36 | |||
| 37 | @Override | ||
| 38 | public void handle(ClientPacketHandler controller) { | ||
| 39 | ValidationContext vc = new ValidationContext(); | ||
| 40 | vc.setActiveElement(PrintValidatable.INSTANCE); | ||
| 41 | |||
| 42 | controller.markAsDeobfuscated(vc, new EntryReference<>(entry, entry.getName())); | ||
| 43 | |||
| 44 | if (!vc.canProceed()) return; | ||
| 45 | controller.sendPacket(new ConfirmChangeC2SPacket(syncId)); | ||
| 46 | } | ||
| 47 | } | ||
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 @@ | |||
| 1 | package cuchaz.enigma.network.packet; | 1 | package cuchaz.enigma.network.packet; |
| 2 | 2 | ||
| 3 | import cuchaz.enigma.translation.representation.MethodDescriptor; | ||
| 4 | import cuchaz.enigma.translation.representation.TypeDescriptor; | ||
| 5 | import cuchaz.enigma.translation.representation.entry.ClassEntry; | ||
| 6 | import cuchaz.enigma.translation.representation.entry.Entry; | ||
| 7 | import cuchaz.enigma.translation.representation.entry.FieldEntry; | ||
| 8 | import cuchaz.enigma.translation.representation.entry.LocalVariableEntry; | ||
| 9 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | ||
| 10 | |||
| 11 | import java.io.DataInput; | 3 | import java.io.DataInput; |
| 12 | import java.io.DataOutput; | 4 | import java.io.DataOutput; |
| 13 | import java.io.IOException; | 5 | import java.io.IOException; |
| 14 | import java.nio.charset.StandardCharsets; | 6 | import java.nio.charset.StandardCharsets; |
| 15 | 7 | ||
| 8 | import cuchaz.enigma.translation.mapping.AccessModifier; | ||
| 9 | import cuchaz.enigma.translation.mapping.EntryChange; | ||
| 10 | import cuchaz.enigma.translation.representation.MethodDescriptor; | ||
| 11 | import cuchaz.enigma.translation.representation.TypeDescriptor; | ||
| 12 | import cuchaz.enigma.translation.representation.entry.*; | ||
| 13 | import cuchaz.enigma.utils.TristateChange; | ||
| 14 | |||
| 16 | public class PacketHelper { | 15 | public class PacketHelper { |
| 17 | 16 | ||
| 18 | private static final int ENTRY_CLASS = 0, ENTRY_FIELD = 1, ENTRY_METHOD = 2, ENTRY_LOCAL_VAR = 3; | 17 | private static final int ENTRY_CLASS = 0, ENTRY_FIELD = 1, ENTRY_METHOD = 2, ENTRY_LOCAL_VAR = 3; |
| @@ -37,35 +36,40 @@ public class PacketHelper { | |||
| 37 | } | 36 | } |
| 38 | 37 | ||
| 39 | switch (type) { | 38 | switch (type) { |
| 40 | case ENTRY_CLASS: { | 39 | case ENTRY_CLASS: { |
| 41 | if (parent != null && !(parent instanceof ClassEntry)) { | 40 | if (parent != null && !(parent instanceof ClassEntry)) { |
| 42 | throw new IOException("Class requires class parent"); | 41 | throw new IOException("Class requires class parent"); |
| 42 | } | ||
| 43 | |||
| 44 | return new ClassEntry((ClassEntry) parent, name, javadocs); | ||
| 43 | } | 45 | } |
| 44 | return new ClassEntry((ClassEntry) parent, name, javadocs); | 46 | case ENTRY_FIELD: { |
| 45 | } | 47 | if (!(parent instanceof ClassEntry parentClass)) { |
| 46 | case ENTRY_FIELD: { | 48 | throw new IOException("Field requires class parent"); |
| 47 | if (!(parent instanceof ClassEntry)) { | 49 | } |
| 48 | throw new IOException("Field requires class parent"); | 50 | |
| 51 | TypeDescriptor desc = new TypeDescriptor(readString(input)); | ||
| 52 | return new FieldEntry(parentClass, name, desc, javadocs); | ||
| 49 | } | 53 | } |
| 50 | TypeDescriptor desc = new TypeDescriptor(readString(input)); | 54 | case ENTRY_METHOD: { |
| 51 | return new FieldEntry((ClassEntry) parent, name, desc, javadocs); | 55 | if (!(parent instanceof ClassEntry parentClass)) { |
| 52 | } | 56 | throw new IOException("Method requires class parent"); |
| 53 | case ENTRY_METHOD: { | 57 | } |
| 54 | if (!(parent instanceof ClassEntry)) { | 58 | |
| 55 | throw new IOException("Method requires class parent"); | 59 | MethodDescriptor desc = new MethodDescriptor(readString(input)); |
| 60 | return new MethodEntry(parentClass, name, desc, javadocs); | ||
| 56 | } | 61 | } |
| 57 | MethodDescriptor desc = new MethodDescriptor(readString(input)); | 62 | case ENTRY_LOCAL_VAR: { |
| 58 | return new MethodEntry((ClassEntry) parent, name, desc, javadocs); | 63 | if (!(parent instanceof MethodEntry parentMethod)) { |
| 59 | } | 64 | throw new IOException("Local variable requires method parent"); |
| 60 | case ENTRY_LOCAL_VAR: { | 65 | } |
| 61 | if (!(parent instanceof MethodEntry)) { | 66 | |
| 62 | throw new IOException("Local variable requires method parent"); | 67 | int index = input.readUnsignedShort(); |
| 68 | boolean parameter = input.readBoolean(); | ||
| 69 | return new LocalVariableEntry(parentMethod, index, name, parameter, javadocs); | ||
| 63 | } | 70 | } |
| 64 | int index = input.readUnsignedShort(); | 71 | default: |
| 65 | boolean parameter = input.readBoolean(); | 72 | throw new IOException("Received unknown entry type " + type); |
| 66 | return new LocalVariableEntry((MethodEntry) parent, index, name, parameter, javadocs); | ||
| 67 | } | ||
| 68 | default: throw new IOException("Received unknown entry type " + type); | ||
| 69 | } | 73 | } |
| 70 | } | 74 | } |
| 71 | 75 | ||
| @@ -132,4 +136,64 @@ public class PacketHelper { | |||
| 132 | output.write(bytes); | 136 | output.write(bytes); |
| 133 | } | 137 | } |
| 134 | 138 | ||
| 139 | public static EntryChange<?> readEntryChange(DataInput input) throws IOException { | ||
| 140 | Entry<?> e = readEntry(input); | ||
| 141 | EntryChange<?> change = EntryChange.modify(e); | ||
| 142 | |||
| 143 | int flags = input.readUnsignedByte(); | ||
| 144 | TristateChange.Type deobfNameT = TristateChange.Type.values()[flags & 0x3]; | ||
| 145 | TristateChange.Type accessT = TristateChange.Type.values()[flags >> 2 & 0x3]; | ||
| 146 | TristateChange.Type javadocT = TristateChange.Type.values()[flags >> 4 & 0x3]; | ||
| 147 | |||
| 148 | switch (deobfNameT) { | ||
| 149 | case RESET: | ||
| 150 | change = change.clearDeobfName(); | ||
| 151 | break; | ||
| 152 | case SET: | ||
| 153 | change = change.withDeobfName(readString(input)); | ||
| 154 | break; | ||
| 155 | } | ||
| 156 | |||
| 157 | switch (accessT) { | ||
| 158 | case RESET: | ||
| 159 | change = change.clearAccess(); | ||
| 160 | break; | ||
| 161 | case SET: | ||
| 162 | change = change.withAccess(AccessModifier.values()[flags >> 6 & 0x3]); | ||
| 163 | break; | ||
| 164 | } | ||
| 165 | |||
| 166 | switch (javadocT) { | ||
| 167 | case RESET: | ||
| 168 | change = change.clearJavadoc(); | ||
| 169 | break; | ||
| 170 | case SET: | ||
| 171 | change = change.withJavadoc(readString(input)); | ||
| 172 | break; | ||
| 173 | } | ||
| 174 | |||
| 175 | return change; | ||
| 176 | } | ||
| 177 | |||
| 178 | public static void writeEntryChange(DataOutput output, EntryChange<?> change) throws IOException { | ||
| 179 | writeEntry(output, change.getTarget()); | ||
| 180 | int flags = change.getDeobfName().getType().ordinal() | | ||
| 181 | change.getAccess().getType().ordinal() << 2 | | ||
| 182 | change.getJavadoc().getType().ordinal() << 4; | ||
| 183 | |||
| 184 | if (change.getAccess().isSet()) { | ||
| 185 | flags |= change.getAccess().getNewValue().ordinal() << 6; | ||
| 186 | } | ||
| 187 | |||
| 188 | output.writeByte(flags); | ||
| 189 | |||
| 190 | if (change.getDeobfName().isSet()) { | ||
| 191 | writeString(output, change.getDeobfName().getNewValue()); | ||
| 192 | } | ||
| 193 | |||
| 194 | if (change.getJavadoc().isSet()) { | ||
| 195 | writeString(output, change.getJavadoc().getNewValue()); | ||
| 196 | } | ||
| 197 | } | ||
| 198 | |||
| 135 | } | 199 | } |
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 @@ | |||
| 1 | package cuchaz.enigma.network.packet; | 1 | package cuchaz.enigma.network.packet; |
| 2 | 2 | ||
| 3 | import cuchaz.enigma.network.ClientPacketHandler; | ||
| 4 | import cuchaz.enigma.network.ServerPacketHandler; | ||
| 5 | |||
| 6 | import java.util.HashMap; | 3 | import java.util.HashMap; |
| 7 | import java.util.Map; | 4 | import java.util.Map; |
| 8 | import java.util.function.Supplier; | 5 | import java.util.function.Supplier; |
| 9 | 6 | ||
| 7 | import cuchaz.enigma.network.ClientPacketHandler; | ||
| 8 | import cuchaz.enigma.network.ServerPacketHandler; | ||
| 9 | |||
| 10 | public class PacketRegistry { | 10 | public class PacketRegistry { |
| 11 | 11 | ||
| 12 | private static final Map<Class<? extends Packet<ServerPacketHandler>>, Integer> c2sPacketIds = new HashMap<>(); | 12 | private static final Map<Class<? extends Packet<ServerPacketHandler>>, Integer> c2sPacketIds = new HashMap<>(); |
| @@ -27,20 +27,14 @@ public class PacketRegistry { | |||
| 27 | static { | 27 | static { |
| 28 | registerC2S(0, LoginC2SPacket.class, LoginC2SPacket::new); | 28 | registerC2S(0, LoginC2SPacket.class, LoginC2SPacket::new); |
| 29 | registerC2S(1, ConfirmChangeC2SPacket.class, ConfirmChangeC2SPacket::new); | 29 | registerC2S(1, ConfirmChangeC2SPacket.class, ConfirmChangeC2SPacket::new); |
| 30 | registerC2S(2, RenameC2SPacket.class, RenameC2SPacket::new); | ||
| 31 | registerC2S(3, RemoveMappingC2SPacket.class, RemoveMappingC2SPacket::new); | ||
| 32 | registerC2S(4, ChangeDocsC2SPacket.class, ChangeDocsC2SPacket::new); | ||
| 33 | registerC2S(5, MarkDeobfuscatedC2SPacket.class, MarkDeobfuscatedC2SPacket::new); | ||
| 34 | registerC2S(6, MessageC2SPacket.class, MessageC2SPacket::new); | 30 | registerC2S(6, MessageC2SPacket.class, MessageC2SPacket::new); |
| 31 | registerC2S(7, EntryChangeC2SPacket.class, EntryChangeC2SPacket::new); | ||
| 35 | 32 | ||
| 36 | registerS2C(0, KickS2CPacket.class, KickS2CPacket::new); | 33 | registerS2C(0, KickS2CPacket.class, KickS2CPacket::new); |
| 37 | registerS2C(1, SyncMappingsS2CPacket.class, SyncMappingsS2CPacket::new); | 34 | registerS2C(1, SyncMappingsS2CPacket.class, SyncMappingsS2CPacket::new); |
| 38 | registerS2C(2, RenameS2CPacket.class, RenameS2CPacket::new); | ||
| 39 | registerS2C(3, RemoveMappingS2CPacket.class, RemoveMappingS2CPacket::new); | ||
| 40 | registerS2C(4, ChangeDocsS2CPacket.class, ChangeDocsS2CPacket::new); | ||
| 41 | registerS2C(5, MarkDeobfuscatedS2CPacket.class, MarkDeobfuscatedS2CPacket::new); | ||
| 42 | registerS2C(6, MessageS2CPacket.class, MessageS2CPacket::new); | 35 | registerS2C(6, MessageS2CPacket.class, MessageS2CPacket::new); |
| 43 | registerS2C(7, UserListS2CPacket.class, UserListS2CPacket::new); | 36 | registerS2C(7, UserListS2CPacket.class, UserListS2CPacket::new); |
| 37 | registerS2C(8, EntryChangeS2CPacket.class, EntryChangeS2CPacket::new); | ||
| 44 | } | 38 | } |
| 45 | 39 | ||
| 46 | public static int getC2SId(Packet<ServerPacketHandler> packet) { | 40 | public static int getC2SId(Packet<ServerPacketHandler> 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 @@ | |||
| 1 | package cuchaz.enigma.network.packet; | ||
| 2 | |||
| 3 | import java.io.DataInput; | ||
| 4 | import java.io.DataOutput; | ||
| 5 | import java.io.IOException; | ||
| 6 | |||
| 7 | import cuchaz.enigma.network.Message; | ||
| 8 | import cuchaz.enigma.network.ServerPacketHandler; | ||
| 9 | import cuchaz.enigma.translation.representation.entry.Entry; | ||
| 10 | import cuchaz.enigma.utils.validation.PrintValidatable; | ||
| 11 | import cuchaz.enigma.utils.validation.ValidationContext; | ||
| 12 | |||
| 13 | public class RemoveMappingC2SPacket implements Packet<ServerPacketHandler> { | ||
| 14 | private Entry<?> entry; | ||
| 15 | |||
| 16 | RemoveMappingC2SPacket() { | ||
| 17 | } | ||
| 18 | |||
| 19 | public RemoveMappingC2SPacket(Entry<?> entry) { | ||
| 20 | this.entry = entry; | ||
| 21 | } | ||
| 22 | |||
| 23 | @Override | ||
| 24 | public void read(DataInput input) throws IOException { | ||
| 25 | this.entry = PacketHelper.readEntry(input); | ||
| 26 | } | ||
| 27 | |||
| 28 | @Override | ||
| 29 | public void write(DataOutput output) throws IOException { | ||
| 30 | PacketHelper.writeEntry(output, entry); | ||
| 31 | } | ||
| 32 | |||
| 33 | @Override | ||
| 34 | public void handle(ServerPacketHandler handler) { | ||
| 35 | ValidationContext vc = new ValidationContext(); | ||
| 36 | vc.setActiveElement(PrintValidatable.INSTANCE); | ||
| 37 | |||
| 38 | boolean valid = handler.getServer().canModifyEntry(handler.getClient(), entry); | ||
| 39 | |||
| 40 | if (valid) { | ||
| 41 | handler.getServer().getMappings().removeByObf(vc, entry); | ||
| 42 | valid = vc.canProceed(); | ||
| 43 | } | ||
| 44 | |||
| 45 | if (!valid) { | ||
| 46 | handler.getServer().sendCorrectMapping(handler.getClient(), entry, true); | ||
| 47 | return; | ||
| 48 | } | ||
| 49 | |||
| 50 | handler.getServer().log(handler.getServer().getUsername(handler.getClient()) + " removed the mapping for " + entry); | ||
| 51 | |||
| 52 | int syncId = handler.getServer().lockEntry(handler.getClient(), entry); | ||
| 53 | handler.getServer().sendToAllExcept(handler.getClient(), new RemoveMappingS2CPacket(syncId, entry)); | ||
| 54 | handler.getServer().sendMessage(Message.removeMapping(handler.getServer().getUsername(handler.getClient()), entry)); | ||
| 55 | } | ||
| 56 | } | ||
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 @@ | |||
| 1 | package cuchaz.enigma.network.packet; | ||
| 2 | |||
| 3 | import java.io.DataInput; | ||
| 4 | import java.io.DataOutput; | ||
| 5 | import java.io.IOException; | ||
| 6 | |||
| 7 | import cuchaz.enigma.analysis.EntryReference; | ||
| 8 | import cuchaz.enigma.network.ClientPacketHandler; | ||
| 9 | import cuchaz.enigma.translation.representation.entry.Entry; | ||
| 10 | import cuchaz.enigma.utils.validation.PrintValidatable; | ||
| 11 | import cuchaz.enigma.utils.validation.ValidationContext; | ||
| 12 | |||
| 13 | public class RemoveMappingS2CPacket implements Packet<ClientPacketHandler> { | ||
| 14 | private int syncId; | ||
| 15 | private Entry<?> entry; | ||
| 16 | |||
| 17 | RemoveMappingS2CPacket() { | ||
| 18 | } | ||
| 19 | |||
| 20 | public RemoveMappingS2CPacket(int syncId, Entry<?> entry) { | ||
| 21 | this.syncId = syncId; | ||
| 22 | this.entry = entry; | ||
| 23 | } | ||
| 24 | |||
| 25 | @Override | ||
| 26 | public void read(DataInput input) throws IOException { | ||
| 27 | this.syncId = input.readUnsignedShort(); | ||
| 28 | this.entry = PacketHelper.readEntry(input); | ||
| 29 | } | ||
| 30 | |||
| 31 | @Override | ||
| 32 | public void write(DataOutput output) throws IOException { | ||
| 33 | output.writeShort(syncId); | ||
| 34 | PacketHelper.writeEntry(output, entry); | ||
| 35 | } | ||
| 36 | |||
| 37 | @Override | ||
| 38 | public void handle(ClientPacketHandler controller) { | ||
| 39 | ValidationContext vc = new ValidationContext(); | ||
| 40 | vc.setActiveElement(PrintValidatable.INSTANCE); | ||
| 41 | |||
| 42 | controller.removeMapping(vc, new EntryReference<>(entry, entry.getName())); | ||
| 43 | |||
| 44 | if (!vc.canProceed()) return; | ||
| 45 | controller.sendPacket(new ConfirmChangeC2SPacket(syncId)); | ||
| 46 | } | ||
| 47 | } | ||
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 @@ | |||
| 1 | package cuchaz.enigma.network.packet; | ||
| 2 | |||
| 3 | import java.io.DataInput; | ||
| 4 | import java.io.DataOutput; | ||
| 5 | import java.io.IOException; | ||
| 6 | |||
| 7 | import cuchaz.enigma.network.Message; | ||
| 8 | import cuchaz.enigma.network.ServerPacketHandler; | ||
| 9 | import cuchaz.enigma.translation.mapping.EntryMapping; | ||
| 10 | import cuchaz.enigma.translation.representation.entry.Entry; | ||
| 11 | import cuchaz.enigma.utils.validation.PrintValidatable; | ||
| 12 | import cuchaz.enigma.utils.validation.ValidationContext; | ||
| 13 | |||
| 14 | public class RenameC2SPacket implements Packet<ServerPacketHandler> { | ||
| 15 | private Entry<?> entry; | ||
| 16 | private String newName; | ||
| 17 | private boolean refreshClassTree; | ||
| 18 | |||
| 19 | RenameC2SPacket() { | ||
| 20 | } | ||
| 21 | |||
| 22 | public RenameC2SPacket(Entry<?> entry, String newName, boolean refreshClassTree) { | ||
| 23 | this.entry = entry; | ||
| 24 | this.newName = newName; | ||
| 25 | this.refreshClassTree = refreshClassTree; | ||
| 26 | } | ||
| 27 | |||
| 28 | @Override | ||
| 29 | public void read(DataInput input) throws IOException { | ||
| 30 | this.entry = PacketHelper.readEntry(input); | ||
| 31 | this.newName = PacketHelper.readString(input); | ||
| 32 | this.refreshClassTree = input.readBoolean(); | ||
| 33 | } | ||
| 34 | |||
| 35 | @Override | ||
| 36 | public void write(DataOutput output) throws IOException { | ||
| 37 | PacketHelper.writeEntry(output, entry); | ||
| 38 | PacketHelper.writeString(output, newName); | ||
| 39 | output.writeBoolean(refreshClassTree); | ||
| 40 | } | ||
| 41 | |||
| 42 | @Override | ||
| 43 | public void handle(ServerPacketHandler handler) { | ||
| 44 | ValidationContext vc = new ValidationContext(); | ||
| 45 | vc.setActiveElement(PrintValidatable.INSTANCE); | ||
| 46 | |||
| 47 | boolean valid = handler.getServer().canModifyEntry(handler.getClient(), entry); | ||
| 48 | |||
| 49 | if (valid) { | ||
| 50 | EntryMapping previous = handler.getServer().getMappings().getDeobfMapping(entry); | ||
| 51 | handler.getServer().getMappings().mapFromObf(vc, entry, previous != null ? previous.withName(newName) : new EntryMapping(newName)); | ||
| 52 | valid = vc.canProceed(); | ||
| 53 | } | ||
| 54 | |||
| 55 | if (!valid) { | ||
| 56 | handler.getServer().sendCorrectMapping(handler.getClient(), entry, refreshClassTree); | ||
| 57 | return; | ||
| 58 | } | ||
| 59 | |||
| 60 | handler.getServer().log(handler.getServer().getUsername(handler.getClient()) + " renamed " + entry + " to " + newName); | ||
| 61 | |||
| 62 | int syncId = handler.getServer().lockEntry(handler.getClient(), entry); | ||
| 63 | handler.getServer().sendToAllExcept(handler.getClient(), new RenameS2CPacket(syncId, entry, newName, refreshClassTree)); | ||
| 64 | handler.getServer().sendMessage(Message.rename(handler.getServer().getUsername(handler.getClient()), entry, newName)); | ||
| 65 | } | ||
| 66 | } | ||
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 @@ | |||
| 1 | package cuchaz.enigma.network.packet; | ||
| 2 | |||
| 3 | import java.io.DataInput; | ||
| 4 | import java.io.DataOutput; | ||
| 5 | import java.io.IOException; | ||
| 6 | |||
| 7 | import cuchaz.enigma.analysis.EntryReference; | ||
| 8 | import cuchaz.enigma.network.ClientPacketHandler; | ||
| 9 | import cuchaz.enigma.translation.representation.entry.Entry; | ||
| 10 | import cuchaz.enigma.utils.validation.PrintValidatable; | ||
| 11 | import cuchaz.enigma.utils.validation.ValidationContext; | ||
| 12 | |||
| 13 | public class RenameS2CPacket implements Packet<ClientPacketHandler> { | ||
| 14 | private int syncId; | ||
| 15 | private Entry<?> entry; | ||
| 16 | private String newName; | ||
| 17 | private boolean refreshClassTree; | ||
| 18 | |||
| 19 | RenameS2CPacket() { | ||
| 20 | } | ||
| 21 | |||
| 22 | public RenameS2CPacket(int syncId, Entry<?> entry, String newName, boolean refreshClassTree) { | ||
| 23 | this.syncId = syncId; | ||
| 24 | this.entry = entry; | ||
| 25 | this.newName = newName; | ||
| 26 | this.refreshClassTree = refreshClassTree; | ||
| 27 | } | ||
| 28 | |||
| 29 | @Override | ||
| 30 | public void read(DataInput input) throws IOException { | ||
| 31 | this.syncId = input.readUnsignedShort(); | ||
| 32 | this.entry = PacketHelper.readEntry(input); | ||
| 33 | this.newName = PacketHelper.readString(input); | ||
| 34 | this.refreshClassTree = input.readBoolean(); | ||
| 35 | } | ||
| 36 | |||
| 37 | @Override | ||
| 38 | public void write(DataOutput output) throws IOException { | ||
| 39 | output.writeShort(syncId); | ||
| 40 | PacketHelper.writeEntry(output, entry); | ||
| 41 | PacketHelper.writeString(output, newName); | ||
| 42 | output.writeBoolean(refreshClassTree); | ||
| 43 | } | ||
| 44 | |||
| 45 | @Override | ||
| 46 | public void handle(ClientPacketHandler controller) { | ||
| 47 | ValidationContext vc = new ValidationContext(); | ||
| 48 | vc.setActiveElement(PrintValidatable.INSTANCE); | ||
| 49 | |||
| 50 | controller.rename(vc, new EntryReference<>(entry, entry.getName()), newName, refreshClassTree); | ||
| 51 | |||
| 52 | if (!vc.canProceed()) return; | ||
| 53 | controller.sendPacket(new ConfirmChangeC2SPacket(syncId)); | ||
| 54 | } | ||
| 55 | } | ||
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 @@ | |||
| 1 | package cuchaz.enigma.network.packet; | 1 | package cuchaz.enigma.network.packet; |
| 2 | 2 | ||
| 3 | import cuchaz.enigma.translation.mapping.EntryMapping; | ||
| 4 | import cuchaz.enigma.translation.mapping.tree.EntryTree; | ||
| 5 | import cuchaz.enigma.translation.mapping.tree.EntryTreeNode; | ||
| 6 | import cuchaz.enigma.translation.mapping.tree.HashEntryTree; | ||
| 7 | import cuchaz.enigma.network.ClientPacketHandler; | ||
| 8 | import cuchaz.enigma.network.EnigmaServer; | ||
| 9 | import cuchaz.enigma.translation.representation.entry.Entry; | ||
| 10 | |||
| 11 | import java.io.DataInput; | 3 | import java.io.DataInput; |
| 12 | import java.io.DataOutput; | 4 | import java.io.DataOutput; |
| 13 | import java.io.IOException; | 5 | import java.io.IOException; |
| 14 | import java.util.Collection; | 6 | import java.util.Collection; |
| 15 | import java.util.List; | 7 | import java.util.List; |
| 16 | 8 | ||
| 9 | import cuchaz.enigma.network.ClientPacketHandler; | ||
| 10 | import cuchaz.enigma.network.EnigmaServer; | ||
| 11 | import cuchaz.enigma.translation.mapping.EntryMapping; | ||
| 12 | import cuchaz.enigma.translation.mapping.tree.EntryTree; | ||
| 13 | import cuchaz.enigma.translation.mapping.tree.EntryTreeNode; | ||
| 14 | import cuchaz.enigma.translation.mapping.tree.HashEntryTree; | ||
| 15 | import cuchaz.enigma.translation.representation.entry.Entry; | ||
| 16 | |||
| 17 | public class SyncMappingsS2CPacket implements Packet<ClientPacketHandler> { | 17 | public class SyncMappingsS2CPacket implements Packet<ClientPacketHandler> { |
| 18 | private EntryTree<EntryMapping> mappings; | 18 | private EntryTree<EntryMapping> mappings; |
| 19 | 19 | ||
| @@ -35,16 +35,9 @@ public class SyncMappingsS2CPacket implements Packet<ClientPacketHandler> { | |||
| 35 | 35 | ||
| 36 | private void readEntryTreeNode(DataInput input, Entry<?> parent) throws IOException { | 36 | private void readEntryTreeNode(DataInput input, Entry<?> parent) throws IOException { |
| 37 | Entry<?> entry = PacketHelper.readEntry(input, parent, false); | 37 | Entry<?> entry = PacketHelper.readEntry(input, parent, false); |
| 38 | EntryMapping mapping = null; | 38 | String name = PacketHelper.readString(input); |
| 39 | if (input.readBoolean()) { | 39 | String javadoc = PacketHelper.readString(input); |
| 40 | String name = input.readUTF(); | 40 | EntryMapping mapping = new EntryMapping(!name.isEmpty() ? name : null, !javadoc.isEmpty() ? javadoc : null); |
| 41 | if (input.readBoolean()) { | ||
| 42 | String javadoc = input.readUTF(); | ||
| 43 | mapping = new EntryMapping(name, javadoc); | ||
| 44 | } else { | ||
| 45 | mapping = new EntryMapping(name); | ||
| 46 | } | ||
| 47 | } | ||
| 48 | mappings.insert(entry, mapping); | 41 | mappings.insert(entry, mapping); |
| 49 | int size = input.readUnsignedShort(); | 42 | int size = input.readUnsignedShort(); |
| 50 | for (int i = 0; i < size; i++) { | 43 | for (int i = 0; i < size; i++) { |
| @@ -64,14 +57,10 @@ public class SyncMappingsS2CPacket implements Packet<ClientPacketHandler> { | |||
| 64 | private static void writeEntryTreeNode(DataOutput output, EntryTreeNode<EntryMapping> node) throws IOException { | 57 | private static void writeEntryTreeNode(DataOutput output, EntryTreeNode<EntryMapping> node) throws IOException { |
| 65 | PacketHelper.writeEntry(output, node.getEntry(), false); | 58 | PacketHelper.writeEntry(output, node.getEntry(), false); |
| 66 | EntryMapping value = node.getValue(); | 59 | EntryMapping value = node.getValue(); |
| 67 | output.writeBoolean(value != null); | 60 | if (value == null) value = EntryMapping.DEFAULT; |
| 68 | if (value != null) { | 61 | |
| 69 | PacketHelper.writeString(output, value.getTargetName()); | 62 | PacketHelper.writeString(output, value.targetName() != null ? value.targetName() : ""); |
| 70 | output.writeBoolean(value.getJavadoc() != null); | 63 | PacketHelper.writeString(output, value.javadoc() != null ? value.javadoc() : ""); |
| 71 | if (value.getJavadoc() != null) { | ||
| 72 | PacketHelper.writeString(output, value.getJavadoc()); | ||
| 73 | } | ||
| 74 | } | ||
| 75 | Collection<? extends EntryTreeNode<EntryMapping>> children = node.getChildNodes(); | 64 | Collection<? extends EntryTreeNode<EntryMapping>> children = node.getChildNodes(); |
| 76 | output.writeShort(children.size()); | 65 | output.writeShort(children.size()); |
| 77 | for (EntryTreeNode<EntryMapping> child : children) { | 66 | for (EntryTreeNode<EntryMapping> child : children) { |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/Gui.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/Gui.java index a657d171..cddedad7 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/Gui.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/Gui.java | |||
| @@ -49,11 +49,9 @@ import cuchaz.enigma.gui.renderer.InheritanceTreeCellRenderer; | |||
| 49 | import cuchaz.enigma.gui.renderer.MessageListCellRenderer; | 49 | import cuchaz.enigma.gui.renderer.MessageListCellRenderer; |
| 50 | import cuchaz.enigma.gui.util.*; | 50 | import cuchaz.enigma.gui.util.*; |
| 51 | import cuchaz.enigma.network.Message; | 51 | import cuchaz.enigma.network.Message; |
| 52 | import cuchaz.enigma.network.packet.MarkDeobfuscatedC2SPacket; | ||
| 53 | import cuchaz.enigma.network.packet.MessageC2SPacket; | 52 | import cuchaz.enigma.network.packet.MessageC2SPacket; |
| 54 | import cuchaz.enigma.network.packet.RemoveMappingC2SPacket; | ||
| 55 | import cuchaz.enigma.network.packet.RenameC2SPacket; | ||
| 56 | import cuchaz.enigma.source.Token; | 53 | import cuchaz.enigma.source.Token; |
| 54 | import cuchaz.enigma.translation.mapping.EntryChange; | ||
| 57 | import cuchaz.enigma.translation.mapping.EntryRemapper; | 55 | import cuchaz.enigma.translation.mapping.EntryRemapper; |
| 58 | import cuchaz.enigma.translation.representation.entry.ClassEntry; | 56 | import cuchaz.enigma.translation.representation.entry.ClassEntry; |
| 59 | import cuchaz.enigma.translation.representation.entry.Entry; | 57 | import cuchaz.enigma.translation.representation.entry.Entry; |
| @@ -740,12 +738,10 @@ public class Gui implements LanguageChangeListener { | |||
| 740 | 738 | ||
| 741 | Entry<?> obfEntry = cursorReference.entry; | 739 | Entry<?> obfEntry = cursorReference.entry; |
| 742 | 740 | ||
| 743 | if (controller.project.getMapper().extendedDeobfuscate(obfEntry).isDeobfuscated()) { | 741 | if (this.controller.project.getMapper().getDeobfMapping(obfEntry).targetName() != null) { |
| 744 | if (!validateImmediateAction(vc -> this.controller.removeMapping(vc, cursorReference))) return; | 742 | validateImmediateAction(vc -> this.controller.applyChange(vc, EntryChange.modify(obfEntry).clearDeobfName())); |
| 745 | this.controller.sendPacket(new RemoveMappingC2SPacket(cursorReference.getNameableEntry())); | ||
| 746 | } else { | 743 | } else { |
| 747 | if (!validateImmediateAction(vc -> this.controller.markAsDeobfuscated(vc, cursorReference))) return; | 744 | validateImmediateAction(vc -> this.controller.applyChange(vc, EntryChange.modify(obfEntry).withDefaultDeobfName(this.getController().project))); |
| 748 | this.controller.sendPacket(new MarkDeobfuscatedC2SPacket(cursorReference.getNameableEntry())); | ||
| 749 | } | 745 | } |
| 750 | } | 746 | } |
| 751 | 747 | ||
| @@ -813,7 +809,7 @@ public class Gui implements LanguageChangeListener { | |||
| 813 | this.frame.repaint(); | 809 | this.frame.repaint(); |
| 814 | } | 810 | } |
| 815 | 811 | ||
| 816 | public void onPanelRename(ValidationContext vc, Object prevData, Object data, DefaultMutableTreeNode node) { | 812 | public void onRenameFromClassTree(ValidationContext vc, Object prevData, Object data, DefaultMutableTreeNode node) { |
| 817 | if (data instanceof String) { | 813 | if (data instanceof String) { |
| 818 | // package rename | 814 | // package rename |
| 819 | for (int i = 0; i < node.getChildCount(); i++) { | 815 | for (int i = 0; i < node.getChildCount(); i++) { |
| @@ -821,7 +817,7 @@ public class Gui implements LanguageChangeListener { | |||
| 821 | ClassEntry prevDataChild = (ClassEntry) childNode.getUserObject(); | 817 | ClassEntry prevDataChild = (ClassEntry) childNode.getUserObject(); |
| 822 | ClassEntry dataChild = new ClassEntry(data + "/" + prevDataChild.getSimpleName()); | 818 | ClassEntry dataChild = new ClassEntry(data + "/" + prevDataChild.getSimpleName()); |
| 823 | 819 | ||
| 824 | onPanelRename(vc, prevDataChild, dataChild, node); | 820 | onRenameFromClassTree(vc, prevDataChild, dataChild, node); |
| 825 | } | 821 | } |
| 826 | node.setUserObject(data); | 822 | node.setUserObject(data); |
| 827 | // Ob package will never be modified, just reload deob view | 823 | // Ob package will never be modified, just reload deob view |
| @@ -839,9 +835,9 @@ public class Gui implements LanguageChangeListener { | |||
| 839 | .filter(e -> mapper.deobfuscate(e).equals(deobf)) | 835 | .filter(e -> mapper.deobfuscate(e).equals(deobf)) |
| 840 | .findAny().orElse(deobf); | 836 | .findAny().orElse(deobf); |
| 841 | 837 | ||
| 842 | this.controller.rename(vc, new EntryReference<>(obf, obf.getFullName()), ((ClassEntry) data).getFullName(), false); | 838 | this.controller.applyChange(vc, EntryChange.modify(obf).withDeobfName(((ClassEntry) data).getFullName())); |
| 843 | if (!vc.canProceed()) return; | 839 | } else { |
| 844 | this.controller.sendPacket(new RenameC2SPacket(obf, ((ClassEntry) data).getFullName(), false)); | 840 | throw new IllegalStateException(String.format("unhandled rename object data: '%s'", data)); |
| 845 | } | 841 | } |
| 846 | } | 842 | } |
| 847 | 843 | ||
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java index 2b75655a..4a15b418 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java | |||
| @@ -18,6 +18,7 @@ import java.io.IOException; | |||
| 18 | import java.nio.file.Path; | 18 | import java.nio.file.Path; |
| 19 | import java.util.Collection; | 19 | import java.util.Collection; |
| 20 | import java.util.List; | 20 | import java.util.List; |
| 21 | import java.util.Objects; | ||
| 21 | import java.util.Set; | 22 | import java.util.Set; |
| 22 | import java.util.concurrent.CompletableFuture; | 23 | import java.util.concurrent.CompletableFuture; |
| 23 | import java.util.concurrent.ExecutionException; | 24 | import java.util.concurrent.ExecutionException; |
| @@ -39,10 +40,12 @@ import cuchaz.enigma.classprovider.ClasspathClassProvider; | |||
| 39 | import cuchaz.enigma.gui.config.NetConfig; | 40 | import cuchaz.enigma.gui.config.NetConfig; |
| 40 | import cuchaz.enigma.gui.config.UiConfig; | 41 | import cuchaz.enigma.gui.config.UiConfig; |
| 41 | import cuchaz.enigma.gui.dialog.ProgressDialog; | 42 | import cuchaz.enigma.gui.dialog.ProgressDialog; |
| 43 | import cuchaz.enigma.gui.newabstraction.EntryValidation; | ||
| 42 | import cuchaz.enigma.gui.stats.StatsGenerator; | 44 | import cuchaz.enigma.gui.stats.StatsGenerator; |
| 43 | import cuchaz.enigma.gui.stats.StatsMember; | 45 | import cuchaz.enigma.gui.stats.StatsMember; |
| 44 | import cuchaz.enigma.gui.util.History; | 46 | import cuchaz.enigma.gui.util.History; |
| 45 | import cuchaz.enigma.network.*; | 47 | import cuchaz.enigma.network.*; |
| 48 | import cuchaz.enigma.network.packet.EntryChangeC2SPacket; | ||
| 46 | import cuchaz.enigma.network.packet.LoginC2SPacket; | 49 | import cuchaz.enigma.network.packet.LoginC2SPacket; |
| 47 | import cuchaz.enigma.network.packet.Packet; | 50 | import cuchaz.enigma.network.packet.Packet; |
| 48 | import cuchaz.enigma.source.DecompiledClassSource; | 51 | import cuchaz.enigma.source.DecompiledClassSource; |
| @@ -62,6 +65,7 @@ import cuchaz.enigma.translation.representation.entry.FieldEntry; | |||
| 62 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | 65 | import cuchaz.enigma.translation.representation.entry.MethodEntry; |
| 63 | import cuchaz.enigma.utils.I18n; | 66 | import cuchaz.enigma.utils.I18n; |
| 64 | import cuchaz.enigma.utils.Utils; | 67 | import cuchaz.enigma.utils.Utils; |
| 68 | import cuchaz.enigma.utils.validation.PrintValidatable; | ||
| 65 | import cuchaz.enigma.utils.validation.ValidationContext; | 69 | import cuchaz.enigma.utils.validation.ValidationContext; |
| 66 | 70 | ||
| 67 | public class GuiController implements ClientPacketHandler { | 71 | public class GuiController implements ClientPacketHandler { |
| @@ -401,19 +405,6 @@ public class GuiController implements ClientPacketHandler { | |||
| 401 | }); | 405 | }); |
| 402 | } | 406 | } |
| 403 | 407 | ||
| 404 | public void onModifierChanged(ValidationContext vc, Entry<?> entry, AccessModifier modifier) { | ||
| 405 | EntryRemapper mapper = project.getMapper(); | ||
| 406 | |||
| 407 | EntryMapping mapping = mapper.getDeobfMapping(entry); | ||
| 408 | if (mapping != null) { | ||
| 409 | mapper.mapFromObf(vc, entry, new EntryMapping(mapping.getTargetName(), modifier)); | ||
| 410 | } else { | ||
| 411 | mapper.mapFromObf(vc, entry, new EntryMapping(entry.getName(), modifier)); | ||
| 412 | } | ||
| 413 | |||
| 414 | chp.invalidateMapped(); | ||
| 415 | } | ||
| 416 | |||
| 417 | public StructureTreeNode getClassStructure(ClassEntry entry, StructureTreeOptions options) { | 408 | public StructureTreeNode getClassStructure(ClassEntry entry, StructureTreeOptions options) { |
| 418 | StructureTreeNode rootNode = new StructureTreeNode(this.project, entry, entry); | 409 | StructureTreeNode rootNode = new StructureTreeNode(this.project, entry, entry); |
| 419 | rootNode.load(this.project, options); | 410 | rootNode.load(this.project, options); |
| @@ -471,74 +462,54 @@ public class GuiController implements ClientPacketHandler { | |||
| 471 | } | 462 | } |
| 472 | 463 | ||
| 473 | @Override | 464 | @Override |
| 474 | public void rename(ValidationContext vc, EntryReference<Entry<?>, Entry<?>> reference, String newName, boolean refreshClassTree) { | 465 | public boolean applyChangeFromServer(EntryChange<?> change) { |
| 475 | rename(vc, reference, newName, refreshClassTree, false); | 466 | ValidationContext vc = new ValidationContext(); |
| 476 | } | 467 | vc.setActiveElement(PrintValidatable.INSTANCE); |
| 477 | 468 | this.applyChange0(vc, change); | |
| 478 | public void rename(ValidationContext vc, EntryReference<Entry<?>, Entry<?>> reference, String newName, boolean refreshClassTree, boolean validateOnly) { | ||
| 479 | Entry<?> entry = reference.getNameableEntry(); | ||
| 480 | EntryMapping previous = project.getMapper().getDeobfMapping(entry); | ||
| 481 | project.getMapper().mapFromObf(vc, entry, previous != null ? previous.withName(newName) : new EntryMapping(newName), true, validateOnly); | ||
| 482 | gui.showStructure(gui.getActiveEditor()); | 469 | gui.showStructure(gui.getActiveEditor()); |
| 483 | 470 | ||
| 484 | if (validateOnly || !vc.canProceed()) return; | 471 | return vc.canProceed(); |
| 472 | } | ||
| 485 | 473 | ||
| 486 | if (refreshClassTree && reference.entry instanceof ClassEntry && !((ClassEntry) reference.entry).isInnerClass()) | 474 | public void validateChange(ValidationContext vc, EntryChange<?> change) { |
| 487 | this.gui.moveClassTree(reference.entry, newName); | 475 | if (change.getDeobfName().isSet()) { |
| 476 | EntryValidation.validateRename(vc, this.project, change.getTarget(), change.getDeobfName().getNewValue()); | ||
| 477 | } | ||
| 488 | 478 | ||
| 489 | chp.invalidateMapped(); | 479 | if (change.getJavadoc().isSet()) { |
| 480 | EntryValidation.validateJavadoc(vc, change.getJavadoc().getNewValue()); | ||
| 481 | } | ||
| 490 | } | 482 | } |
| 491 | 483 | ||
| 492 | @Override | 484 | public void applyChange(ValidationContext vc, EntryChange<?> change) { |
| 493 | public void removeMapping(ValidationContext vc, EntryReference<Entry<?>, Entry<?>> reference) { | 485 | this.applyChange0(vc, change); |
| 494 | project.getMapper().removeByObf(vc, reference.getNameableEntry()); | ||
| 495 | gui.showStructure(gui.getActiveEditor()); | 486 | gui.showStructure(gui.getActiveEditor()); |
| 496 | |||
| 497 | if (!vc.canProceed()) return; | 487 | if (!vc.canProceed()) return; |
| 498 | 488 | this.sendPacket(new EntryChangeC2SPacket(change)); | |
| 499 | if (reference.entry instanceof ClassEntry) | ||
| 500 | this.gui.moveClassTree(reference.entry, false, true); | ||
| 501 | |||
| 502 | chp.invalidateMapped(); | ||
| 503 | } | 489 | } |
| 504 | 490 | ||
| 505 | @Override | 491 | private void applyChange0(ValidationContext vc, EntryChange<?> change) { |
| 506 | public void changeDocs(ValidationContext vc, EntryReference<Entry<?>, Entry<?>> reference, String updatedDocs) { | 492 | validateChange(vc, change); |
| 507 | changeDocs(vc, reference, updatedDocs, false); | 493 | if (!vc.canProceed()) return; |
| 508 | } | ||
| 509 | |||
| 510 | public void changeDocs(ValidationContext vc, EntryReference<Entry<?>, Entry<?>> reference, String updatedDocs, boolean validateOnly) { | ||
| 511 | changeDoc(vc, reference.entry, updatedDocs, validateOnly); | ||
| 512 | |||
| 513 | if (validateOnly || !vc.canProceed()) return; | ||
| 514 | 494 | ||
| 515 | chp.invalidateJavadoc(reference.getLocationClassEntry()); | 495 | Entry<?> target = change.getTarget(); |
| 516 | } | 496 | EntryMapping prev = this.project.getMapper().getDeobfMapping(target); |
| 497 | EntryMapping mapping = EntryUtil.applyChange(vc, this.project.getMapper(), change); | ||
| 517 | 498 | ||
| 518 | private void changeDoc(ValidationContext vc, Entry<?> obfEntry, String newDoc, boolean validateOnly) { | 499 | boolean renamed = !change.getDeobfName().isUnchanged(); |
| 519 | EntryRemapper mapper = project.getMapper(); | ||
| 520 | 500 | ||
| 521 | EntryMapping deobfMapping = mapper.getDeobfMapping(obfEntry); | 501 | if (renamed && target instanceof ClassEntry && !((ClassEntry) target).isInnerClass()) { |
| 522 | if (deobfMapping == null) { | 502 | this.gui.moveClassTree(target, prev.targetName() == null, mapping.targetName() == null); |
| 523 | deobfMapping = new EntryMapping(mapper.deobfuscate(obfEntry).getName()); | ||
| 524 | } | 503 | } |
| 525 | 504 | ||
| 526 | mapper.mapFromObf(vc, obfEntry, deobfMapping.withDocs(newDoc), false, validateOnly); | 505 | if (!Objects.equals(prev.targetName(), mapping.targetName())) { |
| 527 | } | 506 | this.chp.invalidateMapped(); |
| 507 | } | ||
| 528 | 508 | ||
| 529 | @Override | 509 | if (!Objects.equals(prev.javadoc(), mapping.javadoc())) { |
| 530 | public void markAsDeobfuscated(ValidationContext vc, EntryReference<Entry<?>, Entry<?>> reference) { | 510 | this.chp.invalidateJavadoc(target.getTopLevelClass()); |
| 531 | EntryRemapper mapper = project.getMapper(); | 511 | } |
| 532 | Entry<?> entry = reference.getNameableEntry(); | ||
| 533 | mapper.mapFromObf(vc, entry, new EntryMapping(mapper.deobfuscate(entry).getName())); | ||
| 534 | gui.showStructure(gui.getActiveEditor()); | 512 | gui.showStructure(gui.getActiveEditor()); |
| 535 | |||
| 536 | if (!vc.canProceed()) return; | ||
| 537 | |||
| 538 | if (reference.entry instanceof ClassEntry && !((ClassEntry) reference.entry).isInnerClass()) | ||
| 539 | this.gui.moveClassTree(reference.entry, true, false); | ||
| 540 | |||
| 541 | chp.invalidateMapped(); | ||
| 542 | } | 513 | } |
| 543 | 514 | ||
| 544 | public void openStats(Set<StatsMember> includedMembers, String topLevelPackage, boolean includeSynthetic) { | 515 | public void openStats(Set<StatsMember> includedMembers, String topLevelPackage, boolean includeSynthetic) { |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/JavadocDialog.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/JavadocDialog.java index 2fc67476..9470e11c 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/JavadocDialog.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/JavadocDialog.java | |||
| @@ -29,23 +29,22 @@ import cuchaz.enigma.gui.config.UiConfig; | |||
| 29 | import cuchaz.enigma.gui.elements.ValidatableTextArea; | 29 | import cuchaz.enigma.gui.elements.ValidatableTextArea; |
| 30 | import cuchaz.enigma.gui.util.GuiUtil; | 30 | import cuchaz.enigma.gui.util.GuiUtil; |
| 31 | import cuchaz.enigma.gui.util.ScaleUtil; | 31 | import cuchaz.enigma.gui.util.ScaleUtil; |
| 32 | import cuchaz.enigma.network.packet.ChangeDocsC2SPacket; | 32 | import cuchaz.enigma.translation.mapping.EntryChange; |
| 33 | import cuchaz.enigma.translation.representation.entry.Entry; | 33 | import cuchaz.enigma.translation.representation.entry.Entry; |
| 34 | import cuchaz.enigma.utils.I18n; | 34 | import cuchaz.enigma.utils.I18n; |
| 35 | import cuchaz.enigma.utils.validation.Message; | ||
| 36 | import cuchaz.enigma.utils.validation.ValidationContext; | 35 | import cuchaz.enigma.utils.validation.ValidationContext; |
| 37 | 36 | ||
| 38 | public class JavadocDialog { | 37 | public class JavadocDialog { |
| 39 | 38 | ||
| 40 | private final JDialog ui; | 39 | private final JDialog ui; |
| 41 | private final GuiController controller; | 40 | private final GuiController controller; |
| 42 | private final EntryReference<Entry<?>, Entry<?>> entry; | 41 | private final Entry<?> entry; |
| 43 | 42 | ||
| 44 | private final ValidatableTextArea text; | 43 | private final ValidatableTextArea text; |
| 45 | 44 | ||
| 46 | private final ValidationContext vc = new ValidationContext(); | 45 | private final ValidationContext vc = new ValidationContext(); |
| 47 | 46 | ||
| 48 | private JavadocDialog(JFrame parent, GuiController controller, EntryReference<Entry<?>, Entry<?>> entry, String preset) { | 47 | private JavadocDialog(JFrame parent, GuiController controller, Entry<?> entry, String preset) { |
| 49 | this.ui = new JDialog(parent, I18n.translate("javadocs.edit")); | 48 | this.ui = new JDialog(parent, I18n.translate("javadocs.edit")); |
| 50 | this.controller = controller; | 49 | this.controller = controller; |
| 51 | this.entry = entry; | 50 | this.entry = entry; |
| @@ -161,28 +160,21 @@ public class JavadocDialog { | |||
| 161 | public void validate() { | 160 | public void validate() { |
| 162 | vc.setActiveElement(text); | 161 | vc.setActiveElement(text); |
| 163 | 162 | ||
| 164 | if (text.getText().contains("*/")) { | 163 | controller.validateChange(vc, EntryChange.modify(entry).withJavadoc(text.getText())); |
| 165 | vc.raise(Message.ILLEGAL_DOC_COMMENT_END); | ||
| 166 | } | ||
| 167 | |||
| 168 | controller.changeDocs(vc, entry, text.getText(), true); | ||
| 169 | } | 164 | } |
| 170 | 165 | ||
| 171 | public void save() { | 166 | public void save() { |
| 172 | vc.setActiveElement(text); | 167 | vc.setActiveElement(text); |
| 173 | controller.changeDocs(vc, entry, text.getText().trim().isEmpty() ? null : text.getText()); | ||
| 174 | |||
| 175 | if (!vc.canProceed()) return; | ||
| 176 | 168 | ||
| 177 | controller.sendPacket(new ChangeDocsC2SPacket(entry.getNameableEntry(), text.getText())); | 169 | controller.applyChange(vc, EntryChange.modify(entry).withJavadoc(text.getText())); |
| 178 | } | 170 | } |
| 179 | 171 | ||
| 180 | public static void show(JFrame parent, GuiController controller, EntryReference<Entry<?>, Entry<?>> entry) { | 172 | public static void show(JFrame parent, GuiController controller, EntryReference<Entry<?>, Entry<?>> entry) { |
| 181 | EntryReference<Entry<?>, Entry<?>> translatedReference = controller.project.getMapper().deobfuscate(entry); | 173 | EntryReference<Entry<?>, Entry<?>> translatedReference = controller.project.getMapper().deobfuscate(entry); |
| 182 | String text = Strings.nullToEmpty(translatedReference.entry.getJavadocs()); | 174 | String text = Strings.nullToEmpty(translatedReference.entry.getJavadocs()); |
| 183 | 175 | ||
| 184 | JavadocDialog dialog = new JavadocDialog(parent, controller, entry, text); | 176 | JavadocDialog dialog = new JavadocDialog(parent, controller, entry.getNameableEntry(), text); |
| 185 | dialog.ui.doLayout(); | 177 | //dialog.ui.doLayout(); |
| 186 | dialog.ui.setVisible(true); | 178 | dialog.ui.setVisible(true); |
| 187 | dialog.text.grabFocus(); | 179 | dialog.text.grabFocus(); |
| 188 | } | 180 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/newabstraction/EntryValidation.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/newabstraction/EntryValidation.java new file mode 100644 index 00000000..898529a4 --- /dev/null +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/newabstraction/EntryValidation.java | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | package cuchaz.enigma.gui.newabstraction; | ||
| 2 | |||
| 3 | import cuchaz.enigma.EnigmaProject; | ||
| 4 | import cuchaz.enigma.translation.representation.entry.Entry; | ||
| 5 | import cuchaz.enigma.utils.validation.Message; | ||
| 6 | import cuchaz.enigma.utils.validation.ValidationContext; | ||
| 7 | |||
| 8 | public class EntryValidation { | ||
| 9 | |||
| 10 | public static boolean validateJavadoc(ValidationContext vc, String javadoc) { | ||
| 11 | if (javadoc.contains("*/")) { | ||
| 12 | vc.raise(Message.ILLEGAL_DOC_COMMENT_END); | ||
| 13 | return false; | ||
| 14 | } | ||
| 15 | return true; | ||
| 16 | } | ||
| 17 | |||
| 18 | public static boolean validateRename(ValidationContext vc, EnigmaProject p, Entry<?> entry, String newName) { | ||
| 19 | return p.getMapper().getValidator().validateRename(vc, entry, newName); | ||
| 20 | } | ||
| 21 | |||
| 22 | } | ||
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/DeobfPanel.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/DeobfPanel.java index 5b7882b0..cd09c1a1 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/DeobfPanel.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/DeobfPanel.java | |||
| @@ -22,7 +22,7 @@ public class DeobfPanel extends JPanel { | |||
| 22 | 22 | ||
| 23 | this.deobfClasses = new ClassSelector(gui, ClassSelector.DEOBF_CLASS_COMPARATOR, true); | 23 | this.deobfClasses = new ClassSelector(gui, ClassSelector.DEOBF_CLASS_COMPARATOR, true); |
| 24 | this.deobfClasses.setSelectionListener(gui.getController()::navigateTo); | 24 | this.deobfClasses.setSelectionListener(gui.getController()::navigateTo); |
| 25 | this.deobfClasses.setRenameSelectionListener(gui::onPanelRename); | 25 | this.deobfClasses.setRenameSelectionListener(gui::onRenameFromClassTree); |
| 26 | 26 | ||
| 27 | this.setLayout(new BorderLayout()); | 27 | this.setLayout(new BorderLayout()); |
| 28 | this.add(this.title, BorderLayout.NORTH); | 28 | this.add(this.title, BorderLayout.NORTH); |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/IdentifierPanel.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/IdentifierPanel.java index 3bae94c3..4ae0b7be 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/IdentifierPanel.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/IdentifierPanel.java | |||
| @@ -15,7 +15,6 @@ import javax.swing.JLabel; | |||
| 15 | import javax.swing.JPanel; | 15 | import javax.swing.JPanel; |
| 16 | 16 | ||
| 17 | import cuchaz.enigma.EnigmaProject; | 17 | import cuchaz.enigma.EnigmaProject; |
| 18 | import cuchaz.enigma.analysis.EntryReference; | ||
| 19 | import cuchaz.enigma.gui.EditableType; | 18 | import cuchaz.enigma.gui.EditableType; |
| 20 | import cuchaz.enigma.gui.Gui; | 19 | import cuchaz.enigma.gui.Gui; |
| 21 | import cuchaz.enigma.gui.elements.ConvertingTextField; | 20 | import cuchaz.enigma.gui.elements.ConvertingTextField; |
| @@ -23,8 +22,8 @@ import cuchaz.enigma.gui.events.ConvertingTextFieldListener; | |||
| 23 | import cuchaz.enigma.gui.util.GridBagConstraintsBuilder; | 22 | import cuchaz.enigma.gui.util.GridBagConstraintsBuilder; |
| 24 | import cuchaz.enigma.gui.util.GuiUtil; | 23 | import cuchaz.enigma.gui.util.GuiUtil; |
| 25 | import cuchaz.enigma.gui.util.ScaleUtil; | 24 | import cuchaz.enigma.gui.util.ScaleUtil; |
| 26 | import cuchaz.enigma.network.packet.RenameC2SPacket; | ||
| 27 | import cuchaz.enigma.translation.mapping.AccessModifier; | 25 | import cuchaz.enigma.translation.mapping.AccessModifier; |
| 26 | import cuchaz.enigma.translation.mapping.EntryChange; | ||
| 28 | import cuchaz.enigma.translation.mapping.EntryMapping; | 27 | import cuchaz.enigma.translation.mapping.EntryMapping; |
| 29 | import cuchaz.enigma.translation.representation.entry.*; | 28 | import cuchaz.enigma.translation.representation.entry.*; |
| 30 | import cuchaz.enigma.utils.I18n; | 29 | import cuchaz.enigma.utils.I18n; |
| @@ -76,7 +75,7 @@ public class IdentifierPanel { | |||
| 76 | } | 75 | } |
| 77 | 76 | ||
| 78 | private void onModifierChanged(AccessModifier modifier) { | 77 | private void onModifierChanged(AccessModifier modifier) { |
| 79 | gui.validateImmediateAction(vc -> this.gui.getController().onModifierChanged(vc, entry, modifier)); | 78 | gui.validateImmediateAction(vc -> this.gui.getController().applyChange(vc, EntryChange.modify(entry).withAccess(modifier))); |
| 80 | } | 79 | } |
| 81 | 80 | ||
| 82 | public void refreshReference() { | 81 | public void refreshReference() { |
| @@ -176,13 +175,12 @@ public class IdentifierPanel { | |||
| 176 | } | 175 | } |
| 177 | 176 | ||
| 178 | private void validateRename(String newName) { | 177 | private void validateRename(String newName) { |
| 179 | gui.getController().rename(vc, new EntryReference<>(entry, deobfEntry.getName()), newName, true, true); | 178 | gui.getController().validateChange(vc, EntryChange.modify(entry).withDeobfName(newName)); |
| 180 | } | 179 | } |
| 181 | 180 | ||
| 182 | private void doRename(String newName) { | 181 | private void doRename(String newName) { |
| 183 | gui.getController().rename(vc, new EntryReference<>(entry, deobfEntry.getName()), newName, true); | 182 | EntryChange<? extends Entry<?>> change = EntryChange.modify(entry).withDeobfName(newName); |
| 184 | if (!vc.canProceed()) return; | 183 | gui.getController().applyChange(vc, change); |
| 185 | gui.getController().sendPacket(new RenameC2SPacket(entry, newName, true)); | ||
| 186 | } | 184 | } |
| 187 | 185 | ||
| 188 | public void retranslateUi() { | 186 | public void retranslateUi() { |
| @@ -277,12 +275,7 @@ public class IdentifierPanel { | |||
| 277 | 275 | ||
| 278 | JComboBox<AccessModifier> combo = new JComboBox<>(AccessModifier.values()); | 276 | JComboBox<AccessModifier> combo = new JComboBox<>(AccessModifier.values()); |
| 279 | EntryMapping mapping = project.getMapper().getDeobfMapping(e); | 277 | EntryMapping mapping = project.getMapper().getDeobfMapping(e); |
| 280 | 278 | combo.setSelectedIndex(mapping.accessModifier().ordinal()); | |
| 281 | if (mapping != null) { | ||
| 282 | combo.setSelectedIndex(mapping.getAccessModifier().ordinal()); | ||
| 283 | } else { | ||
| 284 | combo.setSelectedIndex(AccessModifier.UNCHANGED.ordinal()); | ||
| 285 | } | ||
| 286 | 279 | ||
| 287 | if (this.gui.isEditable(type)) { | 280 | if (this.gui.isEditable(type)) { |
| 288 | combo.addItemListener(event -> { | 281 | combo.addItemListener(event -> { |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/ObfPanel.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/ObfPanel.java index b384968d..7783843d 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/ObfPanel.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/ObfPanel.java | |||
| @@ -33,7 +33,7 @@ public class ObfPanel extends JPanel { | |||
| 33 | 33 | ||
| 34 | this.obfClasses = new ClassSelector(gui, obfClassComparator, false); | 34 | this.obfClasses = new ClassSelector(gui, obfClassComparator, false); |
| 35 | this.obfClasses.setSelectionListener(gui.getController()::navigateTo); | 35 | this.obfClasses.setSelectionListener(gui.getController()::navigateTo); |
| 36 | this.obfClasses.setRenameSelectionListener(gui::onPanelRename); | 36 | this.obfClasses.setRenameSelectionListener(gui::onRenameFromClassTree); |
| 37 | 37 | ||
| 38 | this.setLayout(new BorderLayout()); | 38 | this.setLayout(new BorderLayout()); |
| 39 | this.add(this.title, BorderLayout.NORTH); | 39 | this.add(this.title, BorderLayout.NORTH); |
diff --git a/enigma/src/main/java/cuchaz/enigma/source/DecompiledClassSource.java b/enigma/src/main/java/cuchaz/enigma/source/DecompiledClassSource.java index 9ac611f5..5f371a58 100644 --- a/enigma/src/main/java/cuchaz/enigma/source/DecompiledClassSource.java +++ b/enigma/src/main/java/cuchaz/enigma/source/DecompiledClassSource.java | |||
| @@ -79,7 +79,7 @@ public class DecompiledClassSource { | |||
| 79 | return null; | 79 | return null; |
| 80 | } | 80 | } |
| 81 | 81 | ||
| 82 | private Optional<String> proposeName(EnigmaProject project, Entry<?> entry) { | 82 | public static Optional<String> proposeName(EnigmaProject project, Entry<?> entry) { |
| 83 | EnigmaServices services = project.getEnigma().getServices(); | 83 | EnigmaServices services = project.getEnigma().getServices(); |
| 84 | 84 | ||
| 85 | return services.get(NameProposalService.TYPE).stream().flatMap(nameProposalService -> { | 85 | return services.get(NameProposalService.TYPE).stream().flatMap(nameProposalService -> { |
diff --git a/enigma/src/main/java/cuchaz/enigma/source/cfr/EnigmaDumper.java b/enigma/src/main/java/cuchaz/enigma/source/cfr/EnigmaDumper.java index b85851fa..4e8940ad 100644 --- a/enigma/src/main/java/cuchaz/enigma/source/cfr/EnigmaDumper.java +++ b/enigma/src/main/java/cuchaz/enigma/source/cfr/EnigmaDumper.java | |||
| @@ -148,7 +148,7 @@ public class EnigmaDumper extends StringStreamDumper { | |||
| 148 | continue; | 148 | continue; |
| 149 | } | 149 | } |
| 150 | 150 | ||
| 151 | String javaDoc = mapping.getJavadoc(); | 151 | String javaDoc = mapping.javadoc(); |
| 152 | if (javaDoc != null) { | 152 | if (javaDoc != null) { |
| 153 | recordComponentDocs.add(String.format("@param %s %s", field.getFieldName(), javaDoc)); | 153 | recordComponentDocs.add(String.format("@param %s %s", field.getFieldName(), javaDoc)); |
| 154 | } | 154 | } |
| @@ -159,7 +159,7 @@ public class EnigmaDumper extends StringStreamDumper { | |||
| 159 | 159 | ||
| 160 | String javadoc = null; | 160 | String javadoc = null; |
| 161 | if (mapping != null) { | 161 | if (mapping != null) { |
| 162 | javadoc = mapping.getJavadoc(); | 162 | javadoc = mapping.javadoc(); |
| 163 | } | 163 | } |
| 164 | 164 | ||
| 165 | if (javadoc != null || !recordComponentDocs.isEmpty()) { | 165 | if (javadoc != null || !recordComponentDocs.isEmpty()) { |
| @@ -191,7 +191,7 @@ public class EnigmaDumper extends StringStreamDumper { | |||
| 191 | MethodEntry methodEntry = getMethodEntry(method); | 191 | MethodEntry methodEntry = getMethodEntry(method); |
| 192 | EntryMapping mapping = mapper.getDeobfMapping(methodEntry); | 192 | EntryMapping mapping = mapper.getDeobfMapping(methodEntry); |
| 193 | if (mapping != null) { | 193 | if (mapping != null) { |
| 194 | String javadoc = mapping.getJavadoc(); | 194 | String javadoc = mapping.javadoc(); |
| 195 | if (javadoc != null) { | 195 | if (javadoc != null) { |
| 196 | lines.addAll(Arrays.asList(javadoc.split("\\R"))); | 196 | lines.addAll(Arrays.asList(javadoc.split("\\R"))); |
| 197 | } | 197 | } |
| @@ -204,9 +204,9 @@ public class EnigmaDumper extends StringStreamDumper { | |||
| 204 | if (each instanceof LocalVariableEntry) { | 204 | if (each instanceof LocalVariableEntry) { |
| 205 | EntryMapping paramMapping = mapper.getDeobfMapping(each); | 205 | EntryMapping paramMapping = mapper.getDeobfMapping(each); |
| 206 | if (paramMapping != null) { | 206 | if (paramMapping != null) { |
| 207 | String javadoc = paramMapping.getJavadoc(); | 207 | String javadoc = paramMapping.javadoc(); |
| 208 | if (javadoc != null) { | 208 | if (javadoc != null) { |
| 209 | lines.addAll(Arrays.asList(("@param " + paramMapping.getTargetName() + " " + javadoc).split("\\R"))); | 209 | lines.addAll(Arrays.asList(("@param " + paramMapping.targetName() + " " + javadoc).split("\\R"))); |
| 210 | } | 210 | } |
| 211 | } | 211 | } |
| 212 | } | 212 | } |
| @@ -230,7 +230,7 @@ public class EnigmaDumper extends StringStreamDumper { | |||
| 230 | if (mapper != null && !recordComponent) { | 230 | if (mapper != null && !recordComponent) { |
| 231 | EntryMapping mapping = mapper.getDeobfMapping(getFieldEntry(owner, field.getFieldName(), field.getDescriptor())); | 231 | EntryMapping mapping = mapper.getDeobfMapping(getFieldEntry(owner, field.getFieldName(), field.getDescriptor())); |
| 232 | if (mapping != null) { | 232 | if (mapping != null) { |
| 233 | String javadoc = mapping.getJavadoc(); | 233 | String javadoc = mapping.javadoc(); |
| 234 | if (javadoc != null) { | 234 | if (javadoc != null) { |
| 235 | print("/**").newln(); | 235 | print("/**").newln(); |
| 236 | for (String line : javadoc.split("\\R")) { | 236 | for (String line : javadoc.split("\\R")) { |
diff --git a/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/AddJavadocsAstTransform.java b/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/AddJavadocsAstTransform.java index 70fc8c6b..1e5beb1e 100644 --- a/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/AddJavadocsAstTransform.java +++ b/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/AddJavadocsAstTransform.java | |||
| @@ -47,16 +47,17 @@ public final class AddJavadocsAstTransform implements IAstTransform { | |||
| 47 | 47 | ||
| 48 | private <T extends AstNode> Comment[] getComments(T node, Function<T, Entry<?>> retriever) { | 48 | private <T extends AstNode> Comment[] getComments(T node, Function<T, Entry<?>> retriever) { |
| 49 | final EntryMapping mapping = remapper.getDeobfMapping(retriever.apply(node)); | 49 | final EntryMapping mapping = remapper.getDeobfMapping(retriever.apply(node)); |
| 50 | final String docs = mapping == null ? null : Strings.emptyToNull(mapping.getJavadoc()); | 50 | final String docs = Strings.emptyToNull(mapping.javadoc()); |
| 51 | return docs == null ? null : Stream.of(docs.split("\\R")).map(st -> new Comment(st, | 51 | return docs == null ? null : Stream.of(docs.split("\\R")).map(st -> new Comment(st, |
| 52 | CommentType.Documentation)).toArray(Comment[]::new); | 52 | CommentType.Documentation)).toArray(Comment[]::new); |
| 53 | } | 53 | } |
| 54 | 54 | ||
| 55 | private Comment[] getParameterComments(ParameterDeclaration node, Function<ParameterDeclaration, Entry<?>> retriever) { | 55 | private Comment[] getParameterComments(ParameterDeclaration node, Function<ParameterDeclaration, Entry<?>> retriever) { |
| 56 | final EntryMapping mapping = remapper.getDeobfMapping(retriever.apply(node)); | 56 | Entry<?> entry = retriever.apply(node); |
| 57 | final EntryMapping mapping = remapper.getDeobfMapping(entry); | ||
| 57 | final Comment[] ret = getComments(node, retriever); | 58 | final Comment[] ret = getComments(node, retriever); |
| 58 | if (ret != null) { | 59 | if (ret != null) { |
| 59 | final String paramPrefix = "@param " + mapping.getTargetName() + " "; | 60 | final String paramPrefix = "@param " + (mapping.targetName() != null ? mapping.targetName() : entry.getName()) + " "; |
| 60 | final String indent = Strings.repeat(" ", paramPrefix.length()); | 61 | final String indent = Strings.repeat(" ", paramPrefix.length()); |
| 61 | ret[0].setContent(paramPrefix + ret[0].getContent()); | 62 | ret[0].setContent(paramPrefix + ret[0].getContent()); |
| 62 | for (int i = 1; i < ret.length; i++) { | 63 | for (int i = 1; i < ret.length; i++) { |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryChange.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryChange.java new file mode 100644 index 00000000..b5ec8552 --- /dev/null +++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryChange.java | |||
| @@ -0,0 +1,97 @@ | |||
| 1 | package cuchaz.enigma.translation.mapping; | ||
| 2 | |||
| 3 | import java.util.Objects; | ||
| 4 | import java.util.Optional; | ||
| 5 | |||
| 6 | import javax.annotation.Nullable; | ||
| 7 | |||
| 8 | import cuchaz.enigma.EnigmaProject; | ||
| 9 | import cuchaz.enigma.source.DecompiledClassSource; | ||
| 10 | import cuchaz.enigma.translation.representation.entry.Entry; | ||
| 11 | import cuchaz.enigma.utils.TristateChange; | ||
| 12 | |||
| 13 | public final class EntryChange<E extends Entry<?>> { | ||
| 14 | |||
| 15 | private final E target; | ||
| 16 | private final TristateChange<String> deobfName; | ||
| 17 | private final TristateChange<String> javadoc; | ||
| 18 | private final TristateChange<AccessModifier> access; | ||
| 19 | |||
| 20 | private EntryChange(E target, TristateChange<String> deobfName, TristateChange<String> javadoc, TristateChange<AccessModifier> access) { | ||
| 21 | this.target = target; | ||
| 22 | this.deobfName = deobfName; | ||
| 23 | this.javadoc = javadoc; | ||
| 24 | this.access = access; | ||
| 25 | } | ||
| 26 | |||
| 27 | public static <E extends Entry<?>> EntryChange<E> modify(E target) { | ||
| 28 | return new EntryChange<>(target, TristateChange.unchanged(), TristateChange.unchanged(), TristateChange.unchanged()); | ||
| 29 | } | ||
| 30 | |||
| 31 | public EntryChange<E> withDeobfName(String name) { | ||
| 32 | return new EntryChange<>(this.target, TristateChange.set(name), this.javadoc, this.access); | ||
| 33 | } | ||
| 34 | |||
| 35 | public EntryChange<E> withDefaultDeobfName(@Nullable EnigmaProject project) { | ||
| 36 | Optional<String> proposed = project != null ? DecompiledClassSource.proposeName(project, this.target) : Optional.empty(); | ||
| 37 | return this.withDeobfName(proposed.orElse(this.target.getName())); | ||
| 38 | } | ||
| 39 | |||
| 40 | public EntryChange<E> clearDeobfName() { | ||
| 41 | return new EntryChange<>(this.target, TristateChange.reset(), this.javadoc, this.access); | ||
| 42 | } | ||
| 43 | |||
| 44 | public EntryChange<E> withJavadoc(String javadoc) { | ||
| 45 | return new EntryChange<>(this.target, this.deobfName, TristateChange.set(javadoc), this.access); | ||
| 46 | } | ||
| 47 | |||
| 48 | public EntryChange<E> clearJavadoc() { | ||
| 49 | return new EntryChange<>(this.target, this.deobfName, TristateChange.reset(), this.access); | ||
| 50 | } | ||
| 51 | |||
| 52 | public EntryChange<E> withAccess(AccessModifier access) { | ||
| 53 | return new EntryChange<>(this.target, this.deobfName, this.javadoc, TristateChange.set(access)); | ||
| 54 | } | ||
| 55 | |||
| 56 | public EntryChange<E> clearAccess() { | ||
| 57 | return new EntryChange<>(this.target, this.deobfName, this.javadoc, TristateChange.reset()); | ||
| 58 | } | ||
| 59 | |||
| 60 | public TristateChange<String> getDeobfName() { | ||
| 61 | return this.deobfName; | ||
| 62 | } | ||
| 63 | |||
| 64 | public TristateChange<String> getJavadoc() { | ||
| 65 | return this.javadoc; | ||
| 66 | } | ||
| 67 | |||
| 68 | public TristateChange<AccessModifier> getAccess() { | ||
| 69 | return this.access; | ||
| 70 | } | ||
| 71 | |||
| 72 | public E getTarget() { | ||
| 73 | return this.target; | ||
| 74 | } | ||
| 75 | |||
| 76 | @Override | ||
| 77 | public boolean equals(Object o) { | ||
| 78 | if (this == o) return true; | ||
| 79 | if (!(o instanceof EntryChange)) return false; | ||
| 80 | EntryChange<?> that = (EntryChange<?>) o; | ||
| 81 | return Objects.equals(this.target, that.target) && | ||
| 82 | Objects.equals(this.deobfName, that.deobfName) && | ||
| 83 | Objects.equals(this.javadoc, that.javadoc) && | ||
| 84 | Objects.equals(this.access, that.access); | ||
| 85 | } | ||
| 86 | |||
| 87 | @Override | ||
| 88 | public int hashCode() { | ||
| 89 | return Objects.hash(this.target, this.deobfName, this.javadoc, this.access); | ||
| 90 | } | ||
| 91 | |||
| 92 | @Override | ||
| 93 | public String toString() { | ||
| 94 | return String.format("EntryChange { target: %s, deobfName: %s, javadoc: %s, access: %s }", this.target, this.deobfName, this.javadoc, this.access); | ||
| 95 | } | ||
| 96 | |||
| 97 | } | ||
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryMapping.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryMapping.java index c607817c..e916bf35 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryMapping.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryMapping.java | |||
| @@ -1,49 +1,37 @@ | |||
| 1 | package cuchaz.enigma.translation.mapping; | 1 | package cuchaz.enigma.translation.mapping; |
| 2 | 2 | ||
| 3 | import java.util.Arrays; | ||
| 4 | |||
| 3 | import javax.annotation.Nonnull; | 5 | import javax.annotation.Nonnull; |
| 4 | import javax.annotation.Nullable; | 6 | import javax.annotation.Nullable; |
| 5 | 7 | ||
| 6 | public class EntryMapping { | 8 | public record EntryMapping( |
| 7 | private final String targetName; | 9 | @Nullable String targetName, |
| 8 | private final AccessModifier accessModifier; | 10 | @Nonnull AccessModifier accessModifier, |
| 9 | private final @Nullable String javadoc; | 11 | @Nullable String javadoc |
| 12 | ) { | ||
| 13 | public static final EntryMapping DEFAULT = new EntryMapping(null, AccessModifier.UNCHANGED, null); | ||
| 14 | |||
| 15 | public EntryMapping { | ||
| 16 | if (accessModifier == null) { | ||
| 17 | accessModifier = AccessModifier.UNCHANGED; | ||
| 18 | System.err.println("EntryMapping initialized with 'null' accessModifier, assuming UNCHANGED. Please fix."); | ||
| 19 | Arrays.stream(new Exception().getStackTrace()).skip(1).map("\tat %s"::formatted).forEach(System.err::println); | ||
| 20 | } | ||
| 21 | } | ||
| 10 | 22 | ||
| 11 | public EntryMapping(@Nonnull String targetName) { | 23 | public EntryMapping(@Nullable String targetName) { |
| 12 | this(targetName, AccessModifier.UNCHANGED); | 24 | this(targetName, AccessModifier.UNCHANGED); |
| 13 | } | 25 | } |
| 14 | 26 | ||
| 15 | public EntryMapping(@Nonnull String targetName, @Nullable String javadoc) { | 27 | public EntryMapping(@Nullable String targetName, @Nullable String javadoc) { |
| 16 | this(targetName, AccessModifier.UNCHANGED, javadoc); | 28 | this(targetName, AccessModifier.UNCHANGED, javadoc); |
| 17 | } | 29 | } |
| 18 | 30 | ||
| 19 | public EntryMapping(@Nonnull String targetName, AccessModifier accessModifier) { | 31 | public EntryMapping(@Nullable String targetName, AccessModifier accessModifier) { |
| 20 | this(targetName, accessModifier, null); | 32 | this(targetName, accessModifier, null); |
| 21 | } | 33 | } |
| 22 | 34 | ||
| 23 | public EntryMapping(@Nonnull String targetName, AccessModifier accessModifier, @Nullable String javadoc) { | ||
| 24 | this.targetName = targetName; | ||
| 25 | this.accessModifier = accessModifier; | ||
| 26 | this.javadoc = javadoc; | ||
| 27 | } | ||
| 28 | |||
| 29 | @Nonnull | ||
| 30 | public String getTargetName() { | ||
| 31 | return targetName; | ||
| 32 | } | ||
| 33 | |||
| 34 | @Nonnull | ||
| 35 | public AccessModifier getAccessModifier() { | ||
| 36 | if (accessModifier == null) { | ||
| 37 | return AccessModifier.UNCHANGED; | ||
| 38 | } | ||
| 39 | return accessModifier; | ||
| 40 | } | ||
| 41 | |||
| 42 | @Nullable | ||
| 43 | public String getJavadoc() { | ||
| 44 | return javadoc; | ||
| 45 | } | ||
| 46 | |||
| 47 | public EntryMapping withName(String newName) { | 35 | public EntryMapping withName(String newName) { |
| 48 | return new EntryMapping(newName, accessModifier, javadoc); | 36 | return new EntryMapping(newName, accessModifier, javadoc); |
| 49 | } | 37 | } |
| @@ -55,21 +43,4 @@ public class EntryMapping { | |||
| 55 | public EntryMapping withDocs(String newDocs) { | 43 | public EntryMapping withDocs(String newDocs) { |
| 56 | return new EntryMapping(targetName, accessModifier, newDocs); | 44 | return new EntryMapping(targetName, accessModifier, newDocs); |
| 57 | } | 45 | } |
| 58 | |||
| 59 | @Override | ||
| 60 | public boolean equals(Object obj) { | ||
| 61 | if (obj == this) return true; | ||
| 62 | |||
| 63 | if (obj instanceof EntryMapping) { | ||
| 64 | EntryMapping mapping = (EntryMapping) obj; | ||
| 65 | return mapping.targetName.equals(targetName) && mapping.accessModifier.equals(accessModifier); | ||
| 66 | } | ||
| 67 | |||
| 68 | return false; | ||
| 69 | } | ||
| 70 | |||
| 71 | @Override | ||
| 72 | public int hashCode() { | ||
| 73 | return targetName.hashCode() + accessModifier.hashCode() * 31; | ||
| 74 | } | ||
| 75 | } | 46 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryRemapper.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryRemapper.java index 8b5490e1..0977b742 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryRemapper.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryRemapper.java | |||
| @@ -1,10 +1,11 @@ | |||
| 1 | package cuchaz.enigma.translation.mapping; | 1 | package cuchaz.enigma.translation.mapping; |
| 2 | 2 | ||
| 3 | import java.util.Collection; | 3 | import java.util.Collection; |
| 4 | import java.util.Objects; | ||
| 4 | import java.util.List; | 5 | import java.util.List; |
| 5 | import java.util.stream.Stream; | 6 | import java.util.stream.Stream; |
| 6 | 7 | ||
| 7 | import javax.annotation.Nullable; | 8 | import javax.annotation.Nonnull; |
| 8 | 9 | ||
| 9 | import cuchaz.enigma.analysis.index.JarIndex; | 10 | import cuchaz.enigma.analysis.index.JarIndex; |
| 10 | import cuchaz.enigma.translation.MappingTranslator; | 11 | import cuchaz.enigma.translation.MappingTranslator; |
| @@ -50,15 +51,15 @@ public class EntryRemapper { | |||
| 50 | return new EntryRemapper(index, new HashEntryTree<>()); | 51 | return new EntryRemapper(index, new HashEntryTree<>()); |
| 51 | } | 52 | } |
| 52 | 53 | ||
| 53 | public <E extends Entry<?>> void mapFromObf(ValidationContext vc, E obfuscatedEntry, @Nullable EntryMapping deobfMapping) { | 54 | public void validatePutMapping(ValidationContext vc, Entry<?> obfuscatedEntry, @Nonnull EntryMapping deobfMapping) { |
| 54 | mapFromObf(vc, obfuscatedEntry, deobfMapping, true); | 55 | doPutMapping(vc, obfuscatedEntry, deobfMapping, true); |
| 55 | } | 56 | } |
| 56 | 57 | ||
| 57 | public <E extends Entry<?>> void mapFromObf(ValidationContext vc, E obfuscatedEntry, @Nullable EntryMapping deobfMapping, boolean renaming) { | 58 | public void putMapping(ValidationContext vc, Entry<?> obfuscatedEntry, @Nonnull EntryMapping deobfMapping) { |
| 58 | mapFromObf(vc, obfuscatedEntry, deobfMapping, renaming, false); | 59 | doPutMapping(vc, obfuscatedEntry, deobfMapping, false); |
| 59 | } | 60 | } |
| 60 | 61 | ||
| 61 | public <E extends Entry<?>> void mapFromObf(ValidationContext vc, E obfuscatedEntry, @Nullable EntryMapping deobfMapping, boolean renaming, boolean validateOnly) { | 62 | private void doPutMapping(ValidationContext vc, Entry<?> obfuscatedEntry, @Nonnull EntryMapping deobfMapping, boolean validateOnly) { |
| 62 | if (obfuscatedEntry instanceof FieldEntry) { | 63 | if (obfuscatedEntry instanceof FieldEntry) { |
| 63 | FieldEntry fieldEntry = (FieldEntry) obfuscatedEntry; | 64 | FieldEntry fieldEntry = (FieldEntry) obfuscatedEntry; |
| 64 | ClassEntry classEntry = fieldEntry.getParent(); | 65 | ClassEntry classEntry = fieldEntry.getParent(); |
| @@ -66,25 +67,27 @@ public class EntryRemapper { | |||
| 66 | mapRecordComponentGetter(vc, classEntry, fieldEntry, deobfMapping); | 67 | mapRecordComponentGetter(vc, classEntry, fieldEntry, deobfMapping); |
| 67 | } | 68 | } |
| 68 | 69 | ||
| 69 | Collection<E> resolvedEntries = obfResolver.resolveEntry(obfuscatedEntry, renaming ? ResolutionStrategy.RESOLVE_ROOT : ResolutionStrategy.RESOLVE_CLOSEST); | 70 | boolean renaming = !Objects.equals(getDeobfMapping(obfuscatedEntry).targetName(), deobfMapping.targetName()); |
| 70 | 71 | ||
| 71 | if (renaming && deobfMapping != null) { | 72 | Collection<Entry<?>> resolvedEntries = obfResolver.resolveEntry(obfuscatedEntry, renaming ? ResolutionStrategy.RESOLVE_ROOT : ResolutionStrategy.RESOLVE_CLOSEST); |
| 72 | for (E resolvedEntry : resolvedEntries) { | 73 | |
| 73 | validator.validateRename(vc, resolvedEntry, deobfMapping.getTargetName()); | 74 | if (renaming && deobfMapping.targetName() != null) { |
| 75 | for (Entry<?> resolvedEntry : resolvedEntries) { | ||
| 76 | validator.validateRename(vc, resolvedEntry, deobfMapping.targetName()); | ||
| 74 | } | 77 | } |
| 75 | } | 78 | } |
| 76 | 79 | ||
| 77 | if (validateOnly || !vc.canProceed()) return; | 80 | if (validateOnly || !vc.canProceed()) return; |
| 78 | 81 | ||
| 79 | for (E resolvedEntry : resolvedEntries) { | 82 | for (Entry<?> resolvedEntry : resolvedEntries) { |
| 80 | obfToDeobf.insert(resolvedEntry, deobfMapping); | 83 | if (deobfMapping.equals(EntryMapping.DEFAULT)) { |
| 84 | obfToDeobf.insert(resolvedEntry, null); | ||
| 85 | } else { | ||
| 86 | obfToDeobf.insert(resolvedEntry, deobfMapping); | ||
| 87 | } | ||
| 81 | } | 88 | } |
| 82 | } | 89 | } |
| 83 | 90 | ||
| 84 | public void removeByObf(ValidationContext vc, Entry<?> obfuscatedEntry) { | ||
| 85 | mapFromObf(vc, obfuscatedEntry, null); | ||
| 86 | } | ||
| 87 | |||
| 88 | // A little bit of a hack to also map the getter method for record fields/components. | 91 | // A little bit of a hack to also map the getter method for record fields/components. |
| 89 | private void mapRecordComponentGetter(ValidationContext vc, ClassEntry classEntry, FieldEntry fieldEntry, EntryMapping fieldMapping) { | 92 | private void mapRecordComponentGetter(ValidationContext vc, ClassEntry classEntry, FieldEntry fieldEntry, EntryMapping fieldMapping) { |
| 90 | if (!jarIndex.getEntryIndex().getClassAccess(classEntry).isRecord() || jarIndex.getEntryIndex().getFieldAccess(fieldEntry).isStatic()) { | 93 | if (!jarIndex.getEntryIndex().getClassAccess(classEntry).isRecord() || jarIndex.getEntryIndex().getFieldAccess(fieldEntry).isStatic()) { |
| @@ -107,20 +110,17 @@ public class EntryRemapper { | |||
| 107 | } | 110 | } |
| 108 | 111 | ||
| 109 | if (methodEntry == null && fieldMapping != null) { | 112 | if (methodEntry == null && fieldMapping != null) { |
| 110 | vc.raise(Message.UNKNOWN_RECORD_GETTER, fieldMapping.getTargetName()); | 113 | vc.raise(Message.UNKNOWN_RECORD_GETTER, fieldMapping.targetName()); |
| 111 | return; | 114 | return; |
| 112 | } | 115 | } |
| 113 | 116 | ||
| 114 | mapFromObf(vc, methodEntry, fieldMapping != null ? new EntryMapping(fieldMapping.getTargetName()) : null); | 117 | putMapping(vc, methodEntry, fieldMapping != null ? new EntryMapping(fieldMapping.targetName()) : null); |
| 115 | } | 118 | } |
| 116 | 119 | ||
| 117 | @Nullable | 120 | @Nonnull |
| 118 | public EntryMapping getDeobfMapping(Entry<?> entry) { | 121 | public EntryMapping getDeobfMapping(Entry<?> entry) { |
| 119 | return obfToDeobf.get(entry); | 122 | EntryMapping entryMapping = obfToDeobf.get(entry); |
| 120 | } | 123 | return entryMapping == null ? EntryMapping.DEFAULT : entryMapping; |
| 121 | |||
| 122 | public boolean hasDeobfMapping(Entry<?> obfEntry) { | ||
| 123 | return obfToDeobf.contains(obfEntry); | ||
| 124 | } | 124 | } |
| 125 | 125 | ||
| 126 | public <T extends Translatable> TranslateResult<T> extendedDeobfuscate(T translatable) { | 126 | public <T extends Translatable> TranslateResult<T> extendedDeobfuscate(T translatable) { |
| @@ -158,4 +158,9 @@ public class EntryRemapper { | |||
| 158 | public EntryResolver getObfResolver() { | 158 | public EntryResolver getObfResolver() { |
| 159 | return obfResolver; | 159 | return obfResolver; |
| 160 | } | 160 | } |
| 161 | |||
| 162 | public MappingValidator getValidator() { | ||
| 163 | return validator; | ||
| 164 | } | ||
| 165 | |||
| 161 | } | 166 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryUtil.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryUtil.java new file mode 100644 index 00000000..582076c1 --- /dev/null +++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryUtil.java | |||
| @@ -0,0 +1,42 @@ | |||
| 1 | package cuchaz.enigma.translation.mapping; | ||
| 2 | |||
| 3 | import javax.annotation.Nonnull; | ||
| 4 | |||
| 5 | import cuchaz.enigma.translation.representation.entry.Entry; | ||
| 6 | import cuchaz.enigma.utils.validation.ValidationContext; | ||
| 7 | |||
| 8 | public class EntryUtil { | ||
| 9 | |||
| 10 | public static EntryMapping applyChange(ValidationContext vc, EntryRemapper remapper, EntryChange<?> change) { | ||
| 11 | Entry<?> target = change.getTarget(); | ||
| 12 | EntryMapping prev = remapper.getDeobfMapping(target); | ||
| 13 | EntryMapping mapping = EntryUtil.applyChange(prev, change); | ||
| 14 | |||
| 15 | remapper.putMapping(vc, target, mapping); | ||
| 16 | |||
| 17 | return mapping; | ||
| 18 | } | ||
| 19 | |||
| 20 | public static EntryMapping applyChange(@Nonnull EntryMapping self, EntryChange<?> change) { | ||
| 21 | if (change.getDeobfName().isSet()) { | ||
| 22 | self = self.withName(change.getDeobfName().getNewValue()); | ||
| 23 | } else if (change.getDeobfName().isReset()) { | ||
| 24 | self = self.withName(null); | ||
| 25 | } | ||
| 26 | |||
| 27 | if (change.getJavadoc().isSet()) { | ||
| 28 | self = self.withDocs(change.getJavadoc().getNewValue()); | ||
| 29 | } else if (change.getJavadoc().isReset()) { | ||
| 30 | self = self.withDocs(null); | ||
| 31 | } | ||
| 32 | |||
| 33 | if (change.getAccess().isSet()) { | ||
| 34 | self = self.withModifier(change.getAccess().getNewValue()); | ||
| 35 | } else if (change.getAccess().isReset()) { | ||
| 36 | self = self.withModifier(AccessModifier.UNCHANGED); | ||
| 37 | } | ||
| 38 | |||
| 39 | return self; | ||
| 40 | } | ||
| 41 | |||
| 42 | } | ||
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingValidator.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingValidator.java index 1615912b..065e5c3e 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingValidator.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingValidator.java | |||
| @@ -25,18 +25,22 @@ public class MappingValidator { | |||
| 25 | this.index = index; | 25 | this.index = index; |
| 26 | } | 26 | } |
| 27 | 27 | ||
| 28 | public void validateRename(ValidationContext vc, Entry<?> entry, String name) { | 28 | public boolean validateRename(ValidationContext vc, Entry<?> entry, String name) { |
| 29 | Collection<Entry<?>> equivalentEntries = index.getEntryResolver().resolveEquivalentEntries(entry); | 29 | Collection<Entry<?>> equivalentEntries = index.getEntryResolver().resolveEquivalentEntries(entry); |
| 30 | boolean error = false; | ||
| 30 | for (Entry<?> equivalentEntry : equivalentEntries) { | 31 | for (Entry<?> equivalentEntry : equivalentEntries) { |
| 31 | equivalentEntry.validateName(vc, name); | 32 | equivalentEntry.validateName(vc, name); |
| 32 | validateUnique(vc, equivalentEntry, name); | 33 | error |= validateUnique(vc, equivalentEntry, name); |
| 33 | } | 34 | } |
| 35 | return error; | ||
| 34 | } | 36 | } |
| 35 | 37 | ||
| 36 | private void validateUnique(ValidationContext vc, Entry<?> entry, String name) { | 38 | private boolean validateUnique(ValidationContext vc, Entry<?> entry, String name) { |
| 37 | ClassEntry containingClass = entry.getContainingClass(); | 39 | ClassEntry containingClass = entry.getContainingClass(); |
| 38 | Collection<ClassEntry> relatedClasses = getRelatedClasses(containingClass); | 40 | Collection<ClassEntry> relatedClasses = getRelatedClasses(containingClass); |
| 39 | 41 | ||
| 42 | boolean error = false; | ||
| 43 | |||
| 40 | for (ClassEntry relatedClass : relatedClasses) { | 44 | for (ClassEntry relatedClass : relatedClasses) { |
| 41 | Entry<?> relatedEntry = entry.replaceAncestor(containingClass, relatedClass); | 45 | Entry<?> relatedEntry = entry.replaceAncestor(containingClass, relatedClass); |
| 42 | Entry<?> translatedEntry = deobfuscator.translate(relatedEntry); | 46 | Entry<?> translatedEntry = deobfuscator.translate(relatedEntry); |
| @@ -52,8 +56,11 @@ public class MappingValidator { | |||
| 52 | } else { | 56 | } else { |
| 53 | vc.raise(Message.NONUNIQUE_NAME, name); | 57 | vc.raise(Message.NONUNIQUE_NAME, name); |
| 54 | } | 58 | } |
| 59 | error = true; | ||
| 55 | } | 60 | } |
| 56 | } | 61 | } |
| 62 | |||
| 63 | return error; | ||
| 57 | } | 64 | } |
| 58 | 65 | ||
| 59 | private Collection<ClassEntry> getRelatedClasses(ClassEntry classEntry) { | 66 | private Collection<ClassEntry> getRelatedClasses(ClassEntry classEntry) { |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingsChecker.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingsChecker.java index 141a07cc..392b1a67 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingsChecker.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingsChecker.java | |||
| @@ -75,7 +75,7 @@ public class MappingsChecker { | |||
| 75 | private final Map<Entry<?>, String> droppedMappings = new HashMap<>(); | 75 | private final Map<Entry<?>, String> droppedMappings = new HashMap<>(); |
| 76 | 76 | ||
| 77 | public void drop(Entry<?> entry, EntryMapping mapping) { | 77 | public void drop(Entry<?> entry, EntryMapping mapping) { |
| 78 | droppedMappings.put(entry, mapping.getTargetName()); | 78 | droppedMappings.put(entry, mapping.targetName() != null ? mapping.targetName() : entry.getName()); |
| 79 | } | 79 | } |
| 80 | 80 | ||
| 81 | void apply(EntryTree<EntryMapping> mappings) { | 81 | void apply(EntryTree<EntryMapping> mappings) { |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/RawEntryMapping.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/RawEntryMapping.java index 79587a0b..6465008b 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/RawEntryMapping.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/RawEntryMapping.java | |||
| @@ -1,23 +1,23 @@ | |||
| 1 | package cuchaz.enigma.translation.mapping.serde; | 1 | package cuchaz.enigma.translation.mapping.serde; |
| 2 | 2 | ||
| 3 | import cuchaz.enigma.translation.mapping.AccessModifier; | ||
| 4 | import cuchaz.enigma.translation.mapping.EntryMapping; | ||
| 5 | |||
| 6 | import java.util.ArrayList; | 3 | import java.util.ArrayList; |
| 7 | import java.util.List; | 4 | import java.util.List; |
| 8 | 5 | ||
| 6 | import cuchaz.enigma.translation.mapping.AccessModifier; | ||
| 7 | import cuchaz.enigma.translation.mapping.EntryMapping; | ||
| 8 | |||
| 9 | public final class RawEntryMapping { | 9 | public final class RawEntryMapping { |
| 10 | private final String targetName; | 10 | private final String targetName; |
| 11 | private final AccessModifier access; | 11 | private final AccessModifier access; |
| 12 | private List<String> javadocs = new ArrayList<>(); | 12 | private final List<String> javadocs = new ArrayList<>(); |
| 13 | 13 | ||
| 14 | public RawEntryMapping(String targetName) { | 14 | public RawEntryMapping(String targetName) { |
| 15 | this(targetName, null); | 15 | this(targetName, AccessModifier.UNCHANGED); |
| 16 | } | 16 | } |
| 17 | 17 | ||
| 18 | public RawEntryMapping(String targetName, AccessModifier access) { | 18 | public RawEntryMapping(String targetName, AccessModifier access) { |
| 19 | this.access = access; | 19 | this.access = access; |
| 20 | this.targetName = targetName; | 20 | this.targetName = targetName != null && !targetName.equals("-") ? targetName : null; |
| 21 | } | 21 | } |
| 22 | 22 | ||
| 23 | public void addJavadocLine(String line) { | 23 | public void addJavadocLine(String line) { |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/enigma/EnigmaMappingsReader.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/enigma/EnigmaMappingsReader.java index 27545c03..ccc25dff 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/enigma/EnigmaMappingsReader.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/enigma/EnigmaMappingsReader.java | |||
| @@ -1,15 +1,21 @@ | |||
| 1 | package cuchaz.enigma.translation.mapping.serde.enigma; | 1 | package cuchaz.enigma.translation.mapping.serde.enigma; |
| 2 | 2 | ||
| 3 | import java.io.IOException; | ||
| 4 | import java.nio.file.FileSystem; | ||
| 5 | import java.nio.file.FileSystems; | ||
| 6 | import java.nio.file.Files; | ||
| 7 | import java.nio.file.Path; | ||
| 8 | import java.util.*; | ||
| 9 | |||
| 10 | import javax.annotation.Nullable; | ||
| 11 | |||
| 3 | import com.google.common.base.Charsets; | 12 | import com.google.common.base.Charsets; |
| 13 | |||
| 4 | import cuchaz.enigma.ProgressListener; | 14 | import cuchaz.enigma.ProgressListener; |
| 5 | import cuchaz.enigma.translation.mapping.serde.MappingParseException; | ||
| 6 | import cuchaz.enigma.translation.mapping.AccessModifier; | 15 | import cuchaz.enigma.translation.mapping.AccessModifier; |
| 7 | import cuchaz.enigma.translation.mapping.EntryMapping; | 16 | import cuchaz.enigma.translation.mapping.EntryMapping; |
| 8 | import cuchaz.enigma.translation.mapping.MappingPair; | 17 | import cuchaz.enigma.translation.mapping.MappingPair; |
| 9 | import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters; | 18 | import cuchaz.enigma.translation.mapping.serde.*; |
| 10 | import cuchaz.enigma.translation.mapping.serde.MappingHelper; | ||
| 11 | import cuchaz.enigma.translation.mapping.serde.MappingsReader; | ||
| 12 | import cuchaz.enigma.translation.mapping.serde.RawEntryMapping; | ||
| 13 | import cuchaz.enigma.translation.mapping.tree.EntryTree; | 19 | import cuchaz.enigma.translation.mapping.tree.EntryTree; |
| 14 | import cuchaz.enigma.translation.mapping.tree.HashEntryTree; | 20 | import cuchaz.enigma.translation.mapping.tree.HashEntryTree; |
| 15 | import cuchaz.enigma.translation.representation.MethodDescriptor; | 21 | import cuchaz.enigma.translation.representation.MethodDescriptor; |
| @@ -17,18 +23,6 @@ import cuchaz.enigma.translation.representation.TypeDescriptor; | |||
| 17 | import cuchaz.enigma.translation.representation.entry.*; | 23 | import cuchaz.enigma.translation.representation.entry.*; |
| 18 | import cuchaz.enigma.utils.I18n; | 24 | import cuchaz.enigma.utils.I18n; |
| 19 | 25 | ||
| 20 | import javax.annotation.Nullable; | ||
| 21 | import java.io.IOException; | ||
| 22 | import java.nio.file.FileSystem; | ||
| 23 | import java.nio.file.FileSystems; | ||
| 24 | import java.nio.file.Files; | ||
| 25 | import java.nio.file.Path; | ||
| 26 | import java.util.ArrayDeque; | ||
| 27 | import java.util.Arrays; | ||
| 28 | import java.util.Deque; | ||
| 29 | import java.util.List; | ||
| 30 | import java.util.Locale; | ||
| 31 | |||
| 32 | public enum EnigmaMappingsReader implements MappingsReader { | 26 | public enum EnigmaMappingsReader implements MappingsReader { |
| 33 | FILE { | 27 | FILE { |
| 34 | @Override | 28 | @Override |
| @@ -200,12 +194,12 @@ public enum EnigmaMappingsReader implements MappingsReader { | |||
| 200 | throw new RuntimeException("Unknown token '" + keyToken + "'"); | 194 | throw new RuntimeException("Unknown token '" + keyToken + "'"); |
| 201 | } | 195 | } |
| 202 | } | 196 | } |
| 203 | 197 | ||
| 204 | private static void readJavadoc(MappingPair<?, RawEntryMapping> parent, String[] tokens) { | 198 | private static void readJavadoc(MappingPair<?, RawEntryMapping> parent, String[] tokens) { |
| 205 | if (parent == null) | 199 | if (parent == null) |
| 206 | throw new IllegalStateException("Javadoc has no parent!"); | 200 | throw new IllegalStateException("Javadoc has no parent!"); |
| 207 | // Empty string to concat | 201 | // Empty string to concat |
| 208 | String jdLine = tokens.length > 1 ? String.join(" ", Arrays.copyOfRange(tokens,1,tokens.length)) : ""; | 202 | String jdLine = tokens.length > 1 ? String.join(" ", Arrays.copyOfRange(tokens, 1, tokens.length)) : ""; |
| 209 | if (parent.getMapping() == null) { | 203 | if (parent.getMapping() == null) { |
| 210 | parent.setMapping(new RawEntryMapping(parent.getEntry().getName(), AccessModifier.UNCHANGED)); | 204 | parent.setMapping(new RawEntryMapping(parent.getEntry().getName(), AccessModifier.UNCHANGED)); |
| 211 | } | 205 | } |
| @@ -237,11 +231,7 @@ public enum EnigmaMappingsReader implements MappingsReader { | |||
| 237 | modifier = parseModifier(tokens[3]); | 231 | modifier = parseModifier(tokens[3]); |
| 238 | } | 232 | } |
| 239 | 233 | ||
| 240 | if (mapping != null) { | 234 | return new MappingPair<>(obfuscatedEntry, new RawEntryMapping(mapping, modifier)); |
| 241 | return new MappingPair<>(obfuscatedEntry, new RawEntryMapping(mapping, modifier)); | ||
| 242 | } else { | ||
| 243 | return new MappingPair<>(obfuscatedEntry); | ||
| 244 | } | ||
| 245 | } | 235 | } |
| 246 | 236 | ||
| 247 | private static MappingPair<FieldEntry, RawEntryMapping> parseField(@Nullable Entry<?> parent, String[] tokens) { | 237 | private static MappingPair<FieldEntry, RawEntryMapping> parseField(@Nullable Entry<?> parent, String[] tokens) { |
| @@ -252,7 +242,7 @@ public enum EnigmaMappingsReader implements MappingsReader { | |||
| 252 | ClassEntry ownerEntry = (ClassEntry) parent; | 242 | ClassEntry ownerEntry = (ClassEntry) parent; |
| 253 | 243 | ||
| 254 | String obfuscatedName = tokens[1]; | 244 | String obfuscatedName = tokens[1]; |
| 255 | String mapping = obfuscatedName; | 245 | String mapping = null; |
| 256 | AccessModifier modifier = AccessModifier.UNCHANGED; | 246 | AccessModifier modifier = AccessModifier.UNCHANGED; |
| 257 | TypeDescriptor descriptor; | 247 | TypeDescriptor descriptor; |
| 258 | 248 | ||
| @@ -269,19 +259,15 @@ public enum EnigmaMappingsReader implements MappingsReader { | |||
| 269 | descriptor = new TypeDescriptor(tokens[3]); | 259 | descriptor = new TypeDescriptor(tokens[3]); |
| 270 | } | 260 | } |
| 271 | } else if (tokens.length == 5) { | 261 | } else if (tokens.length == 5) { |
| 272 | descriptor = new TypeDescriptor(tokens[3]); | ||
| 273 | mapping = tokens[2]; | 262 | mapping = tokens[2]; |
| 274 | modifier = parseModifier(tokens[4]); | 263 | modifier = parseModifier(tokens[3]); |
| 264 | descriptor = new TypeDescriptor(tokens[4]); | ||
| 275 | } else { | 265 | } else { |
| 276 | throw new RuntimeException("Invalid field declaration"); | 266 | throw new RuntimeException("Invalid field declaration"); |
| 277 | } | 267 | } |
| 278 | 268 | ||
| 279 | FieldEntry obfuscatedEntry = new FieldEntry(ownerEntry, obfuscatedName, descriptor); | 269 | FieldEntry obfuscatedEntry = new FieldEntry(ownerEntry, obfuscatedName, descriptor); |
| 280 | if (mapping != null) { | 270 | return new MappingPair<>(obfuscatedEntry, new RawEntryMapping(mapping, modifier)); |
| 281 | return new MappingPair<>(obfuscatedEntry, new RawEntryMapping(mapping, modifier)); | ||
| 282 | } else { | ||
| 283 | return new MappingPair<>(obfuscatedEntry); | ||
| 284 | } | ||
| 285 | } | 271 | } |
| 286 | 272 | ||
| 287 | private static MappingPair<MethodEntry, RawEntryMapping> parseMethod(@Nullable Entry<?> parent, String[] tokens) { | 273 | private static MappingPair<MethodEntry, RawEntryMapping> parseMethod(@Nullable Entry<?> parent, String[] tokens) { |
| @@ -317,11 +303,7 @@ public enum EnigmaMappingsReader implements MappingsReader { | |||
| 317 | } | 303 | } |
| 318 | 304 | ||
| 319 | MethodEntry obfuscatedEntry = new MethodEntry(ownerEntry, obfuscatedName, descriptor); | 305 | MethodEntry obfuscatedEntry = new MethodEntry(ownerEntry, obfuscatedName, descriptor); |
| 320 | if (mapping != null) { | 306 | return new MappingPair<>(obfuscatedEntry, new RawEntryMapping(mapping, modifier)); |
| 321 | return new MappingPair<>(obfuscatedEntry, new RawEntryMapping(mapping, modifier)); | ||
| 322 | } else { | ||
| 323 | return new MappingPair<>(obfuscatedEntry); | ||
| 324 | } | ||
| 325 | } | 307 | } |
| 326 | 308 | ||
| 327 | private static MappingPair<LocalVariableEntry, RawEntryMapping> parseArgument(@Nullable Entry<?> parent, String[] tokens) { | 309 | private static MappingPair<LocalVariableEntry, RawEntryMapping> parseArgument(@Nullable Entry<?> parent, String[] tokens) { |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/enigma/EnigmaMappingsWriter.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/enigma/EnigmaMappingsWriter.java index d9f1470d..5d7a7893 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/enigma/EnigmaMappingsWriter.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/enigma/EnigmaMappingsWriter.java | |||
| @@ -15,12 +15,7 @@ import java.io.IOException; | |||
| 15 | import java.io.PrintWriter; | 15 | import java.io.PrintWriter; |
| 16 | import java.net.URI; | 16 | import java.net.URI; |
| 17 | import java.net.URISyntaxException; | 17 | import java.net.URISyntaxException; |
| 18 | import java.nio.file.DirectoryStream; | 18 | import java.nio.file.*; |
| 19 | import java.nio.file.FileSystem; | ||
| 20 | import java.nio.file.FileSystems; | ||
| 21 | import java.nio.file.Files; | ||
| 22 | import java.nio.file.Path; | ||
| 23 | import java.nio.file.Paths; | ||
| 24 | import java.util.ArrayList; | 19 | import java.util.ArrayList; |
| 25 | import java.util.Collection; | 20 | import java.util.Collection; |
| 26 | import java.util.Collections; | 21 | import java.util.Collections; |
| @@ -28,25 +23,19 @@ import java.util.Objects; | |||
| 28 | import java.util.concurrent.atomic.AtomicInteger; | 23 | import java.util.concurrent.atomic.AtomicInteger; |
| 29 | import java.util.stream.Stream; | 24 | import java.util.stream.Stream; |
| 30 | 25 | ||
| 26 | import javax.annotation.Nonnull; | ||
| 27 | |||
| 31 | import cuchaz.enigma.ProgressListener; | 28 | import cuchaz.enigma.ProgressListener; |
| 32 | import cuchaz.enigma.translation.MappingTranslator; | 29 | import cuchaz.enigma.translation.MappingTranslator; |
| 33 | import cuchaz.enigma.translation.Translator; | 30 | import cuchaz.enigma.translation.Translator; |
| 34 | import cuchaz.enigma.translation.mapping.AccessModifier; | 31 | import cuchaz.enigma.translation.mapping.AccessModifier; |
| 35 | import cuchaz.enigma.translation.mapping.EntryMapping; | 32 | import cuchaz.enigma.translation.mapping.EntryMapping; |
| 36 | import cuchaz.enigma.translation.mapping.MappingDelta; | 33 | import cuchaz.enigma.translation.mapping.MappingDelta; |
| 37 | import cuchaz.enigma.translation.mapping.serde.MappingFileNameFormat; | ||
| 38 | import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters; | ||
| 39 | import cuchaz.enigma.translation.mapping.VoidEntryResolver; | 34 | import cuchaz.enigma.translation.mapping.VoidEntryResolver; |
| 40 | import cuchaz.enigma.translation.mapping.serde.LfPrintWriter; | 35 | import cuchaz.enigma.translation.mapping.serde.*; |
| 41 | import cuchaz.enigma.translation.mapping.serde.MappingHelper; | ||
| 42 | import cuchaz.enigma.translation.mapping.serde.MappingsWriter; | ||
| 43 | import cuchaz.enigma.translation.mapping.tree.EntryTree; | 36 | import cuchaz.enigma.translation.mapping.tree.EntryTree; |
| 44 | import cuchaz.enigma.translation.mapping.tree.EntryTreeNode; | 37 | import cuchaz.enigma.translation.mapping.tree.EntryTreeNode; |
| 45 | import cuchaz.enigma.translation.representation.entry.ClassEntry; | 38 | import cuchaz.enigma.translation.representation.entry.*; |
| 46 | import cuchaz.enigma.translation.representation.entry.Entry; | ||
| 47 | import cuchaz.enigma.translation.representation.entry.FieldEntry; | ||
| 48 | import cuchaz.enigma.translation.representation.entry.LocalVariableEntry; | ||
| 49 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | ||
| 50 | import cuchaz.enigma.utils.I18n; | 39 | import cuchaz.enigma.utils.I18n; |
| 51 | 40 | ||
| 52 | public enum EnigmaMappingsWriter implements MappingsWriter { | 41 | public enum EnigmaMappingsWriter implements MappingsWriter { |
| @@ -184,19 +173,22 @@ public enum EnigmaMappingsWriter implements MappingsWriter { | |||
| 184 | 173 | ||
| 185 | EntryMapping classEntryMapping = mappings.get(classEntry); | 174 | EntryMapping classEntryMapping = mappings.get(classEntry); |
| 186 | 175 | ||
| 176 | if (classEntryMapping == null) { | ||
| 177 | classEntryMapping = EntryMapping.DEFAULT; | ||
| 178 | } | ||
| 179 | |||
| 187 | writer.println(writeClass(classEntry, classEntryMapping).trim()); | 180 | writer.println(writeClass(classEntry, classEntryMapping).trim()); |
| 188 | if (classEntryMapping != null && classEntryMapping.getJavadoc() != null) { | 181 | if (classEntryMapping.javadoc() != null) { |
| 189 | writeDocs(writer, classEntryMapping, 0); | 182 | writeDocs(writer, classEntryMapping, 0); |
| 190 | } | 183 | } |
| 191 | 184 | ||
| 192 | for (Entry<?> child : children) { | 185 | for (Entry<?> child : children) { |
| 193 | writeEntry(writer, mappings, child, 1); | 186 | writeEntry(writer, mappings, child, 1); |
| 194 | } | 187 | } |
| 195 | |||
| 196 | } | 188 | } |
| 197 | 189 | ||
| 198 | private void writeDocs(PrintWriter writer, EntryMapping mapping, int depth) { | 190 | private void writeDocs(PrintWriter writer, EntryMapping mapping, int depth) { |
| 199 | String jd = mapping.getJavadoc(); | 191 | String jd = mapping.javadoc(); |
| 200 | if (jd != null) { | 192 | if (jd != null) { |
| 201 | for (String line : jd.split("\\R")) { | 193 | for (String line : jd.split("\\R")) { |
| 202 | writer.println(indent(EnigmaFormat.COMMENT + " " + MappingHelper.escape(line), depth + 1)); | 194 | writer.println(indent(EnigmaFormat.COMMENT + " " + MappingHelper.escape(line), depth + 1)); |
| @@ -212,20 +204,26 @@ public enum EnigmaMappingsWriter implements MappingsWriter { | |||
| 212 | 204 | ||
| 213 | EntryMapping mapping = node.getValue(); | 205 | EntryMapping mapping = node.getValue(); |
| 214 | 206 | ||
| 215 | if (entry instanceof ClassEntry) { | 207 | if (mapping == null) { |
| 216 | String line = writeClass((ClassEntry) entry, mapping); | 208 | mapping = EntryMapping.DEFAULT; |
| 217 | writer.println(indent(line, depth)); | 209 | } |
| 218 | } else if (entry instanceof MethodEntry) { | 210 | |
| 219 | String line = writeMethod((MethodEntry) entry, mapping); | 211 | String line = null; |
| 220 | writer.println(indent(line, depth)); | 212 | if (entry instanceof ClassEntry classEntry) { |
| 221 | } else if (entry instanceof FieldEntry) { | 213 | line = writeClass(classEntry, mapping); |
| 222 | String line = writeField((FieldEntry) entry, mapping); | 214 | } else if (entry instanceof MethodEntry methodEntry) { |
| 223 | writer.println(indent(line, depth)); | 215 | line = writeMethod(methodEntry, mapping); |
| 224 | } else if (entry instanceof LocalVariableEntry && mapping != null) { | 216 | } else if (entry instanceof FieldEntry fieldEntry) { |
| 225 | String line = writeArgument((LocalVariableEntry) entry, mapping); | 217 | line = writeField(fieldEntry, mapping); |
| 218 | } else if (entry instanceof LocalVariableEntry varEntry && mapping.targetName() != null) { | ||
| 219 | line = writeArgument(varEntry, mapping); | ||
| 220 | } | ||
| 221 | |||
| 222 | if (line != null) { | ||
| 226 | writer.println(indent(line, depth)); | 223 | writer.println(indent(line, depth)); |
| 227 | } | 224 | } |
| 228 | if (mapping != null && mapping.getJavadoc() != null) { | 225 | |
| 226 | if (mapping.javadoc() != null) { | ||
| 229 | writeDocs(writer, mapping, depth); | 227 | writeDocs(writer, mapping, depth); |
| 230 | } | 228 | } |
| 231 | 229 | ||
| @@ -254,55 +252,53 @@ public enum EnigmaMappingsWriter implements MappingsWriter { | |||
| 254 | .forEach(result::add); | 252 | .forEach(result::add); |
| 255 | 253 | ||
| 256 | children.stream().filter(e -> e instanceof ClassEntry) | 254 | children.stream().filter(e -> e instanceof ClassEntry) |
| 257 | .map(e -> (ClassEntry) e) | 255 | .map(e -> (ClassEntry) e) |
| 258 | .sorted() | 256 | .sorted() |
| 259 | .forEach(result::add); | 257 | .forEach(result::add); |
| 260 | 258 | ||
| 261 | return result; | 259 | return result; |
| 262 | } | 260 | } |
| 263 | 261 | ||
| 264 | protected String writeClass(ClassEntry entry, EntryMapping mapping) { | 262 | protected String writeClass(ClassEntry entry, @Nonnull EntryMapping mapping) { |
| 265 | StringBuilder builder = new StringBuilder(EnigmaFormat.CLASS +" "); | 263 | StringBuilder builder = new StringBuilder(EnigmaFormat.CLASS + " "); |
| 266 | builder.append(entry.getName()).append(' '); | 264 | builder.append(entry.getName()).append(' '); |
| 267 | writeMapping(builder, mapping); | 265 | writeMapping(builder, mapping); |
| 268 | 266 | ||
| 269 | return builder.toString(); | 267 | return builder.toString(); |
| 270 | } | 268 | } |
| 271 | 269 | ||
| 272 | protected String writeMethod(MethodEntry entry, EntryMapping mapping) { | 270 | protected String writeMethod(MethodEntry entry, @Nonnull EntryMapping mapping) { |
| 273 | StringBuilder builder = new StringBuilder(EnigmaFormat.METHOD + " "); | 271 | StringBuilder builder = new StringBuilder(EnigmaFormat.METHOD + " "); |
| 274 | builder.append(entry.getName()).append(' '); | 272 | builder.append(entry.getName()).append(' '); |
| 275 | if (mapping != null && !mapping.getTargetName().equals(entry.getName())) { | 273 | writeMapping(builder, mapping); |
| 276 | writeMapping(builder, mapping); | ||
| 277 | } | ||
| 278 | 274 | ||
| 279 | builder.append(entry.getDesc().toString()); | 275 | builder.append(entry.getDesc().toString()); |
| 280 | 276 | ||
| 281 | return builder.toString(); | 277 | return builder.toString(); |
| 282 | } | 278 | } |
| 283 | 279 | ||
| 284 | protected String writeField(FieldEntry entry, EntryMapping mapping) { | 280 | protected String writeField(FieldEntry entry, @Nonnull EntryMapping mapping) { |
| 285 | StringBuilder builder = new StringBuilder(EnigmaFormat.FIELD + " "); | 281 | StringBuilder builder = new StringBuilder(EnigmaFormat.FIELD + " "); |
| 286 | builder.append(entry.getName()).append(' '); | 282 | builder.append(entry.getName()).append(' '); |
| 287 | if (mapping != null && !mapping.getTargetName().equals(entry.getName())) { | 283 | writeMapping(builder, mapping); |
| 288 | writeMapping(builder, mapping); | ||
| 289 | } | ||
| 290 | 284 | ||
| 291 | builder.append(entry.getDesc().toString()); | 285 | builder.append(entry.getDesc().toString()); |
| 292 | 286 | ||
| 293 | return builder.toString(); | 287 | return builder.toString(); |
| 294 | } | 288 | } |
| 295 | 289 | ||
| 296 | protected String writeArgument(LocalVariableEntry entry, EntryMapping mapping) { | 290 | protected String writeArgument(LocalVariableEntry entry, @Nonnull EntryMapping mapping) { |
| 297 | return EnigmaFormat.PARAMETER + " " + entry.getIndex() + ' ' + mapping.getTargetName(); | 291 | return EnigmaFormat.PARAMETER + " " + entry.getIndex() + ' ' + mapping.targetName(); |
| 298 | } | 292 | } |
| 299 | 293 | ||
| 300 | private void writeMapping(StringBuilder builder, EntryMapping mapping) { | 294 | private void writeMapping(StringBuilder builder, EntryMapping mapping) { |
| 301 | if (mapping != null) { | 295 | if (mapping.targetName() != null) { |
| 302 | builder.append(mapping.getTargetName()).append(' '); | 296 | builder.append(mapping.targetName()).append(' '); |
| 303 | if (mapping.getAccessModifier() != AccessModifier.UNCHANGED) { | 297 | if (mapping.accessModifier() != AccessModifier.UNCHANGED) { |
| 304 | builder.append(mapping.getAccessModifier().getFormattedName()).append(' '); | 298 | builder.append(mapping.accessModifier().getFormattedName()).append(' '); |
| 305 | } | 299 | } |
| 300 | } else if (mapping.accessModifier() != AccessModifier.UNCHANGED) { | ||
| 301 | builder.append("- ").append(mapping.accessModifier().getFormattedName()).append(' '); | ||
| 306 | } | 302 | } |
| 307 | } | 303 | } |
| 308 | 304 | ||
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/tiny/TinyMappingsWriter.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/tiny/TinyMappingsWriter.java index 4f78e6f3..1f785e10 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/tiny/TinyMappingsWriter.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/tiny/TinyMappingsWriter.java | |||
| @@ -73,13 +73,16 @@ public class TinyMappingsWriter implements MappingsWriter { | |||
| 73 | Translator translator = new MappingTranslator(mappings, VoidEntryResolver.INSTANCE); | 73 | Translator translator = new MappingTranslator(mappings, VoidEntryResolver.INSTANCE); |
| 74 | 74 | ||
| 75 | EntryMapping mapping = mappings.get(entry); | 75 | EntryMapping mapping = mappings.get(entry); |
| 76 | if (mapping != null && !entry.getName().equals(mapping.getTargetName())) { | 76 | |
| 77 | // Do not write mappings without deobfuscated name since tiny v1 doesn't | ||
| 78 | // support comments anyway | ||
| 79 | if (mapping != null && mapping.targetName() != null) { | ||
| 77 | if (entry instanceof ClassEntry) { | 80 | if (entry instanceof ClassEntry) { |
| 78 | writeClass(writer, (ClassEntry) entry, translator); | 81 | writeClass(writer, (ClassEntry) entry, translator); |
| 79 | } else if (entry instanceof FieldEntry) { | 82 | } else if (entry instanceof FieldEntry) { |
| 80 | writeLine(writer, serializeEntry(entry, mapping.getTargetName())); | 83 | writeLine(writer, serializeEntry(entry, mapping.targetName())); |
| 81 | } else if (entry instanceof MethodEntry) { | 84 | } else if (entry instanceof MethodEntry) { |
| 82 | writeLine(writer, serializeEntry(entry, mapping.getTargetName())); | 85 | writeLine(writer, serializeEntry(entry, mapping.targetName())); |
| 83 | } | 86 | } |
| 84 | } | 87 | } |
| 85 | 88 | ||
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/tinyv2/TinyV2Writer.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/tinyv2/TinyV2Writer.java index 5160eda3..c4005688 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/tinyv2/TinyV2Writer.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/tinyv2/TinyV2Writer.java | |||
| @@ -62,8 +62,8 @@ public final class TinyV2Writer implements MappingsWriter { | |||
| 62 | Deque<String> parts = new LinkedList<>(); | 62 | Deque<String> parts = new LinkedList<>(); |
| 63 | do { | 63 | do { |
| 64 | EntryMapping mapping = tree.get(classEntry); | 64 | EntryMapping mapping = tree.get(classEntry); |
| 65 | if (mapping != null) { | 65 | if (mapping != null && mapping.targetName() != null) { |
| 66 | parts.addFirst(mapping.getTargetName()); | 66 | parts.addFirst(mapping.targetName()); |
| 67 | } else { | 67 | } else { |
| 68 | parts.addFirst(classEntry.getName()); | 68 | parts.addFirst(classEntry.getName()); |
| 69 | } | 69 | } |
| @@ -81,7 +81,7 @@ public final class TinyV2Writer implements MappingsWriter { | |||
| 81 | writeComment(writer, node.getValue(), 1); | 81 | writeComment(writer, node.getValue(), 1); |
| 82 | 82 | ||
| 83 | for (EntryTreeNode<EntryMapping> child : node.getChildNodes()) { | 83 | for (EntryTreeNode<EntryMapping> child : node.getChildNodes()) { |
| 84 | Entry entry = child.getEntry(); | 84 | Entry<?> entry = child.getEntry(); |
| 85 | if (entry instanceof FieldEntry) { | 85 | if (entry instanceof FieldEntry) { |
| 86 | writeField(writer, child); | 86 | writeField(writer, child); |
| 87 | } else if (entry instanceof MethodEntry) { | 87 | } else if (entry instanceof MethodEntry) { |
| @@ -98,16 +98,21 @@ public final class TinyV2Writer implements MappingsWriter { | |||
| 98 | writer.print(node.getEntry().getName()); | 98 | writer.print(node.getEntry().getName()); |
| 99 | writer.print("\t"); | 99 | writer.print("\t"); |
| 100 | EntryMapping mapping = node.getValue(); | 100 | EntryMapping mapping = node.getValue(); |
| 101 | |||
| 101 | if (mapping == null) { | 102 | if (mapping == null) { |
| 102 | writer.println(node.getEntry().getName()); // todo fix v2 name inference | 103 | mapping = EntryMapping.DEFAULT; |
| 103 | } else { | 104 | } |
| 104 | writer.println(mapping.getTargetName()); | ||
| 105 | 105 | ||
| 106 | writeComment(writer, mapping, 2); | 106 | if (mapping.targetName() != null) { |
| 107 | writer.println(mapping.targetName()); | ||
| 108 | } else { | ||
| 109 | writer.println(node.getEntry().getName()); // todo fix v2 name inference | ||
| 107 | } | 110 | } |
| 108 | 111 | ||
| 112 | writeComment(writer, mapping, 2); | ||
| 113 | |||
| 109 | for (EntryTreeNode<EntryMapping> child : node.getChildNodes()) { | 114 | for (EntryTreeNode<EntryMapping> child : node.getChildNodes()) { |
| 110 | Entry entry = child.getEntry(); | 115 | Entry<?> entry = child.getEntry(); |
| 111 | if (entry instanceof LocalVariableEntry) { | 116 | if (entry instanceof LocalVariableEntry) { |
| 112 | writeParameter(writer, child); | 117 | writeParameter(writer, child); |
| 113 | } | 118 | } |
| @@ -116,7 +121,7 @@ public final class TinyV2Writer implements MappingsWriter { | |||
| 116 | } | 121 | } |
| 117 | 122 | ||
| 118 | private void writeField(PrintWriter writer, EntryTreeNode<EntryMapping> node) { | 123 | private void writeField(PrintWriter writer, EntryTreeNode<EntryMapping> node) { |
| 119 | if (node.getValue() == null) | 124 | if (node.getValue() == null || node.getValue().equals(EntryMapping.DEFAULT)) |
| 120 | return; // Shortcut | 125 | return; // Shortcut |
| 121 | 126 | ||
| 122 | writer.print(indent(1)); | 127 | writer.print(indent(1)); |
| @@ -126,17 +131,22 @@ public final class TinyV2Writer implements MappingsWriter { | |||
| 126 | writer.print(node.getEntry().getName()); | 131 | writer.print(node.getEntry().getName()); |
| 127 | writer.print("\t"); | 132 | writer.print("\t"); |
| 128 | EntryMapping mapping = node.getValue(); | 133 | EntryMapping mapping = node.getValue(); |
| 134 | |||
| 129 | if (mapping == null) { | 135 | if (mapping == null) { |
| 130 | writer.println(node.getEntry().getName()); // todo fix v2 name inference | 136 | mapping = EntryMapping.DEFAULT; |
| 131 | } else { | 137 | } |
| 132 | writer.println(mapping.getTargetName()); | ||
| 133 | 138 | ||
| 134 | writeComment(writer, mapping, 2); | 139 | if (mapping.targetName() != null) { |
| 140 | writer.println(mapping.targetName()); | ||
| 141 | } else { | ||
| 142 | writer.println(node.getEntry().getName()); // todo fix v2 name inference | ||
| 135 | } | 143 | } |
| 144 | |||
| 145 | writeComment(writer, mapping, 2); | ||
| 136 | } | 146 | } |
| 137 | 147 | ||
| 138 | private void writeParameter(PrintWriter writer, EntryTreeNode<EntryMapping> node) { | 148 | private void writeParameter(PrintWriter writer, EntryTreeNode<EntryMapping> node) { |
| 139 | if (node.getValue() == null) | 149 | if (node.getValue() == null || node.getValue().equals(EntryMapping.DEFAULT)) |
| 140 | return; // Shortcut | 150 | return; // Shortcut |
| 141 | 151 | ||
| 142 | writer.print(indent(2)); | 152 | writer.print(indent(2)); |
| @@ -146,20 +156,20 @@ public final class TinyV2Writer implements MappingsWriter { | |||
| 146 | writer.print(node.getEntry().getName()); | 156 | writer.print(node.getEntry().getName()); |
| 147 | writer.print("\t"); | 157 | writer.print("\t"); |
| 148 | EntryMapping mapping = node.getValue(); | 158 | EntryMapping mapping = node.getValue(); |
| 149 | if (mapping == null) { | 159 | if (mapping == null || mapping.targetName() == null) { |
| 150 | writer.println(); // todo ??? | 160 | writer.println(); // todo ??? |
| 151 | } else { | 161 | } else { |
| 152 | writer.println(mapping.getTargetName()); | 162 | writer.println(mapping.targetName()); |
| 153 | 163 | ||
| 154 | writeComment(writer, mapping, 3); | 164 | writeComment(writer, mapping, 3); |
| 155 | } | 165 | } |
| 156 | } | 166 | } |
| 157 | 167 | ||
| 158 | private void writeComment(PrintWriter writer, EntryMapping mapping, int indent) { | 168 | private void writeComment(PrintWriter writer, EntryMapping mapping, int indent) { |
| 159 | if (mapping != null && mapping.getJavadoc() != null) { | 169 | if (mapping != null && mapping.javadoc() != null) { |
| 160 | writer.print(indent(indent)); | 170 | writer.print(indent(indent)); |
| 161 | writer.print("c\t"); | 171 | writer.print("c\t"); |
| 162 | writer.print(MappingHelper.escape(mapping.getJavadoc())); | 172 | writer.print(MappingHelper.escape(mapping.javadoc())); |
| 163 | writer.println(); | 173 | writer.println(); |
| 164 | } | 174 | } |
| 165 | } | 175 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/tree/HashEntryTree.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/tree/HashEntryTree.java index 570941cd..0992d342 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/tree/HashEntryTree.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/tree/HashEntryTree.java | |||
| @@ -6,6 +6,7 @@ import cuchaz.enigma.translation.mapping.EntryMapping; | |||
| 6 | import cuchaz.enigma.translation.mapping.EntryResolver; | 6 | import cuchaz.enigma.translation.mapping.EntryResolver; |
| 7 | import cuchaz.enigma.translation.representation.entry.Entry; | 7 | import cuchaz.enigma.translation.representation.entry.Entry; |
| 8 | 8 | ||
| 9 | import javax.annotation.Nonnull; | ||
| 9 | import javax.annotation.Nullable; | 10 | import javax.annotation.Nullable; |
| 10 | import java.util.*; | 11 | import java.util.*; |
| 11 | import java.util.function.Function; | 12 | import java.util.function.Function; |
| @@ -152,6 +153,7 @@ public class HashEntryTree<T> implements EntryTree<T> { | |||
| 152 | } | 153 | } |
| 153 | 154 | ||
| 154 | @Override | 155 | @Override |
| 156 | @Nonnull | ||
| 155 | public Iterator<EntryTreeNode<T>> iterator() { | 157 | public Iterator<EntryTreeNode<T>> iterator() { |
| 156 | Collection<EntryTreeNode<T>> nodes = new ArrayList<>(); | 158 | Collection<EntryTreeNode<T>> nodes = new ArrayList<>(); |
| 157 | for (EntryTreeNode<T> node : root.values()) { | 159 | for (EntryTreeNode<T> node : root.values()) { |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/representation/Lambda.java b/enigma/src/main/java/cuchaz/enigma/translation/representation/Lambda.java index a6aed731..13c7cd48 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/representation/Lambda.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/representation/Lambda.java | |||
| @@ -35,9 +35,9 @@ public class Lambda implements Translatable { | |||
| 35 | EntryMapping samMethodMapping = resolveMapping(resolver, mappings, samMethod); | 35 | EntryMapping samMethodMapping = resolveMapping(resolver, mappings, samMethod); |
| 36 | 36 | ||
| 37 | return TranslateResult.of( | 37 | return TranslateResult.of( |
| 38 | samMethodMapping == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED, | 38 | samMethodMapping.targetName() == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED, |
| 39 | new Lambda( | 39 | new Lambda( |
| 40 | samMethodMapping != null ? samMethodMapping.getTargetName() : invokedName, | 40 | samMethodMapping.targetName() != null ? samMethodMapping.targetName() : invokedName, |
| 41 | invokedType.extendedTranslate(translator, resolver, mappings).getValue(), | 41 | invokedType.extendedTranslate(translator, resolver, mappings).getValue(), |
| 42 | samMethodType.extendedTranslate(translator, resolver, mappings).getValue(), | 42 | samMethodType.extendedTranslate(translator, resolver, mappings).getValue(), |
| 43 | implMethod.extendedTranslate(translator, resolver, mappings).getValue(), | 43 | implMethod.extendedTranslate(translator, resolver, mappings).getValue(), |
| @@ -53,7 +53,7 @@ public class Lambda implements Translatable { | |||
| 53 | return mapping; | 53 | return mapping; |
| 54 | } | 54 | } |
| 55 | } | 55 | } |
| 56 | return null; | 56 | return EntryMapping.DEFAULT; |
| 57 | } | 57 | } |
| 58 | 58 | ||
| 59 | public ClassEntry getInterface() { | 59 | public ClassEntry getInterface() { |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/ClassDefEntry.java b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/ClassDefEntry.java index b0fd2865..237c93dc 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/ClassDefEntry.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/ClassDefEntry.java | |||
| @@ -13,6 +13,7 @@ package cuchaz.enigma.translation.representation.entry; | |||
| 13 | 13 | ||
| 14 | import java.util.Arrays; | 14 | import java.util.Arrays; |
| 15 | 15 | ||
| 16 | import javax.annotation.Nonnull; | ||
| 16 | import javax.annotation.Nullable; | 17 | import javax.annotation.Nullable; |
| 17 | 18 | ||
| 18 | import com.google.common.base.Preconditions; | 19 | import com.google.common.base.Preconditions; |
| @@ -75,15 +76,15 @@ public class ClassDefEntry extends ClassEntry implements DefEntry<ClassEntry> { | |||
| 75 | } | 76 | } |
| 76 | 77 | ||
| 77 | @Override | 78 | @Override |
| 78 | public TranslateResult<ClassDefEntry> extendedTranslate(Translator translator, @Nullable EntryMapping mapping) { | 79 | public TranslateResult<ClassDefEntry> extendedTranslate(Translator translator, @Nonnull EntryMapping mapping) { |
| 79 | Signature translatedSignature = translator.translate(signature); | 80 | Signature translatedSignature = translator.translate(signature); |
| 80 | String translatedName = mapping != null ? mapping.getTargetName() : name; | 81 | String translatedName = mapping.targetName() != null ? mapping.targetName() : name; |
| 81 | AccessFlags translatedAccess = mapping != null ? mapping.getAccessModifier().transform(access) : access; | 82 | AccessFlags translatedAccess = mapping.accessModifier().transform(access); |
| 82 | ClassEntry translatedSuper = translator.translate(superClass); | 83 | ClassEntry translatedSuper = translator.translate(superClass); |
| 83 | ClassEntry[] translatedInterfaces = Arrays.stream(interfaces).map(translator::translate).toArray(ClassEntry[]::new); | 84 | ClassEntry[] translatedInterfaces = Arrays.stream(interfaces).map(translator::translate).toArray(ClassEntry[]::new); |
| 84 | String docs = mapping != null ? mapping.getJavadoc() : null; | 85 | String docs = mapping.javadoc(); |
| 85 | return TranslateResult.of( | 86 | return TranslateResult.of( |
| 86 | mapping == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED, | 87 | mapping.targetName() == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED, |
| 87 | new ClassDefEntry(parent, translatedName, translatedSignature, translatedAccess, translatedSuper, translatedInterfaces, docs) | 88 | new ClassDefEntry(parent, translatedName, translatedSignature, translatedAccess, translatedSuper, translatedInterfaces, docs) |
| 88 | ); | 89 | ); |
| 89 | } | 90 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/ClassEntry.java b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/ClassEntry.java index fe56611b..ec5294ed 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/ClassEntry.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/ClassEntry.java | |||
| @@ -82,16 +82,16 @@ public class ClassEntry extends ParentedEntry<ClassEntry> implements Comparable< | |||
| 82 | } | 82 | } |
| 83 | 83 | ||
| 84 | @Override | 84 | @Override |
| 85 | public TranslateResult<? extends ClassEntry> extendedTranslate(Translator translator, @Nullable EntryMapping mapping) { | 85 | public TranslateResult<? extends ClassEntry> extendedTranslate(Translator translator, @Nonnull EntryMapping mapping) { |
| 86 | if (name.charAt(0) == '[') { | 86 | if (name.charAt(0) == '[') { |
| 87 | TranslateResult<TypeDescriptor> translatedName = translator.extendedTranslate(new TypeDescriptor(name)); | 87 | TranslateResult<TypeDescriptor> translatedName = translator.extendedTranslate(new TypeDescriptor(name)); |
| 88 | return translatedName.map(desc -> new ClassEntry(parent, desc.toString())); | 88 | return translatedName.map(desc -> new ClassEntry(parent, desc.toString())); |
| 89 | } | 89 | } |
| 90 | 90 | ||
| 91 | String translatedName = mapping != null ? mapping.getTargetName() : name; | 91 | String translatedName = mapping.targetName() != null ? mapping.targetName() : name; |
| 92 | String docs = mapping != null ? mapping.getJavadoc() : null; | 92 | String docs = mapping.javadoc(); |
| 93 | return TranslateResult.of( | 93 | return TranslateResult.of( |
| 94 | mapping == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED, | 94 | mapping.targetName() == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED, |
| 95 | new ClassEntry(parent, translatedName, docs) | 95 | new ClassEntry(parent, translatedName, docs) |
| 96 | ); | 96 | ); |
| 97 | } | 97 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/Entry.java b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/Entry.java index 8a81c54a..956f32ca 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/Entry.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/Entry.java | |||
| @@ -13,6 +13,7 @@ package cuchaz.enigma.translation.representation.entry; | |||
| 13 | 13 | ||
| 14 | import java.util.ArrayList; | 14 | import java.util.ArrayList; |
| 15 | import java.util.List; | 15 | import java.util.List; |
| 16 | import java.util.Objects; | ||
| 16 | 17 | ||
| 17 | import javax.annotation.Nullable; | 18 | import javax.annotation.Nullable; |
| 18 | 19 | ||
| @@ -107,16 +108,29 @@ public interface Entry<P extends Entry<?>> extends Translatable { | |||
| 107 | 108 | ||
| 108 | boolean canConflictWith(Entry<?> entry); | 109 | boolean canConflictWith(Entry<?> entry); |
| 109 | 110 | ||
| 110 | @Nullable | ||
| 111 | default ClassEntry getContainingClass() { | 111 | default ClassEntry getContainingClass() { |
| 112 | P parent = getParent(); | 112 | ClassEntry last = null; |
| 113 | if (parent == null) { | 113 | Entry<?> current = this; |
| 114 | return null; | 114 | while (current != null) { |
| 115 | if (current instanceof ClassEntry) { | ||
| 116 | last = (ClassEntry) current; | ||
| 117 | break; | ||
| 118 | } | ||
| 119 | current = current.getParent(); | ||
| 115 | } | 120 | } |
| 116 | if (parent instanceof ClassEntry) { | 121 | return Objects.requireNonNull(last, () -> String.format("%s has no containing class?", this)); |
| 117 | return (ClassEntry) parent; | 122 | } |
| 123 | |||
| 124 | default ClassEntry getTopLevelClass() { | ||
| 125 | ClassEntry last = null; | ||
| 126 | Entry<?> current = this; | ||
| 127 | while (current != null) { | ||
| 128 | if (current instanceof ClassEntry) { | ||
| 129 | last = (ClassEntry) current; | ||
| 130 | } | ||
| 131 | current = current.getParent(); | ||
| 118 | } | 132 | } |
| 119 | return parent.getContainingClass(); | 133 | return Objects.requireNonNull(last, () -> String.format("%s has no top level class?", this)); |
| 120 | } | 134 | } |
| 121 | 135 | ||
| 122 | default List<Entry<?>> getAncestry() { | 136 | default List<Entry<?>> getAncestry() { |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/FieldDefEntry.java b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/FieldDefEntry.java index b9da6cca..0efb6a99 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/FieldDefEntry.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/FieldDefEntry.java | |||
| @@ -11,8 +11,6 @@ | |||
| 11 | 11 | ||
| 12 | package cuchaz.enigma.translation.representation.entry; | 12 | package cuchaz.enigma.translation.representation.entry; |
| 13 | 13 | ||
| 14 | import javax.annotation.Nullable; | ||
| 15 | |||
| 16 | import com.google.common.base.Preconditions; | 14 | import com.google.common.base.Preconditions; |
| 17 | 15 | ||
| 18 | import cuchaz.enigma.source.RenamableTokenType; | 16 | import cuchaz.enigma.source.RenamableTokenType; |
| @@ -23,6 +21,8 @@ import cuchaz.enigma.translation.representation.AccessFlags; | |||
| 23 | import cuchaz.enigma.translation.representation.Signature; | 21 | import cuchaz.enigma.translation.representation.Signature; |
| 24 | import cuchaz.enigma.translation.representation.TypeDescriptor; | 22 | import cuchaz.enigma.translation.representation.TypeDescriptor; |
| 25 | 23 | ||
| 24 | import javax.annotation.Nonnull; | ||
| 25 | |||
| 26 | public class FieldDefEntry extends FieldEntry implements DefEntry<ClassEntry> { | 26 | public class FieldDefEntry extends FieldEntry implements DefEntry<ClassEntry> { |
| 27 | private final AccessFlags access; | 27 | private final AccessFlags access; |
| 28 | private final Signature signature; | 28 | private final Signature signature; |
| @@ -53,14 +53,14 @@ public class FieldDefEntry extends FieldEntry implements DefEntry<ClassEntry> { | |||
| 53 | } | 53 | } |
| 54 | 54 | ||
| 55 | @Override | 55 | @Override |
| 56 | protected TranslateResult<FieldEntry> extendedTranslate(Translator translator, @Nullable EntryMapping mapping) { | 56 | protected TranslateResult<FieldEntry> extendedTranslate(Translator translator, @Nonnull EntryMapping mapping) { |
| 57 | TypeDescriptor translatedDesc = translator.translate(desc); | 57 | TypeDescriptor translatedDesc = translator.translate(desc); |
| 58 | Signature translatedSignature = translator.translate(signature); | 58 | Signature translatedSignature = translator.translate(signature); |
| 59 | String translatedName = mapping != null ? mapping.getTargetName() : name; | 59 | String translatedName = mapping.targetName() != null ? mapping.targetName() : name; |
| 60 | AccessFlags translatedAccess = mapping != null ? mapping.getAccessModifier().transform(access) : access; | 60 | AccessFlags translatedAccess = mapping.accessModifier().transform(access); |
| 61 | String docs = mapping != null ? mapping.getJavadoc() : null; | 61 | String docs = mapping.javadoc(); |
| 62 | return TranslateResult.of( | 62 | return TranslateResult.of( |
| 63 | mapping == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED, | 63 | mapping.targetName() == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED, |
| 64 | new FieldDefEntry(parent, translatedName, translatedDesc, translatedSignature, translatedAccess, docs) | 64 | new FieldDefEntry(parent, translatedName, translatedDesc, translatedSignature, translatedAccess, docs) |
| 65 | ); | 65 | ); |
| 66 | } | 66 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/FieldEntry.java b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/FieldEntry.java index 5ddd33de..db940118 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/FieldEntry.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/FieldEntry.java | |||
| @@ -13,7 +13,7 @@ package cuchaz.enigma.translation.representation.entry; | |||
| 13 | 13 | ||
| 14 | import java.util.Objects; | 14 | import java.util.Objects; |
| 15 | 15 | ||
| 16 | import javax.annotation.Nullable; | 16 | import javax.annotation.Nonnull; |
| 17 | 17 | ||
| 18 | import com.google.common.base.Preconditions; | 18 | import com.google.common.base.Preconditions; |
| 19 | 19 | ||
| @@ -63,11 +63,11 @@ public class FieldEntry extends ParentedEntry<ClassEntry> implements Comparable< | |||
| 63 | } | 63 | } |
| 64 | 64 | ||
| 65 | @Override | 65 | @Override |
| 66 | protected TranslateResult<FieldEntry> extendedTranslate(Translator translator, @Nullable EntryMapping mapping) { | 66 | protected TranslateResult<FieldEntry> extendedTranslate(Translator translator, @Nonnull EntryMapping mapping) { |
| 67 | String translatedName = mapping != null ? mapping.getTargetName() : name; | 67 | String translatedName = mapping.targetName() != null ? mapping.targetName() : name; |
| 68 | String docs = mapping != null ? mapping.getJavadoc() : null; | 68 | String docs = mapping.javadoc(); |
| 69 | return TranslateResult.of( | 69 | return TranslateResult.of( |
| 70 | mapping == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED, | 70 | mapping.targetName() == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED, |
| 71 | new FieldEntry(parent, translatedName, translator.translate(desc), docs) | 71 | new FieldEntry(parent, translatedName, translator.translate(desc), docs) |
| 72 | ); | 72 | ); |
| 73 | } | 73 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableDefEntry.java b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableDefEntry.java index 2712c65a..c151de4e 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableDefEntry.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableDefEntry.java | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | package cuchaz.enigma.translation.representation.entry; | 1 | package cuchaz.enigma.translation.representation.entry; |
| 2 | 2 | ||
| 3 | import javax.annotation.Nullable; | 3 | import javax.annotation.Nonnull; |
| 4 | 4 | ||
| 5 | import com.google.common.base.Preconditions; | 5 | import com.google.common.base.Preconditions; |
| 6 | 6 | ||
| @@ -30,12 +30,12 @@ public class LocalVariableDefEntry extends LocalVariableEntry { | |||
| 30 | } | 30 | } |
| 31 | 31 | ||
| 32 | @Override | 32 | @Override |
| 33 | protected TranslateResult<LocalVariableEntry> extendedTranslate(Translator translator, @Nullable EntryMapping mapping) { | 33 | protected TranslateResult<LocalVariableEntry> extendedTranslate(Translator translator, @Nonnull EntryMapping mapping) { |
| 34 | TypeDescriptor translatedDesc = translator.translate(desc); | 34 | TypeDescriptor translatedDesc = translator.translate(desc); |
| 35 | String translatedName = mapping != null ? mapping.getTargetName() : name; | 35 | String translatedName = mapping.targetName() != null ? mapping.targetName() : name; |
| 36 | String javadoc = mapping != null ? mapping.getJavadoc() : javadocs; | 36 | String javadoc = mapping.javadoc(); |
| 37 | return TranslateResult.of( | 37 | return TranslateResult.of( |
| 38 | mapping == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED, | 38 | mapping.targetName() == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED, |
| 39 | new LocalVariableDefEntry(parent, index, translatedName, parameter, translatedDesc, javadoc) | 39 | new LocalVariableDefEntry(parent, index, translatedName, parameter, translatedDesc, javadoc) |
| 40 | ); | 40 | ); |
| 41 | } | 41 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableEntry.java b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableEntry.java index 154f11fd..1cf1a832 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableEntry.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableEntry.java | |||
| @@ -2,7 +2,7 @@ package cuchaz.enigma.translation.representation.entry; | |||
| 2 | 2 | ||
| 3 | import java.util.Objects; | 3 | import java.util.Objects; |
| 4 | 4 | ||
| 5 | import javax.annotation.Nullable; | 5 | import javax.annotation.Nonnull; |
| 6 | 6 | ||
| 7 | import com.google.common.base.Preconditions; | 7 | import com.google.common.base.Preconditions; |
| 8 | 8 | ||
| @@ -50,11 +50,11 @@ public class LocalVariableEntry extends ParentedEntry<MethodEntry> implements Co | |||
| 50 | } | 50 | } |
| 51 | 51 | ||
| 52 | @Override | 52 | @Override |
| 53 | protected TranslateResult<LocalVariableEntry> extendedTranslate(Translator translator, @Nullable EntryMapping mapping) { | 53 | protected TranslateResult<LocalVariableEntry> extendedTranslate(Translator translator, @Nonnull EntryMapping mapping) { |
| 54 | String translatedName = mapping != null ? mapping.getTargetName() : name; | 54 | String translatedName = mapping.targetName() != null ? mapping.targetName() : name; |
| 55 | String javadoc = mapping != null ? mapping.getJavadoc() : null; | 55 | String javadoc = mapping.javadoc(); |
| 56 | return TranslateResult.of( | 56 | return TranslateResult.of( |
| 57 | mapping == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED, | 57 | mapping.targetName() == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED, |
| 58 | new LocalVariableEntry(parent, index, translatedName, parameter, javadoc) | 58 | new LocalVariableEntry(parent, index, translatedName, parameter, javadoc) |
| 59 | ); | 59 | ); |
| 60 | } | 60 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/MethodDefEntry.java b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/MethodDefEntry.java index cc326d6a..30ef706e 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/MethodDefEntry.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/MethodDefEntry.java | |||
| @@ -11,7 +11,7 @@ | |||
| 11 | 11 | ||
| 12 | package cuchaz.enigma.translation.representation.entry; | 12 | package cuchaz.enigma.translation.representation.entry; |
| 13 | 13 | ||
| 14 | import javax.annotation.Nullable; | 14 | import javax.annotation.Nonnull; |
| 15 | 15 | ||
| 16 | import com.google.common.base.Preconditions; | 16 | import com.google.common.base.Preconditions; |
| 17 | 17 | ||
| @@ -53,14 +53,14 @@ public class MethodDefEntry extends MethodEntry implements DefEntry<ClassEntry> | |||
| 53 | } | 53 | } |
| 54 | 54 | ||
| 55 | @Override | 55 | @Override |
| 56 | protected TranslateResult<MethodDefEntry> extendedTranslate(Translator translator, @Nullable EntryMapping mapping) { | 56 | protected TranslateResult<MethodDefEntry> extendedTranslate(Translator translator, @Nonnull EntryMapping mapping) { |
| 57 | MethodDescriptor translatedDesc = translator.translate(descriptor); | 57 | MethodDescriptor translatedDesc = translator.translate(descriptor); |
| 58 | Signature translatedSignature = translator.translate(signature); | 58 | Signature translatedSignature = translator.translate(signature); |
| 59 | String translatedName = mapping != null ? mapping.getTargetName() : name; | 59 | String translatedName = mapping.targetName() != null ? mapping.targetName() : name; |
| 60 | AccessFlags translatedAccess = mapping != null ? mapping.getAccessModifier().transform(access) : access; | 60 | AccessFlags translatedAccess = mapping.accessModifier().transform(access); |
| 61 | String docs = mapping != null ? mapping.getJavadoc() : null; | 61 | String docs = mapping.javadoc(); |
| 62 | return TranslateResult.of( | 62 | return TranslateResult.of( |
| 63 | mapping == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED, | 63 | mapping.targetName() == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED, |
| 64 | new MethodDefEntry(parent, translatedName, translatedDesc, translatedSignature, translatedAccess, docs) | 64 | new MethodDefEntry(parent, translatedName, translatedDesc, translatedSignature, translatedAccess, docs) |
| 65 | ); | 65 | ); |
| 66 | } | 66 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/MethodEntry.java b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/MethodEntry.java index 864a5802..ab9c2d17 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/MethodEntry.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/MethodEntry.java | |||
| @@ -13,7 +13,7 @@ package cuchaz.enigma.translation.representation.entry; | |||
| 13 | 13 | ||
| 14 | import java.util.Objects; | 14 | import java.util.Objects; |
| 15 | 15 | ||
| 16 | import javax.annotation.Nullable; | 16 | import javax.annotation.Nonnull; |
| 17 | 17 | ||
| 18 | import com.google.common.base.Preconditions; | 18 | import com.google.common.base.Preconditions; |
| 19 | 19 | ||
| @@ -58,11 +58,11 @@ public class MethodEntry extends ParentedEntry<ClassEntry> implements Comparable | |||
| 58 | } | 58 | } |
| 59 | 59 | ||
| 60 | @Override | 60 | @Override |
| 61 | protected TranslateResult<? extends MethodEntry> extendedTranslate(Translator translator, @Nullable EntryMapping mapping) { | 61 | protected TranslateResult<? extends MethodEntry> extendedTranslate(Translator translator, @Nonnull EntryMapping mapping) { |
| 62 | String translatedName = mapping != null ? mapping.getTargetName() : name; | 62 | String translatedName = mapping.targetName() != null ? mapping.targetName() : name; |
| 63 | String docs = mapping != null ? mapping.getJavadoc() : null; | 63 | String docs = mapping.javadoc(); |
| 64 | return TranslateResult.of( | 64 | return TranslateResult.of( |
| 65 | mapping == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED, | 65 | mapping.targetName() == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED, |
| 66 | new MethodEntry(parent, translatedName, translator.translate(descriptor), docs) | 66 | new MethodEntry(parent, translatedName, translator.translate(descriptor), docs) |
| 67 | ); | 67 | ); |
| 68 | } | 68 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/ParentedEntry.java b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/ParentedEntry.java index 56348915..267bc11a 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/ParentedEntry.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/ParentedEntry.java | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | 11 | ||
| 12 | package cuchaz.enigma.translation.representation.entry; | 12 | package cuchaz.enigma.translation.representation.entry; |
| 13 | 13 | ||
| 14 | import javax.annotation.Nonnull; | ||
| 14 | import javax.annotation.Nullable; | 15 | import javax.annotation.Nullable; |
| 15 | 16 | ||
| 16 | import com.google.common.base.Preconditions; | 17 | import com.google.common.base.Preconditions; |
| @@ -41,7 +42,7 @@ public abstract class ParentedEntry<P extends Entry<?>> implements Entry<P> { | |||
| 41 | @Override | 42 | @Override |
| 42 | public abstract ParentedEntry<P> withName(String name); | 43 | public abstract ParentedEntry<P> withName(String name); |
| 43 | 44 | ||
| 44 | protected abstract TranslateResult<? extends ParentedEntry<P>> extendedTranslate(Translator translator, @Nullable EntryMapping mapping); | 45 | protected abstract TranslateResult<? extends ParentedEntry<P>> extendedTranslate(Translator translator, @Nonnull EntryMapping mapping); |
| 45 | 46 | ||
| 46 | @Override | 47 | @Override |
| 47 | public String getName() { | 48 | public String getName() { |
| @@ -93,6 +94,6 @@ public abstract class ParentedEntry<P extends Entry<?>> implements Entry<P> { | |||
| 93 | return mapping; | 94 | return mapping; |
| 94 | } | 95 | } |
| 95 | } | 96 | } |
| 96 | return null; | 97 | return EntryMapping.DEFAULT; |
| 97 | } | 98 | } |
| 98 | } | 99 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/utils/TristateChange.java b/enigma/src/main/java/cuchaz/enigma/utils/TristateChange.java new file mode 100644 index 00000000..864154cc --- /dev/null +++ b/enigma/src/main/java/cuchaz/enigma/utils/TristateChange.java | |||
| @@ -0,0 +1,78 @@ | |||
| 1 | package cuchaz.enigma.utils; | ||
| 2 | |||
| 3 | import java.util.Objects; | ||
| 4 | |||
| 5 | public final class TristateChange<T> { | ||
| 6 | |||
| 7 | private static final TristateChange<?> UNCHANGED = new TristateChange<>(Type.UNCHANGED, null); | ||
| 8 | private static final TristateChange<?> RESET = new TristateChange<>(Type.RESET, null); | ||
| 9 | |||
| 10 | private final Type type; | ||
| 11 | private final T val; | ||
| 12 | |||
| 13 | @SuppressWarnings("unchecked") | ||
| 14 | public static <T> TristateChange<T> unchanged() { | ||
| 15 | return (TristateChange<T>) TristateChange.UNCHANGED; | ||
| 16 | } | ||
| 17 | |||
| 18 | @SuppressWarnings("unchecked") | ||
| 19 | public static <T> TristateChange<T> reset() { | ||
| 20 | return (TristateChange<T>) TristateChange.RESET; | ||
| 21 | } | ||
| 22 | |||
| 23 | public static <T> TristateChange<T> set(T value) { | ||
| 24 | return new TristateChange<>(Type.SET, value); | ||
| 25 | } | ||
| 26 | |||
| 27 | private TristateChange(Type type, T val) { | ||
| 28 | this.type = type; | ||
| 29 | this.val = val; | ||
| 30 | } | ||
| 31 | |||
| 32 | public Type getType() { | ||
| 33 | return this.type; | ||
| 34 | } | ||
| 35 | |||
| 36 | public boolean isUnchanged() { | ||
| 37 | return this.type == Type.UNCHANGED; | ||
| 38 | } | ||
| 39 | |||
| 40 | public boolean isReset() { | ||
| 41 | return this.type == Type.RESET; | ||
| 42 | } | ||
| 43 | |||
| 44 | public boolean isSet() { | ||
| 45 | return this.type == Type.SET; | ||
| 46 | } | ||
| 47 | |||
| 48 | public T getNewValue() { | ||
| 49 | if (this.type != Type.SET) throw new IllegalStateException(String.format("No concrete value in %s", this)); | ||
| 50 | return this.val; | ||
| 51 | } | ||
| 52 | |||
| 53 | @Override | ||
| 54 | public boolean equals(Object o) { | ||
| 55 | if (this == o) return true; | ||
| 56 | if (o == null || getClass() != o.getClass()) return false; | ||
| 57 | TristateChange<?> that = (TristateChange<?>) o; | ||
| 58 | return type == that.type && | ||
| 59 | Objects.equals(val, that.val); | ||
| 60 | } | ||
| 61 | |||
| 62 | @Override | ||
| 63 | public int hashCode() { | ||
| 64 | return Objects.hash(type, val); | ||
| 65 | } | ||
| 66 | |||
| 67 | @Override | ||
| 68 | public String toString() { | ||
| 69 | return String.format("TristateChange { type: %s, val: %s }", type, val); | ||
| 70 | } | ||
| 71 | |||
| 72 | public enum Type { | ||
| 73 | UNCHANGED, | ||
| 74 | RESET, | ||
| 75 | SET, | ||
| 76 | } | ||
| 77 | |||
| 78 | } | ||
diff --git a/enigma/src/main/java/cuchaz/enigma/utils/validation/PrintValidatable.java b/enigma/src/main/java/cuchaz/enigma/utils/validation/PrintValidatable.java index 81b6c43f..5067d7e3 100644 --- a/enigma/src/main/java/cuchaz/enigma/utils/validation/PrintValidatable.java +++ b/enigma/src/main/java/cuchaz/enigma/utils/validation/PrintValidatable.java | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | package cuchaz.enigma.utils.validation; | 1 | package cuchaz.enigma.utils.validation; |
| 2 | 2 | ||
| 3 | import java.io.PrintStream; | ||
| 3 | import java.util.Arrays; | 4 | import java.util.Arrays; |
| 4 | 5 | ||
| 5 | public class PrintValidatable implements Validatable { | 6 | public class PrintValidatable implements Validatable { |
| @@ -8,6 +9,10 @@ public class PrintValidatable implements Validatable { | |||
| 8 | 9 | ||
| 9 | @Override | 10 | @Override |
| 10 | public void addMessage(ParameterizedMessage message) { | 11 | public void addMessage(ParameterizedMessage message) { |
| 12 | formatMessage(System.out, message); | ||
| 13 | } | ||
| 14 | |||
| 15 | public static void formatMessage(PrintStream w, ParameterizedMessage message) { | ||
| 11 | String text = message.getText(); | 16 | String text = message.getText(); |
| 12 | String longText = message.getLongText(); | 17 | String longText = message.getLongText(); |
| 13 | String type = switch (message.message.type) { | 18 | String type = switch (message.message.type) { |
| @@ -15,9 +20,10 @@ public class PrintValidatable implements Validatable { | |||
| 15 | case WARNING -> "warning"; | 20 | case WARNING -> "warning"; |
| 16 | case ERROR -> "error"; | 21 | case ERROR -> "error"; |
| 17 | }; | 22 | }; |
| 18 | System.out.printf("%s: %s\n", type, text); | 23 | w.printf("%s: %s\n", type, text); |
| 24 | |||
| 19 | if (!longText.isEmpty()) { | 25 | if (!longText.isEmpty()) { |
| 20 | Arrays.stream(longText.split("\n")).forEach(s -> System.out.printf(" %s\n", s)); | 26 | Arrays.stream(longText.split("\n")).forEach(s -> w.printf(" %s\n", s)); |
| 21 | } | 27 | } |
| 22 | } | 28 | } |
| 23 | 29 | ||
diff --git a/enigma/src/main/java/cuchaz/enigma/utils/validation/ValidationContext.java b/enigma/src/main/java/cuchaz/enigma/utils/validation/ValidationContext.java index ee2b5956..0ecb9fb3 100644 --- a/enigma/src/main/java/cuchaz/enigma/utils/validation/ValidationContext.java +++ b/enigma/src/main/java/cuchaz/enigma/utils/validation/ValidationContext.java | |||
| @@ -62,6 +62,20 @@ public class ValidationContext { | |||
| 62 | return messages.stream().noneMatch(m -> m.message.type == Type.ERROR); | 62 | return messages.stream().noneMatch(m -> m.message.type == Type.ERROR); |
| 63 | } | 63 | } |
| 64 | 64 | ||
| 65 | /** | ||
| 66 | * If this validation context has at least one error, throw an exception. | ||
| 67 | * | ||
| 68 | * @throws IllegalStateException if errors are present | ||
| 69 | */ | ||
| 70 | public void throwOnError() { | ||
| 71 | if (!this.canProceed()) { | ||
| 72 | for (ParameterizedMessage message : this.messages) { | ||
| 73 | PrintValidatable.formatMessage(System.err, message); | ||
| 74 | } | ||
| 75 | throw new IllegalStateException("Errors encountered; cannot continue! Check error log for details."); | ||
| 76 | } | ||
| 77 | } | ||
| 78 | |||
| 65 | public List<ParameterizedMessage> getMessages() { | 79 | public List<ParameterizedMessage> getMessages() { |
| 66 | return Collections.unmodifiableList(messages); | 80 | return Collections.unmodifiableList(messages); |
| 67 | } | 81 | } |
diff --git a/enigma/src/test/java/cuchaz/enigma/translation/mapping/TestReadWriteCycle.java b/enigma/src/test/java/cuchaz/enigma/translation/mapping/TestReadWriteCycle.java index 4f6654a4..510dd3cd 100644 --- a/enigma/src/test/java/cuchaz/enigma/translation/mapping/TestReadWriteCycle.java +++ b/enigma/src/test/java/cuchaz/enigma/translation/mapping/TestReadWriteCycle.java | |||
| @@ -85,18 +85,18 @@ public class TestReadWriteCycle { | |||
| 85 | Assert.assertTrue("Loaded mappings don't contain testMethod1", loadedMappings.contains(testMethod1.a)); | 85 | Assert.assertTrue("Loaded mappings don't contain testMethod1", loadedMappings.contains(testMethod1.a)); |
| 86 | Assert.assertTrue("Loaded mappings don't contain testMethod2", loadedMappings.contains(testMethod2.a)); | 86 | Assert.assertTrue("Loaded mappings don't contain testMethod2", loadedMappings.contains(testMethod2.a)); |
| 87 | 87 | ||
| 88 | Assert.assertEquals("Incorrect mapping: testClazz", testClazz.b.getTargetName(), loadedMappings.get(testClazz.a).getTargetName()); | 88 | Assert.assertEquals("Incorrect mapping: testClazz", testClazz.b.targetName(), loadedMappings.get(testClazz.a).targetName()); |
| 89 | Assert.assertEquals("Incorrect mapping: testField1", testField1.b.getTargetName(), loadedMappings.get(testField1.a).getTargetName()); | 89 | Assert.assertEquals("Incorrect mapping: testField1", testField1.b.targetName(), loadedMappings.get(testField1.a).targetName()); |
| 90 | Assert.assertEquals("Incorrect mapping: testField2", testField2.b.getTargetName(), loadedMappings.get(testField2.a).getTargetName()); | 90 | Assert.assertEquals("Incorrect mapping: testField2", testField2.b.targetName(), loadedMappings.get(testField2.a).targetName()); |
| 91 | Assert.assertEquals("Incorrect mapping: testMethod1", testMethod1.b.getTargetName(), loadedMappings.get(testMethod1.a).getTargetName()); | 91 | Assert.assertEquals("Incorrect mapping: testMethod1", testMethod1.b.targetName(), loadedMappings.get(testMethod1.a).targetName()); |
| 92 | Assert.assertEquals("Incorrect mapping: testMethod2", testMethod2.b.getTargetName(), loadedMappings.get(testMethod2.a).getTargetName()); | 92 | Assert.assertEquals("Incorrect mapping: testMethod2", testMethod2.b.targetName(), loadedMappings.get(testMethod2.a).targetName()); |
| 93 | 93 | ||
| 94 | if (supportsJavadoc) { | 94 | if (supportsJavadoc) { |
| 95 | Assert.assertEquals("Incorrect javadoc: testClazz", testClazz.b.getJavadoc(), loadedMappings.get(testClazz.a).getJavadoc()); | 95 | Assert.assertEquals("Incorrect javadoc: testClazz", testClazz.b.javadoc(), loadedMappings.get(testClazz.a).javadoc()); |
| 96 | Assert.assertEquals("Incorrect javadoc: testField1", testField1.b.getJavadoc(), loadedMappings.get(testField1.a).getJavadoc()); | 96 | Assert.assertEquals("Incorrect javadoc: testField1", testField1.b.javadoc(), loadedMappings.get(testField1.a).javadoc()); |
| 97 | Assert.assertEquals("Incorrect javadoc: testField2", testField2.b.getJavadoc(), loadedMappings.get(testField2.a).getJavadoc()); | 97 | Assert.assertEquals("Incorrect javadoc: testField2", testField2.b.javadoc(), loadedMappings.get(testField2.a).javadoc()); |
| 98 | Assert.assertEquals("Incorrect javadoc: testMethod1", testMethod1.b.getJavadoc(), loadedMappings.get(testMethod1.a).getJavadoc()); | 98 | Assert.assertEquals("Incorrect javadoc: testMethod1", testMethod1.b.javadoc(), loadedMappings.get(testMethod1.a).javadoc()); |
| 99 | Assert.assertEquals("Incorrect javadoc: testMethod2", testMethod2.b.getJavadoc(), loadedMappings.get(testMethod2.a).getJavadoc()); | 99 | Assert.assertEquals("Incorrect javadoc: testMethod2", testMethod2.b.javadoc(), loadedMappings.get(testMethod2.a).javadoc()); |
| 100 | } | 100 | } |
| 101 | 101 | ||
| 102 | tempFile.delete(); | 102 | tempFile.delete(); |