diff options
| author | 2022-09-14 13:12:55 +0100 | |
|---|---|---|
| committer | 2022-09-14 13:12:55 +0100 | |
| commit | 9c736848fb7aa82d295b3aa2946e6cd132ee998f (patch) | |
| tree | b982613cfa7201b2db25cb64a5950f9a2c34a5b3 /enigma-server | |
| parent | Nested packages in Swing UI (#458) (diff) | |
| download | enigma-fork-9c736848fb7aa82d295b3aa2946e6cd132ee998f.tar.gz enigma-fork-9c736848fb7aa82d295b3aa2946e6cd132ee998f.tar.xz enigma-fork-9c736848fb7aa82d295b3aa2946e6cd132ee998f.zip | |
Add checkstyle (#460)
Diffstat (limited to 'enigma-server')
23 files changed, 358 insertions, 234 deletions
diff --git a/enigma-server/build.gradle b/enigma-server/build.gradle index 2764558..873adb9 100644 --- a/enigma-server/build.gradle +++ b/enigma-server/build.gradle | |||
| @@ -1,10 +1,10 @@ | |||
| 1 | plugins { | 1 | plugins { |
| 2 | id 'application' | 2 | id 'application' |
| 3 | } | 3 | } |
| 4 | 4 | ||
| 5 | dependencies { | 5 | dependencies { |
| 6 | implementation project(':enigma') | 6 | implementation project(':enigma') |
| 7 | implementation 'net.sf.jopt-simple:jopt-simple:6.0-alpha-3' | 7 | implementation 'net.sf.jopt-simple:jopt-simple:6.0-alpha-3' |
| 8 | } | 8 | } |
| 9 | 9 | ||
| 10 | mainClassName = 'cuchaz.enigma.network.DedicatedEnigmaServer' | 10 | mainClassName = 'cuchaz.enigma.network.DedicatedEnigmaServer' |
diff --git a/enigma-server/docs/protocol.md b/enigma-server/docs/protocol.md index 83ef4c0..f642e13 100644 --- a/enigma-server/docs/protocol.md +++ b/enigma-server/docs/protocol.md | |||
| @@ -1,4 +1,5 @@ | |||
| 1 | # Enigma protocol | 1 | # Enigma protocol |
| 2 | |||
| 2 | Enigma uses TCP sockets for communication. Data is sent in each direction as a continuous stream, with packets being | 3 | Enigma uses TCP sockets for communication. Data is sent in each direction as a continuous stream, with packets being |
| 3 | concatenated one after the other. | 4 | concatenated one after the other. |
| 4 | 5 | ||
| @@ -10,6 +11,7 @@ use the same modified UTF format as in `DataOutputStream`, I repeat, the normal | |||
| 10 | Strings, see below. | 11 | Strings, see below. |
| 11 | 12 | ||
| 12 | ## Login protocol | 13 | ## Login protocol |
| 14 | |||
| 13 | ``` | 15 | ``` |
| 14 | Client Server | 16 | Client Server |
| 15 | | | | 17 | | | |
| @@ -22,6 +24,7 @@ Client Server | |||
| 22 | | ConfirmChange | | 24 | | ConfirmChange | |
| 23 | | >>>>>>>>>>>>> | | 25 | | >>>>>>>>>>>>> | |
| 24 | ``` | 26 | ``` |
| 27 | |||
| 25 | 1. On connect, the client sends a login packet to the server. This allows the server to test the validity of the client, | 28 | 1. On connect, the client sends a login packet to the server. This allows the server to test the validity of the client, |
| 26 | as well as allowing the client to declare metadata about itself, such as the username. | 29 | as well as allowing the client to declare metadata about itself, such as the username. |
| 27 | 1. After validating the login packet, the server sends all its mappings to the client, and the client will apply them. | 30 | 1. After validating the login packet, the server sends all its mappings to the client, and the client will apply them. |
| @@ -29,15 +32,18 @@ Client Server | |||
| 29 | has received the mappings and is in sync with the server. Once the server receives this packet, the client will be | 32 | has received the mappings and is in sync with the server. Once the server receives this packet, the client will be |
| 30 | allowed to modify mappings. | 33 | allowed to modify mappings. |
| 31 | 34 | ||
| 32 | The server will not accept any other packets from the client until this entire exchange has been completed. | 35 | The server will not accept any other packets from the client until this entire exchange has been completed. |
| 33 | 36 | ||
| 34 | ## Kicking clients | 37 | ## Kicking clients |
| 38 | |||
| 35 | When the server kicks a client, it may optionally send a `Kick` packet immediately before closing the connection, which | 39 | When the server kicks a client, it may optionally send a `Kick` packet immediately before closing the connection, which |
| 36 | contains the reason why the client was kicked (so the client can display it to the user). This is not required though - | 40 | contains the reason why the client was kicked (so the client can display it to the user). This is not required though - |
| 37 | the server may simply terminate the connection. | 41 | the server may simply terminate the connection. |
| 38 | 42 | ||
| 39 | ## Changing mappings | 43 | ## Changing mappings |
| 44 | |||
| 40 | This section uses the example of renaming, but the same pattern applies to all mapping changes. | 45 | This section uses the example of renaming, but the same pattern applies to all mapping changes. |
| 46 | |||
| 41 | ``` | 47 | ``` |
| 42 | Client A Server Client B | 48 | Client A Server Client B |
| 43 | | | | | 49 | | | | |
| @@ -66,19 +72,23 @@ Client A Server Client B | |||
| 66 | server will unlock that mapping for that client and allow them to make changes again. | 72 | server will unlock that mapping for that client and allow them to make changes again. |
| 67 | 73 | ||
| 68 | ## Packets | 74 | ## Packets |
| 75 | |||
| 69 | ```c | 76 | ```c |
| 70 | struct Packet { | 77 | struct Packet { |
| 71 | unsigned short packet_id; | 78 | unsigned short packet_id; |
| 72 | data[]; // depends on packet_id | 79 | data[]; // depends on packet_id |
| 73 | } | 80 | } |
| 74 | ``` | 81 | ``` |
| 82 | |||
| 75 | The IDs for client-to-server packets are as follows: | 83 | The IDs for client-to-server packets are as follows: |
| 84 | |||
| 76 | - 0: `Login` | 85 | - 0: `Login` |
| 77 | - 1: `ConfirmChange` | 86 | - 1: `ConfirmChange` |
| 78 | - 6: `Message` | 87 | - 6: `Message` |
| 79 | - 7: `EntryChange` | 88 | - 7: `EntryChange` |
| 80 | 89 | ||
| 81 | The IDs for server-to-client packets are as follows: | 90 | The IDs for server-to-client packets are as follows: |
| 91 | |||
| 82 | - 0: `Kick` | 92 | - 0: `Kick` |
| 83 | - 1: `SyncMappings` | 93 | - 1: `SyncMappings` |
| 84 | - 6: `Message` | 94 | - 6: `Message` |
| @@ -86,17 +96,20 @@ The IDs for server-to-client packets are as follows: | |||
| 86 | - 8: `EntryChange` | 96 | - 8: `EntryChange` |
| 87 | 97 | ||
| 88 | ### The utf struct | 98 | ### The utf struct |
| 99 | |||
| 89 | ```c | 100 | ```c |
| 90 | struct utf { | 101 | struct utf { |
| 91 | unsigned short length; | 102 | unsigned short length; |
| 92 | byte data[length]; | 103 | byte data[length]; |
| 93 | } | 104 | } |
| 94 | ``` | 105 | ``` |
| 106 | |||
| 95 | - `length`: The number of bytes in the UTF-8 encoding of the string. Note, this may not be the same as the number of | 107 | - `length`: The number of bytes in the UTF-8 encoding of the string. Note, this may not be the same as the number of |
| 96 | Unicode characters in the string. | 108 | Unicode characters in the string. |
| 97 | - `data`: A standard UTF-8 encoded byte array representing the string. | 109 | - `data`: A standard UTF-8 encoded byte array representing the string. |
| 98 | 110 | ||
| 99 | ### The Entry struct | 111 | ### The Entry struct |
| 112 | |||
| 100 | ```c | 113 | ```c |
| 101 | enum EntryType { | 114 | enum EntryType { |
| 102 | ENTRY_CLASS = 0, ENTRY_FIELD = 1, ENTRY_METHOD = 2, ENTRY_LOCAL_VAR = 3; | 115 | ENTRY_CLASS = 0, ENTRY_FIELD = 1, ENTRY_METHOD = 2, ENTRY_LOCAL_VAR = 3; |
| @@ -121,9 +134,10 @@ struct Entry { | |||
| 121 | } | 134 | } |
| 122 | } | 135 | } |
| 123 | ``` | 136 | ``` |
| 137 | |||
| 124 | - `type`: The type of entry this is. One of `ENTRY_CLASS`, `ENTRY_FIELD`, `ENTRY_METHOD` or `ENTRY_LOCAL_VAR`. | 138 | - `type`: The type of entry this is. One of `ENTRY_CLASS`, `ENTRY_FIELD`, `ENTRY_METHOD` or `ENTRY_LOCAL_VAR`. |
| 125 | - `parent`: The parent entry. Only class entries may have no parent. fields, methods and inner classes must have their | 139 | - `parent`: The parent entry. Only class entries may have no parent. fields, methods and inner classes must have their |
| 126 | containing class as their parent. Local variables have a method as a parent. | 140 | containing class as their parent. Local variables have a method as a parent. |
| 127 | - `name`: The class/field/method/variable name. | 141 | - `name`: The class/field/method/variable name. |
| 128 | - `javadoc`: The javadoc of an entry, if present. | 142 | - `javadoc`: The javadoc of an entry, if present. |
| 129 | - `descriptor`: The field/method descriptor. | 143 | - `descriptor`: The field/method descriptor. |
| @@ -131,6 +145,7 @@ struct Entry { | |||
| 131 | - `parameter`: Whether the local variable is a parameter. | 145 | - `parameter`: Whether the local variable is a parameter. |
| 132 | 146 | ||
| 133 | ### The Message struct | 147 | ### The Message struct |
| 148 | |||
| 134 | ```c | 149 | ```c |
| 135 | enum MessageType { | 150 | enum MessageType { |
| 136 | MESSAGE_CHAT = 0, | 151 | MESSAGE_CHAT = 0, |
| @@ -176,8 +191,9 @@ struct Message { | |||
| 176 | } data; | 191 | } data; |
| 177 | }; | 192 | }; |
| 178 | ``` | 193 | ``` |
| 194 | |||
| 179 | - `type`: The type of message this is. One of `MESSAGE_CHAT`, `MESSAGE_CONNECT`, `MESSAGE_DISCONNECT`, | 195 | - `type`: The type of message this is. One of `MESSAGE_CHAT`, `MESSAGE_CONNECT`, `MESSAGE_DISCONNECT`, |
| 180 | `MESSAGE_EDIT_DOCS`, `MESSAGE_MARK_DEOBF`, `MESSAGE_REMOVE_MAPPING`, `MESSAGE_RENAME`. | 196 | `MESSAGE_EDIT_DOCS`, `MESSAGE_MARK_DEOBF`, `MESSAGE_REMOVE_MAPPING`, `MESSAGE_RENAME`. |
| 181 | - `chat`: Chat message. Use in case `type` is `MESSAGE_CHAT` | 197 | - `chat`: Chat message. Use in case `type` is `MESSAGE_CHAT` |
| 182 | - `connect`: Sent when a user connects. Use in case `type` is `MESSAGE_CONNECT` | 198 | - `connect`: Sent when a user connects. Use in case `type` is `MESSAGE_CONNECT` |
| 183 | - `disconnect`: Sent when a user disconnects. Use in case `type` is `MESSAGE_DISCONNECT` | 199 | - `disconnect`: Sent when a user disconnects. Use in case `type` is `MESSAGE_DISCONNECT` |
| @@ -191,6 +207,7 @@ struct Message { | |||
| 191 | - `new_name`: The new name for the entry. | 207 | - `new_name`: The new name for the entry. |
| 192 | 208 | ||
| 193 | ### The entry_change struct | 209 | ### The entry_change struct |
| 210 | |||
| 194 | ```c | 211 | ```c |
| 195 | typedef enum tristate_change { | 212 | typedef enum tristate_change { |
| 196 | TRISTATE_CHANGE_UNCHANGED = 0, | 213 | TRISTATE_CHANGE_UNCHANGED = 0, |
| @@ -224,6 +241,7 @@ struct entry_change { | |||
| 224 | } | 241 | } |
| 225 | } | 242 | } |
| 226 | ``` | 243 | ``` |
| 244 | |||
| 227 | - `entry`: The entry this change gets applied to. | 245 | - `entry`: The entry this change gets applied to. |
| 228 | - `flags`: See definition of `entry_change_flags`. | 246 | - `flags`: See definition of `entry_change_flags`. |
| 229 | - `deobf_name`: The new deobfuscated name, if deobf_name_change == TRISTATE_CHANGE_SET | 247 | - `deobf_name`: The new deobfuscated name, if deobf_name_change == TRISTATE_CHANGE_SET |
| @@ -231,6 +249,7 @@ struct entry_change { | |||
| 231 | - `access_modifiers`: The new access modifier, if access_change == TRISTATE_CHANGE_SET (otherwise 0) | 249 | - `access_modifiers`: The new access modifier, if access_change == TRISTATE_CHANGE_SET (otherwise 0) |
| 232 | 250 | ||
| 233 | ### Login (client-to-server) | 251 | ### Login (client-to-server) |
| 252 | |||
| 234 | ```c | 253 | ```c |
| 235 | struct LoginC2SPacket { | 254 | struct LoginC2SPacket { |
| 236 | unsigned short protocol_version; | 255 | unsigned short protocol_version; |
| @@ -240,47 +259,57 @@ struct LoginC2SPacket { | |||
| 240 | utf username; | 259 | utf username; |
| 241 | } | 260 | } |
| 242 | ``` | 261 | ``` |
| 262 | |||
| 243 | - `protocol_version`: the version of the protocol. If the version does not match on the server, then the client will be | 263 | - `protocol_version`: the version of the protocol. If the version does not match on the server, then the client will be |
| 244 | kicked immediately. Currently always equal to 0. | 264 | kicked immediately. Currently always equal to 0. |
| 245 | - `checksum`: the SHA-1 hash of the JAR file the client has open. If this does not match the SHA-1 hash of the JAR file | 265 | - `checksum`: the SHA-1 hash of the JAR file the client has open. If this does not match the SHA-1 hash of the JAR file |
| 246 | the server has open, the client will be kicked. | 266 | the server has open, the client will be kicked. |
| 247 | - `password`: the password needed to log into the server. Note that each `char` is 2 bytes, as per the Java data type. | 267 | - `password`: the password needed to log into the server. Note that each `char` is 2 bytes, as per the Java data type. |
| 248 | If this password is incorrect, the client will be kicked. | 268 | If this password is incorrect, the client will be kicked. |
| 249 | - `username`: the username of the user logging in. If the username is not unique, the client will be kicked. | 269 | - `username`: the username of the user logging in. If the username is not unique, the client will be kicked. |
| 250 | 270 | ||
| 251 | ### ConfirmChange (client-to-server) | 271 | ### ConfirmChange (client-to-server) |
| 272 | |||
| 252 | ```c | 273 | ```c |
| 253 | struct ConfirmChangeC2SPacket { | 274 | struct ConfirmChangeC2SPacket { |
| 254 | unsigned short sync_id; | 275 | unsigned short sync_id; |
| 255 | } | 276 | } |
| 256 | ``` | 277 | ``` |
| 278 | |||
| 257 | - `sync_id`: the sync ID to confirm. | 279 | - `sync_id`: the sync ID to confirm. |
| 258 | 280 | ||
| 259 | ### Message (client-to-server) | 281 | ### Message (client-to-server) |
| 282 | |||
| 260 | ```c | 283 | ```c |
| 261 | struct MessageC2SPacket { | 284 | struct MessageC2SPacket { |
| 262 | utf message; | 285 | utf message; |
| 263 | } | 286 | } |
| 264 | ``` | 287 | ``` |
| 288 | |||
| 265 | - `message`: The text message the user sent. | 289 | - `message`: The text message the user sent. |
| 266 | 290 | ||
| 267 | ### EntryChange (client-to-server) | 291 | ### EntryChange (client-to-server) |
| 292 | |||
| 268 | ```c | 293 | ```c |
| 269 | struct EntryChangeC2SPacket { | 294 | struct EntryChangeC2SPacket { |
| 270 | entry_change change; | 295 | entry_change change; |
| 271 | } | 296 | } |
| 272 | ``` | 297 | ``` |
| 298 | |||
| 273 | - `change`: The change to apply. | 299 | - `change`: The change to apply. |
| 274 | 300 | ||
| 275 | ### Kick (server-to-client) | 301 | ### Kick (server-to-client) |
| 302 | |||
| 276 | ```c | 303 | ```c |
| 277 | struct KickS2CPacket { | 304 | struct KickS2CPacket { |
| 278 | utf reason; | 305 | utf reason; |
| 279 | } | 306 | } |
| 280 | ``` | 307 | ``` |
| 308 | |||
| 281 | - `reason`: the reason for the kick, may or may not be a translation key for the client to display to the user. | 309 | - `reason`: the reason for the kick, may or may not be a translation key for the client to display to the user. |
| 282 | 310 | ||
| 283 | ### SyncMappings (server-to-client) | 311 | ### SyncMappings (server-to-client) |
| 312 | |||
| 284 | ```c | 313 | ```c |
| 285 | struct SyncMappingsS2CPacket { | 314 | struct SyncMappingsS2CPacket { |
| 286 | int num_roots; | 315 | int num_roots; |
| @@ -296,6 +325,7 @@ struct MappingNode { | |||
| 296 | } | 325 | } |
| 297 | typedef { Entry but without the has_parent or parent fields } NoParentEntry; | 326 | typedef { Entry but without the has_parent or parent fields } NoParentEntry; |
| 298 | ``` | 327 | ``` |
| 328 | |||
| 299 | - `roots`: The root mapping nodes, containing all the entries without parents. | 329 | - `roots`: The root mapping nodes, containing all the entries without parents. |
| 300 | - `obf_entry`: The value of a node, containing the obfuscated name and descriptor of the entry. | 330 | - `obf_entry`: The value of a node, containing the obfuscated name and descriptor of the entry. |
| 301 | - `name`: The deobfuscated name of the entry, if it exists, otherwise the empty string. | 331 | - `name`: The deobfuscated name of the entry, if it exists, otherwise the empty string. |
| @@ -303,6 +333,7 @@ typedef { Entry but without the has_parent or parent fields } NoParentEntry; | |||
| 303 | - `children`: The children of this node | 333 | - `children`: The children of this node |
| 304 | 334 | ||
| 305 | ### Message (server-to-client) | 335 | ### Message (server-to-client) |
| 336 | |||
| 306 | ```c | 337 | ```c |
| 307 | struct MessageS2CPacket { | 338 | struct MessageS2CPacket { |
| 308 | Message message; | 339 | Message message; |
| @@ -310,6 +341,7 @@ struct MessageS2CPacket { | |||
| 310 | ``` | 341 | ``` |
| 311 | 342 | ||
| 312 | ### UserList (server-to-client) | 343 | ### UserList (server-to-client) |
| 344 | |||
| 313 | ```c | 345 | ```c |
| 314 | struct UserListS2CPacket { | 346 | struct UserListS2CPacket { |
| 315 | unsigned short len; | 347 | unsigned short len; |
| @@ -318,11 +350,13 @@ struct UserListS2CPacket { | |||
| 318 | ``` | 350 | ``` |
| 319 | 351 | ||
| 320 | ### EntryChange (server-to-client) | 352 | ### EntryChange (server-to-client) |
| 353 | |||
| 321 | ```c | 354 | ```c |
| 322 | struct EntryChangeS2CPacket { | 355 | struct EntryChangeS2CPacket { |
| 323 | uint16_t sync_id; | 356 | uint16_t sync_id; |
| 324 | entry_change change; | 357 | entry_change change; |
| 325 | } | 358 | } |
| 326 | ``` | 359 | ``` |
| 360 | |||
| 327 | - `sync_id`: The sync ID of the change for locking purposes. | 361 | - `sync_id`: The sync ID of the change for locking purposes. |
| 328 | - `change`: The change to apply. \ No newline at end of file | 362 | - `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 a651fe8..8fcd437 100644 --- a/enigma-server/src/main/java/cuchaz/enigma/network/ClientPacketHandler.java +++ b/enigma-server/src/main/java/cuchaz/enigma/network/ClientPacketHandler.java | |||
| @@ -1,22 +1,22 @@ | |||
| 1 | package cuchaz.enigma.network; | 1 | package cuchaz.enigma.network; |
| 2 | 2 | ||
| 3 | import java.util.List; | ||
| 4 | |||
| 5 | import cuchaz.enigma.network.packet.Packet; | ||
| 3 | import cuchaz.enigma.translation.mapping.EntryChange; | 6 | import cuchaz.enigma.translation.mapping.EntryChange; |
| 4 | import cuchaz.enigma.translation.mapping.EntryMapping; | 7 | import cuchaz.enigma.translation.mapping.EntryMapping; |
| 5 | import cuchaz.enigma.translation.mapping.tree.EntryTree; | 8 | import cuchaz.enigma.translation.mapping.tree.EntryTree; |
| 6 | import cuchaz.enigma.network.packet.Packet; | ||
| 7 | |||
| 8 | import java.util.List; | ||
| 9 | 9 | ||
| 10 | public interface ClientPacketHandler { | 10 | public interface ClientPacketHandler { |
| 11 | void openMappings(EntryTree<EntryMapping> mappings); | 11 | void openMappings(EntryTree<EntryMapping> mappings); |
| 12 | 12 | ||
| 13 | boolean applyChangeFromServer(EntryChange<?> change); | 13 | boolean applyChangeFromServer(EntryChange<?> change); |
| 14 | 14 | ||
| 15 | void disconnectIfConnected(String reason); | 15 | void disconnectIfConnected(String reason); |
| 16 | 16 | ||
| 17 | void sendPacket(Packet<ServerPacketHandler> packet); | 17 | void sendPacket(Packet<ServerPacketHandler> packet); |
| 18 | 18 | ||
| 19 | void addMessage(Message message); | 19 | void addMessage(Message message); |
| 20 | 20 | ||
| 21 | void updateUserList(List<String> users); | 21 | void updateUserList(List<String> users); |
| 22 | } | 22 | } |
diff --git a/enigma-server/src/main/java/cuchaz/enigma/network/DedicatedEnigmaServer.java b/enigma-server/src/main/java/cuchaz/enigma/network/DedicatedEnigmaServer.java index 41f0834..eb22a50 100644 --- a/enigma-server/src/main/java/cuchaz/enigma/network/DedicatedEnigmaServer.java +++ b/enigma-server/src/main/java/cuchaz/enigma/network/DedicatedEnigmaServer.java | |||
| @@ -1,17 +1,5 @@ | |||
| 1 | package cuchaz.enigma.network; | 1 | package cuchaz.enigma.network; |
| 2 | 2 | ||
| 3 | import com.google.common.io.MoreFiles; | ||
| 4 | import cuchaz.enigma.*; | ||
| 5 | import cuchaz.enigma.classprovider.ClasspathClassProvider; | ||
| 6 | import cuchaz.enigma.translation.mapping.serde.MappingParseException; | ||
| 7 | import cuchaz.enigma.translation.mapping.EntryRemapper; | ||
| 8 | import cuchaz.enigma.translation.mapping.serde.MappingFormat; | ||
| 9 | import cuchaz.enigma.utils.Utils; | ||
| 10 | import joptsimple.OptionParser; | ||
| 11 | import joptsimple.OptionSet; | ||
| 12 | import joptsimple.OptionSpec; | ||
| 13 | import joptsimple.ValueConverter; | ||
| 14 | |||
| 15 | import java.io.IOException; | 3 | import java.io.IOException; |
| 16 | import java.io.PrintWriter; | 4 | import java.io.PrintWriter; |
| 17 | import java.nio.file.Files; | 5 | import java.nio.file.Files; |
| @@ -22,24 +10,30 @@ import java.util.concurrent.Executors; | |||
| 22 | import java.util.concurrent.LinkedBlockingDeque; | 10 | import java.util.concurrent.LinkedBlockingDeque; |
| 23 | import java.util.concurrent.TimeUnit; | 11 | import java.util.concurrent.TimeUnit; |
| 24 | 12 | ||
| 25 | public class DedicatedEnigmaServer extends EnigmaServer { | 13 | import com.google.common.io.MoreFiles; |
| 14 | import joptsimple.OptionParser; | ||
| 15 | import joptsimple.OptionSet; | ||
| 16 | import joptsimple.OptionSpec; | ||
| 17 | import joptsimple.ValueConverter; | ||
| 18 | |||
| 19 | import cuchaz.enigma.Enigma; | ||
| 20 | import cuchaz.enigma.EnigmaProfile; | ||
| 21 | import cuchaz.enigma.EnigmaProject; | ||
| 22 | import cuchaz.enigma.ProgressListener; | ||
| 23 | import cuchaz.enigma.classprovider.ClasspathClassProvider; | ||
| 24 | import cuchaz.enigma.translation.mapping.EntryRemapper; | ||
| 25 | import cuchaz.enigma.translation.mapping.serde.MappingFormat; | ||
| 26 | import cuchaz.enigma.translation.mapping.serde.MappingParseException; | ||
| 27 | import cuchaz.enigma.utils.Utils; | ||
| 26 | 28 | ||
| 29 | public class DedicatedEnigmaServer extends EnigmaServer { | ||
| 27 | private final EnigmaProfile profile; | 30 | private final EnigmaProfile profile; |
| 28 | private final MappingFormat mappingFormat; | 31 | private final MappingFormat mappingFormat; |
| 29 | private final Path mappingsFile; | 32 | private final Path mappingsFile; |
| 30 | private final PrintWriter log; | 33 | private final PrintWriter log; |
| 31 | private BlockingQueue<Runnable> tasks = new LinkedBlockingDeque<>(); | 34 | private BlockingQueue<Runnable> tasks = new LinkedBlockingDeque<>(); |
| 32 | 35 | ||
| 33 | public DedicatedEnigmaServer( | 36 | public DedicatedEnigmaServer(byte[] jarChecksum, char[] password, EnigmaProfile profile, MappingFormat mappingFormat, Path mappingsFile, PrintWriter log, EntryRemapper mappings, int port) { |
| 34 | byte[] jarChecksum, | ||
| 35 | char[] password, | ||
| 36 | EnigmaProfile profile, | ||
| 37 | MappingFormat mappingFormat, | ||
| 38 | Path mappingsFile, | ||
| 39 | PrintWriter log, | ||
| 40 | EntryRemapper mappings, | ||
| 41 | int port | ||
| 42 | ) { | ||
| 43 | super(jarChecksum, password, mappings, port); | 37 | super(jarChecksum, password, mappings, port); |
| 44 | this.profile = profile; | 38 | this.profile = profile; |
| 45 | this.mappingFormat = mappingFormat; | 39 | this.mappingFormat = mappingFormat; |
| @@ -61,33 +55,17 @@ public class DedicatedEnigmaServer extends EnigmaServer { | |||
| 61 | public static void main(String[] args) { | 55 | public static void main(String[] args) { |
| 62 | OptionParser parser = new OptionParser(); | 56 | OptionParser parser = new OptionParser(); |
| 63 | 57 | ||
| 64 | OptionSpec<Path> jarOpt = parser.accepts("jar", "Jar file to open at startup") | 58 | OptionSpec<Path> jarOpt = parser.accepts("jar", "Jar file to open at startup").withRequiredArg().required().withValuesConvertedBy(PathConverter.INSTANCE); |
| 65 | .withRequiredArg() | ||
| 66 | .required() | ||
| 67 | .withValuesConvertedBy(PathConverter.INSTANCE); | ||
| 68 | 59 | ||
| 69 | OptionSpec<Path> mappingsOpt = parser.accepts("mappings", "Mappings file to open at startup") | 60 | OptionSpec<Path> mappingsOpt = parser.accepts("mappings", "Mappings file to open at startup").withRequiredArg().required().withValuesConvertedBy(PathConverter.INSTANCE); |
| 70 | .withRequiredArg() | ||
| 71 | .required() | ||
| 72 | .withValuesConvertedBy(PathConverter.INSTANCE); | ||
| 73 | 61 | ||
| 74 | OptionSpec<Path> profileOpt = parser.accepts("profile", "Profile json to apply at startup") | 62 | OptionSpec<Path> profileOpt = parser.accepts("profile", "Profile json to apply at startup").withRequiredArg().withValuesConvertedBy(PathConverter.INSTANCE); |
| 75 | .withRequiredArg() | ||
| 76 | .withValuesConvertedBy(PathConverter.INSTANCE); | ||
| 77 | 63 | ||
| 78 | OptionSpec<Integer> portOpt = parser.accepts("port", "Port to run the server on") | 64 | OptionSpec<Integer> portOpt = parser.accepts("port", "Port to run the server on").withOptionalArg().ofType(Integer.class).defaultsTo(EnigmaServer.DEFAULT_PORT); |
| 79 | .withOptionalArg() | ||
| 80 | .ofType(Integer.class) | ||
| 81 | .defaultsTo(EnigmaServer.DEFAULT_PORT); | ||
| 82 | 65 | ||
| 83 | OptionSpec<String> passwordOpt = parser.accepts("password", "The password to join the server") | 66 | OptionSpec<String> passwordOpt = parser.accepts("password", "The password to join the server").withRequiredArg().defaultsTo(""); |
| 84 | .withRequiredArg() | ||
| 85 | .defaultsTo(""); | ||
| 86 | 67 | ||
| 87 | OptionSpec<Path> logFileOpt = parser.accepts("log", "The log file to write to") | 68 | OptionSpec<Path> logFileOpt = parser.accepts("log", "The log file to write to").withRequiredArg().withValuesConvertedBy(PathConverter.INSTANCE).defaultsTo(Paths.get("log.txt")); |
| 88 | .withRequiredArg() | ||
| 89 | .withValuesConvertedBy(PathConverter.INSTANCE) | ||
| 90 | .defaultsTo(Paths.get("log.txt")); | ||
| 91 | 69 | ||
| 92 | OptionSet parsedArgs = parser.parse(args); | 70 | OptionSet parsedArgs = parser.parse(args); |
| 93 | Path jar = parsedArgs.valueOf(jarOpt); | 71 | Path jar = parsedArgs.valueOf(jarOpt); |
| @@ -95,14 +73,17 @@ public class DedicatedEnigmaServer extends EnigmaServer { | |||
| 95 | Path profileFile = parsedArgs.valueOf(profileOpt); | 73 | Path profileFile = parsedArgs.valueOf(profileOpt); |
| 96 | int port = parsedArgs.valueOf(portOpt); | 74 | int port = parsedArgs.valueOf(portOpt); |
| 97 | char[] password = parsedArgs.valueOf(passwordOpt).toCharArray(); | 75 | char[] password = parsedArgs.valueOf(passwordOpt).toCharArray(); |
| 76 | |||
| 98 | if (password.length > EnigmaServer.MAX_PASSWORD_LENGTH) { | 77 | if (password.length > EnigmaServer.MAX_PASSWORD_LENGTH) { |
| 99 | System.err.println("Password too long, must be at most " + EnigmaServer.MAX_PASSWORD_LENGTH + " characters"); | 78 | System.err.println("Password too long, must be at most " + EnigmaServer.MAX_PASSWORD_LENGTH + " characters"); |
| 100 | System.exit(1); | 79 | System.exit(1); |
| 101 | } | 80 | } |
| 81 | |||
| 102 | Path logFile = parsedArgs.valueOf(logFileOpt); | 82 | Path logFile = parsedArgs.valueOf(logFileOpt); |
| 103 | 83 | ||
| 104 | System.out.println("Starting Enigma server"); | 84 | System.out.println("Starting Enigma server"); |
| 105 | DedicatedEnigmaServer server; | 85 | DedicatedEnigmaServer server; |
| 86 | |||
| 106 | try { | 87 | try { |
| 107 | byte[] checksum = Utils.zipSha1(parsedArgs.valueOf(jarOpt)); | 88 | byte[] checksum = Utils.zipSha1(parsedArgs.valueOf(jarOpt)); |
| 108 | 89 | ||
| @@ -113,10 +94,12 @@ public class DedicatedEnigmaServer extends EnigmaServer { | |||
| 113 | 94 | ||
| 114 | MappingFormat mappingFormat = MappingFormat.ENIGMA_DIRECTORY; | 95 | MappingFormat mappingFormat = MappingFormat.ENIGMA_DIRECTORY; |
| 115 | EntryRemapper mappings; | 96 | EntryRemapper mappings; |
| 97 | |||
| 116 | if (!Files.exists(mappingsFile)) { | 98 | if (!Files.exists(mappingsFile)) { |
| 117 | mappings = EntryRemapper.empty(project.getJarIndex()); | 99 | mappings = EntryRemapper.empty(project.getJarIndex()); |
| 118 | } else { | 100 | } else { |
| 119 | System.out.println("Reading mappings..."); | 101 | System.out.println("Reading mappings..."); |
| 102 | |||
| 120 | if (Files.isDirectory(mappingsFile)) { | 103 | if (Files.isDirectory(mappingsFile)) { |
| 121 | mappingFormat = MappingFormat.ENIGMA_DIRECTORY; | 104 | mappingFormat = MappingFormat.ENIGMA_DIRECTORY; |
| 122 | } else if ("zip".equalsIgnoreCase(MoreFiles.getFileExtension(mappingsFile))) { | 105 | } else if ("zip".equalsIgnoreCase(MoreFiles.getFileExtension(mappingsFile))) { |
| @@ -124,6 +107,7 @@ public class DedicatedEnigmaServer extends EnigmaServer { | |||
| 124 | } else { | 107 | } else { |
| 125 | mappingFormat = MappingFormat.ENIGMA_FILE; | 108 | mappingFormat = MappingFormat.ENIGMA_FILE; |
| 126 | } | 109 | } |
| 110 | |||
| 127 | mappings = EntryRemapper.mapped(project.getJarIndex(), mappingFormat.read(mappingsFile, ProgressListener.none(), profile.getMappingSaveParameters())); | 111 | mappings = EntryRemapper.mapped(project.getJarIndex(), mappingFormat.read(mappingsFile, ProgressListener.none(), profile.getMappingSaveParameters())); |
| 128 | } | 112 | } |
| 129 | 113 | ||
diff --git a/enigma-server/src/main/java/cuchaz/enigma/network/EnigmaClient.java b/enigma-server/src/main/java/cuchaz/enigma/network/EnigmaClient.java index 71bd011..69e4f5e 100644 --- a/enigma-server/src/main/java/cuchaz/enigma/network/EnigmaClient.java +++ b/enigma-server/src/main/java/cuchaz/enigma/network/EnigmaClient.java | |||
| @@ -1,15 +1,20 @@ | |||
| 1 | package cuchaz.enigma.network; | 1 | package cuchaz.enigma.network; |
| 2 | 2 | ||
| 3 | import cuchaz.enigma.network.packet.Packet; | 3 | import java.io.DataInput; |
| 4 | import cuchaz.enigma.network.packet.PacketRegistry; | 4 | import java.io.DataInputStream; |
| 5 | 5 | import java.io.DataOutput; | |
| 6 | import javax.swing.*; | 6 | import java.io.DataOutputStream; |
| 7 | import java.io.*; | 7 | import java.io.EOFException; |
| 8 | import java.io.IOException; | ||
| 8 | import java.net.Socket; | 9 | import java.net.Socket; |
| 9 | import java.net.SocketException; | 10 | import java.net.SocketException; |
| 10 | 11 | ||
| 11 | public class EnigmaClient { | 12 | import javax.swing.SwingUtilities; |
| 12 | 13 | ||
| 14 | import cuchaz.enigma.network.packet.Packet; | ||
| 15 | import cuchaz.enigma.network.packet.PacketRegistry; | ||
| 16 | |||
| 17 | public class EnigmaClient { | ||
| 13 | private final ClientPacketHandler controller; | 18 | private final ClientPacketHandler controller; |
| 14 | 19 | ||
| 15 | private final String ip; | 20 | private final String ip; |
| @@ -29,17 +34,22 @@ public class EnigmaClient { | |||
| 29 | Thread thread = new Thread(() -> { | 34 | Thread thread = new Thread(() -> { |
| 30 | try { | 35 | try { |
| 31 | DataInput input = new DataInputStream(socket.getInputStream()); | 36 | DataInput input = new DataInputStream(socket.getInputStream()); |
| 37 | |||
| 32 | while (true) { | 38 | while (true) { |
| 33 | int packetId; | 39 | int packetId; |
| 40 | |||
| 34 | try { | 41 | try { |
| 35 | packetId = input.readUnsignedByte(); | 42 | packetId = input.readUnsignedByte(); |
| 36 | } catch (EOFException | SocketException e) { | 43 | } catch (EOFException | SocketException e) { |
| 37 | break; | 44 | break; |
| 38 | } | 45 | } |
| 46 | |||
| 39 | Packet<ClientPacketHandler> packet = PacketRegistry.createS2CPacket(packetId); | 47 | Packet<ClientPacketHandler> packet = PacketRegistry.createS2CPacket(packetId); |
| 48 | |||
| 40 | if (packet == null) { | 49 | if (packet == null) { |
| 41 | throw new IOException("Received invalid packet id " + packetId); | 50 | throw new IOException("Received invalid packet id " + packetId); |
| 42 | } | 51 | } |
| 52 | |||
| 43 | packet.read(input); | 53 | packet.read(input); |
| 44 | SwingUtilities.invokeLater(() -> packet.handle(controller)); | 54 | SwingUtilities.invokeLater(() -> packet.handle(controller)); |
| 45 | } | 55 | } |
| @@ -47,6 +57,7 @@ public class EnigmaClient { | |||
| 47 | controller.disconnectIfConnected(e.toString()); | 57 | controller.disconnectIfConnected(e.toString()); |
| 48 | return; | 58 | return; |
| 49 | } | 59 | } |
| 60 | |||
| 50 | controller.disconnectIfConnected("Disconnected"); | 61 | controller.disconnectIfConnected("Disconnected"); |
| 51 | }); | 62 | }); |
| 52 | thread.setName("Client I/O thread"); | 63 | thread.setName("Client I/O thread"); |
| @@ -65,7 +76,6 @@ public class EnigmaClient { | |||
| 65 | } | 76 | } |
| 66 | } | 77 | } |
| 67 | 78 | ||
| 68 | |||
| 69 | public void sendPacket(Packet<ServerPacketHandler> packet) { | 79 | public void sendPacket(Packet<ServerPacketHandler> packet) { |
| 70 | try { | 80 | try { |
| 71 | output.writeByte(PacketRegistry.getC2SId(packet)); | 81 | output.writeByte(PacketRegistry.getC2SId(packet)); |
| @@ -74,5 +84,4 @@ public class EnigmaClient { | |||
| 74 | controller.disconnectIfConnected(e.toString()); | 84 | controller.disconnectIfConnected(e.toString()); |
| 75 | } | 85 | } |
| 76 | } | 86 | } |
| 77 | |||
| 78 | } | 87 | } |
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 1ce359b..8872735 100644 --- a/enigma-server/src/main/java/cuchaz/enigma/network/EnigmaServer.java +++ b/enigma-server/src/main/java/cuchaz/enigma/network/EnigmaServer.java | |||
| @@ -1,20 +1,35 @@ | |||
| 1 | package cuchaz.enigma.network; | 1 | package cuchaz.enigma.network; |
| 2 | 2 | ||
| 3 | import java.io.*; | 3 | import java.io.DataInput; |
| 4 | import java.io.DataInputStream; | ||
| 5 | import java.io.DataOutput; | ||
| 6 | import java.io.DataOutputStream; | ||
| 7 | import java.io.EOFException; | ||
| 8 | import java.io.IOException; | ||
| 4 | import java.net.ServerSocket; | 9 | import java.net.ServerSocket; |
| 5 | import java.net.Socket; | 10 | import java.net.Socket; |
| 6 | import java.net.SocketException; | 11 | import java.net.SocketException; |
| 7 | import java.util.*; | 12 | import java.util.ArrayList; |
| 13 | import java.util.Collections; | ||
| 14 | import java.util.HashMap; | ||
| 15 | import java.util.HashSet; | ||
| 16 | import java.util.List; | ||
| 17 | import java.util.Map; | ||
| 18 | import java.util.Set; | ||
| 8 | import java.util.concurrent.CopyOnWriteArrayList; | 19 | import java.util.concurrent.CopyOnWriteArrayList; |
| 9 | 20 | ||
| 10 | import cuchaz.enigma.network.packet.*; | 21 | import cuchaz.enigma.network.packet.EntryChangeS2CPacket; |
| 22 | import cuchaz.enigma.network.packet.KickS2CPacket; | ||
| 23 | import cuchaz.enigma.network.packet.MessageS2CPacket; | ||
| 24 | import cuchaz.enigma.network.packet.Packet; | ||
| 25 | import cuchaz.enigma.network.packet.PacketRegistry; | ||
| 26 | import cuchaz.enigma.network.packet.UserListS2CPacket; | ||
| 11 | import cuchaz.enigma.translation.mapping.EntryChange; | 27 | import cuchaz.enigma.translation.mapping.EntryChange; |
| 12 | import cuchaz.enigma.translation.mapping.EntryMapping; | 28 | import cuchaz.enigma.translation.mapping.EntryMapping; |
| 13 | import cuchaz.enigma.translation.mapping.EntryRemapper; | 29 | import cuchaz.enigma.translation.mapping.EntryRemapper; |
| 14 | import cuchaz.enigma.translation.representation.entry.Entry; | 30 | import cuchaz.enigma.translation.representation.entry.Entry; |
| 15 | 31 | ||
| 16 | public abstract class EnigmaServer { | 32 | public abstract class EnigmaServer { |
| 17 | |||
| 18 | // https://discordapp.com/channels/507304429255393322/566418023372816394/700292322918793347 | 33 | // https://discordapp.com/channels/507304429255393322/566418023372816394/700292322918793347 |
| 19 | public static final int DEFAULT_PORT = 34712; | 34 | public static final int DEFAULT_PORT = 34712; |
| 20 | public static final int PROTOCOL_VERSION = 1; | 35 | public static final int PROTOCOL_VERSION = 1; |
| @@ -71,17 +86,22 @@ public abstract class EnigmaServer { | |||
| 71 | Thread thread = new Thread(() -> { | 86 | Thread thread = new Thread(() -> { |
| 72 | try { | 87 | try { |
| 73 | DataInput input = new DataInputStream(client.getInputStream()); | 88 | DataInput input = new DataInputStream(client.getInputStream()); |
| 89 | |||
| 74 | while (true) { | 90 | while (true) { |
| 75 | int packetId; | 91 | int packetId; |
| 92 | |||
| 76 | try { | 93 | try { |
| 77 | packetId = input.readUnsignedByte(); | 94 | packetId = input.readUnsignedByte(); |
| 78 | } catch (EOFException | SocketException e) { | 95 | } catch (EOFException | SocketException e) { |
| 79 | break; | 96 | break; |
| 80 | } | 97 | } |
| 98 | |||
| 81 | Packet<ServerPacketHandler> packet = PacketRegistry.createC2SPacket(packetId); | 99 | Packet<ServerPacketHandler> packet = PacketRegistry.createC2SPacket(packetId); |
| 100 | |||
| 82 | if (packet == null) { | 101 | if (packet == null) { |
| 83 | throw new IOException("Received invalid packet id " + packetId); | 102 | throw new IOException("Received invalid packet id " + packetId); |
| 84 | } | 103 | } |
| 104 | |||
| 85 | packet.read(input); | 105 | packet.read(input); |
| 86 | runOnThread(() -> packet.handle(new ServerPacketHandler(client, this))); | 106 | runOnThread(() -> packet.handle(new ServerPacketHandler(client, this))); |
| 87 | } | 107 | } |
| @@ -90,6 +110,7 @@ public abstract class EnigmaServer { | |||
| 90 | e.printStackTrace(); | 110 | e.printStackTrace(); |
| 91 | return; | 111 | return; |
| 92 | } | 112 | } |
| 113 | |||
| 93 | kick(client, "disconnect.disconnected"); | 114 | kick(client, "disconnect.disconnected"); |
| 94 | }); | 115 | }); |
| 95 | thread.setName("Server I/O thread #" + (nextIoId++)); | 116 | thread.setName("Server I/O thread #" + (nextIoId++)); |
| @@ -103,6 +124,7 @@ public abstract class EnigmaServer { | |||
| 103 | for (Socket client : clients) { | 124 | for (Socket client : clients) { |
| 104 | kick(client, "disconnect.server_closed"); | 125 | kick(client, "disconnect.server_closed"); |
| 105 | } | 126 | } |
| 127 | |||
| 106 | try { | 128 | try { |
| 107 | socket.close(); | 129 | socket.close(); |
| 108 | } catch (IOException e) { | 130 | } catch (IOException e) { |
| @@ -114,7 +136,9 @@ public abstract class EnigmaServer { | |||
| 114 | } | 136 | } |
| 115 | 137 | ||
| 116 | public void kick(Socket client, String reason) { | 138 | public void kick(Socket client, String reason) { |
| 117 | if (!clients.remove(client)) return; | 139 | if (!clients.remove(client)) { |
| 140 | return; | ||
| 141 | } | ||
| 118 | 142 | ||
| 119 | sendPacket(client, new KickS2CPacket(reason)); | 143 | sendPacket(client, new KickS2CPacket(reason)); |
| 120 | 144 | ||
| @@ -123,6 +147,7 @@ public abstract class EnigmaServer { | |||
| 123 | return list.isEmpty(); | 147 | return list.isEmpty(); |
| 124 | }); | 148 | }); |
| 125 | String username = usernames.remove(client); | 149 | String username = usernames.remove(client); |
| 150 | |||
| 126 | try { | 151 | try { |
| 127 | client.close(); | 152 | client.close(); |
| 128 | } catch (IOException e) { | 153 | } catch (IOException e) { |
| @@ -134,6 +159,7 @@ public abstract class EnigmaServer { | |||
| 134 | System.out.println("Kicked " + username + " because " + reason); | 159 | System.out.println("Kicked " + username + " because " + reason); |
| 135 | sendMessage(Message.disconnect(username)); | 160 | sendMessage(Message.disconnect(username)); |
| 136 | } | 161 | } |
| 162 | |||
| 137 | sendUsernamePacket(); | 163 | sendUsernamePacket(); |
| 138 | } | 164 | } |
| 139 | 165 | ||
| @@ -159,6 +185,7 @@ public abstract class EnigmaServer { | |||
| 159 | public void sendPacket(Socket client, Packet<ClientPacketHandler> packet) { | 185 | public void sendPacket(Socket client, Packet<ClientPacketHandler> packet) { |
| 160 | if (!client.isClosed()) { | 186 | if (!client.isClosed()) { |
| 161 | int packetId = PacketRegistry.getS2CId(packet); | 187 | int packetId = PacketRegistry.getS2CId(packet); |
| 188 | |||
| 162 | try { | 189 | try { |
| 163 | DataOutput output = new DataOutputStream(client.getOutputStream()); | 190 | DataOutput output = new DataOutputStream(client.getOutputStream()); |
| 164 | output.writeByte(packetId); | 191 | output.writeByte(packetId); |
| @@ -192,9 +219,11 @@ public abstract class EnigmaServer { | |||
| 192 | } | 219 | } |
| 193 | 220 | ||
| 194 | Integer syncId = syncIds.get(entry); | 221 | Integer syncId = syncIds.get(entry); |
| 222 | |||
| 195 | if (syncId == null) { | 223 | if (syncId == null) { |
| 196 | return true; | 224 | return true; |
| 197 | } | 225 | } |
| 226 | |||
| 198 | Set<Socket> clients = clientsNeedingConfirmation.get(syncId); | 227 | Set<Socket> clients = clientsNeedingConfirmation.get(syncId); |
| 199 | return clients == null || !clients.contains(client); | 228 | return clients == null || !clients.contains(client); |
| 200 | } | 229 | } |
| @@ -202,14 +231,18 @@ public abstract class EnigmaServer { | |||
| 202 | public int lockEntry(Socket exception, Entry<?> entry) { | 231 | public int lockEntry(Socket exception, Entry<?> entry) { |
| 203 | int syncId = nextSyncId; | 232 | int syncId = nextSyncId; |
| 204 | nextSyncId++; | 233 | nextSyncId++; |
| 234 | |||
| 205 | // sync id is sent as an unsigned short, can't have more than 65536 | 235 | // sync id is sent as an unsigned short, can't have more than 65536 |
| 206 | if (nextSyncId == 65536) { | 236 | if (nextSyncId == 65536) { |
| 207 | nextSyncId = DUMMY_SYNC_ID + 1; | 237 | nextSyncId = DUMMY_SYNC_ID + 1; |
| 208 | } | 238 | } |
| 239 | |||
| 209 | Integer oldSyncId = syncIds.get(entry); | 240 | Integer oldSyncId = syncIds.get(entry); |
| 241 | |||
| 210 | if (oldSyncId != null) { | 242 | if (oldSyncId != null) { |
| 211 | clientsNeedingConfirmation.remove(oldSyncId); | 243 | clientsNeedingConfirmation.remove(oldSyncId); |
| 212 | } | 244 | } |
| 245 | |||
| 213 | syncIds.put(entry, syncId); | 246 | syncIds.put(entry, syncId); |
| 214 | inverseSyncIds.put(syncId, entry); | 247 | inverseSyncIds.put(syncId, entry); |
| 215 | Set<Socket> clients = new HashSet<>(this.clients); | 248 | Set<Socket> clients = new HashSet<>(this.clients); |
| @@ -224,8 +257,10 @@ public abstract class EnigmaServer { | |||
| 224 | } | 257 | } |
| 225 | 258 | ||
| 226 | Set<Socket> clients = clientsNeedingConfirmation.get(syncId); | 259 | Set<Socket> clients = clientsNeedingConfirmation.get(syncId); |
| 260 | |||
| 227 | if (clients != null) { | 261 | if (clients != null) { |
| 228 | clients.remove(client); | 262 | clients.remove(client); |
| 263 | |||
| 229 | if (clients.isEmpty()) { | 264 | if (clients.isEmpty()) { |
| 230 | clientsNeedingConfirmation.remove(syncId); | 265 | clientsNeedingConfirmation.remove(syncId); |
| 231 | syncIds.remove(inverseSyncIds.remove(syncId)); | 266 | syncIds.remove(inverseSyncIds.remove(syncId)); |
| @@ -236,6 +271,7 @@ public abstract class EnigmaServer { | |||
| 236 | public void sendCorrectMapping(Socket client, Entry<?> entry, boolean refreshClassTree) { | 271 | public void sendCorrectMapping(Socket client, Entry<?> entry, boolean refreshClassTree) { |
| 237 | EntryMapping oldMapping = mappings.getDeobfMapping(entry); | 272 | EntryMapping oldMapping = mappings.getDeobfMapping(entry); |
| 238 | String oldName = oldMapping.targetName(); | 273 | String oldName = oldMapping.targetName(); |
| 274 | |||
| 239 | if (oldName == null) { | 275 | if (oldName == null) { |
| 240 | sendPacket(client, new EntryChangeS2CPacket(DUMMY_SYNC_ID, EntryChange.modify(entry).clearDeobfName())); | 276 | sendPacket(client, new EntryChangeS2CPacket(DUMMY_SYNC_ID, EntryChange.modify(entry).clearDeobfName())); |
| 241 | } else { | 277 | } else { |
| @@ -269,5 +305,4 @@ public abstract class EnigmaServer { | |||
| 269 | log(String.format("[MSG] %s", message.translate())); | 305 | log(String.format("[MSG] %s", message.translate())); |
| 270 | sendToAll(new MessageS2CPacket(message)); | 306 | sendToAll(new MessageS2CPacket(message)); |
| 271 | } | 307 | } |
| 272 | |||
| 273 | } | 308 | } |
diff --git a/enigma-server/src/main/java/cuchaz/enigma/network/IntegratedEnigmaServer.java b/enigma-server/src/main/java/cuchaz/enigma/network/IntegratedEnigmaServer.java index 21c6825..99e4e99 100644 --- a/enigma-server/src/main/java/cuchaz/enigma/network/IntegratedEnigmaServer.java +++ b/enigma-server/src/main/java/cuchaz/enigma/network/IntegratedEnigmaServer.java | |||
| @@ -1,8 +1,8 @@ | |||
| 1 | package cuchaz.enigma.network; | 1 | package cuchaz.enigma.network; |
| 2 | 2 | ||
| 3 | import cuchaz.enigma.translation.mapping.EntryRemapper; | 3 | import javax.swing.SwingUtilities; |
| 4 | 4 | ||
| 5 | import javax.swing.*; | 5 | import cuchaz.enigma.translation.mapping.EntryRemapper; |
| 6 | 6 | ||
| 7 | public class IntegratedEnigmaServer extends EnigmaServer { | 7 | public class IntegratedEnigmaServer extends EnigmaServer { |
| 8 | public IntegratedEnigmaServer(byte[] jarChecksum, char[] password, EntryRemapper mappings, int port) { | 8 | public IntegratedEnigmaServer(byte[] jarChecksum, char[] password, EntryRemapper mappings, int port) { |
diff --git a/enigma-server/src/main/java/cuchaz/enigma/network/Message.java b/enigma-server/src/main/java/cuchaz/enigma/network/Message.java index c157838..d49e60c 100644 --- a/enigma-server/src/main/java/cuchaz/enigma/network/Message.java +++ b/enigma-server/src/main/java/cuchaz/enigma/network/Message.java | |||
| @@ -10,9 +10,8 @@ import cuchaz.enigma.translation.representation.entry.Entry; | |||
| 10 | import cuchaz.enigma.utils.I18n; | 10 | import cuchaz.enigma.utils.I18n; |
| 11 | 11 | ||
| 12 | public abstract class Message { | 12 | public abstract class Message { |
| 13 | |||
| 14 | public final String user; | 13 | public final String user; |
| 15 | 14 | ||
| 16 | public static Chat chat(String user, String message) { | 15 | public static Chat chat(String user, String message) { |
| 17 | return new Chat(user, message); | 16 | return new Chat(user, message); |
| 18 | } | 17 | } |
| @@ -47,34 +46,37 @@ public abstract class Message { | |||
| 47 | 46 | ||
| 48 | public static Message read(DataInput input) throws IOException { | 47 | public static Message read(DataInput input) throws IOException { |
| 49 | byte typeId = input.readByte(); | 48 | byte typeId = input.readByte(); |
| 49 | |||
| 50 | if (typeId < 0 || typeId >= Type.values().length) { | 50 | if (typeId < 0 || typeId >= Type.values().length) { |
| 51 | throw new IOException(String.format("Invalid message type ID %d", typeId)); | 51 | throw new IOException(String.format("Invalid message type ID %d", typeId)); |
| 52 | } | 52 | } |
| 53 | |||
| 53 | Type type = Type.values()[typeId]; | 54 | Type type = Type.values()[typeId]; |
| 54 | String user = input.readUTF(); | 55 | String user = input.readUTF(); |
| 56 | |||
| 55 | switch (type) { | 57 | switch (type) { |
| 56 | case CHAT: | 58 | case CHAT: |
| 57 | String message = input.readUTF(); | 59 | String message = input.readUTF(); |
| 58 | return chat(user, message); | 60 | return chat(user, message); |
| 59 | case CONNECT: | 61 | case CONNECT: |
| 60 | return connect(user); | 62 | return connect(user); |
| 61 | case DISCONNECT: | 63 | case DISCONNECT: |
| 62 | return disconnect(user); | 64 | return disconnect(user); |
| 63 | case EDIT_DOCS: | 65 | case EDIT_DOCS: |
| 64 | Entry<?> entry = PacketHelper.readEntry(input); | 66 | Entry<?> entry = PacketHelper.readEntry(input); |
| 65 | return editDocs(user, entry); | 67 | return editDocs(user, entry); |
| 66 | case MARK_DEOBF: | 68 | case MARK_DEOBF: |
| 67 | entry = PacketHelper.readEntry(input); | 69 | entry = PacketHelper.readEntry(input); |
| 68 | return markDeobf(user, entry); | 70 | return markDeobf(user, entry); |
| 69 | case REMOVE_MAPPING: | 71 | case REMOVE_MAPPING: |
| 70 | entry = PacketHelper.readEntry(input); | 72 | entry = PacketHelper.readEntry(input); |
| 71 | return removeMapping(user, entry); | 73 | return removeMapping(user, entry); |
| 72 | case RENAME: | 74 | case RENAME: |
| 73 | entry = PacketHelper.readEntry(input); | 75 | entry = PacketHelper.readEntry(input); |
| 74 | String newName = input.readUTF(); | 76 | String newName = input.readUTF(); |
| 75 | return rename(user, entry, newName); | 77 | return rename(user, entry, newName); |
| 76 | default: | 78 | default: |
| 77 | throw new IllegalStateException("unreachable"); | 79 | throw new IllegalStateException("unreachable"); |
| 78 | } | 80 | } |
| 79 | } | 81 | } |
| 80 | 82 | ||
| @@ -89,8 +91,14 @@ public abstract class Message { | |||
| 89 | 91 | ||
| 90 | @Override | 92 | @Override |
| 91 | public boolean equals(Object o) { | 93 | public boolean equals(Object o) { |
| 92 | if (this == o) return true; | 94 | if (this == o) { |
| 93 | if (o == null || getClass() != o.getClass()) return false; | 95 | return true; |
| 96 | } | ||
| 97 | |||
| 98 | if (o == null || getClass() != o.getClass()) { | ||
| 99 | return false; | ||
| 100 | } | ||
| 101 | |||
| 94 | Message message = (Message) o; | 102 | Message message = (Message) o; |
| 95 | return Objects.equals(user, message.user); | 103 | return Objects.equals(user, message.user); |
| 96 | } | 104 | } |
| @@ -111,7 +119,6 @@ public abstract class Message { | |||
| 111 | } | 119 | } |
| 112 | 120 | ||
| 113 | public static final class Chat extends Message { | 121 | public static final class Chat extends Message { |
| 114 | |||
| 115 | public final String message; | 122 | public final String message; |
| 116 | 123 | ||
| 117 | private Chat(String user, String message) { | 124 | private Chat(String user, String message) { |
| @@ -137,9 +144,18 @@ public abstract class Message { | |||
| 137 | 144 | ||
| 138 | @Override | 145 | @Override |
| 139 | public boolean equals(Object o) { | 146 | public boolean equals(Object o) { |
| 140 | if (this == o) return true; | 147 | if (this == o) { |
| 141 | if (o == null || getClass() != o.getClass()) return false; | 148 | return true; |
| 142 | if (!super.equals(o)) return false; | 149 | } |
| 150 | |||
| 151 | if (o == null || getClass() != o.getClass()) { | ||
| 152 | return false; | ||
| 153 | } | ||
| 154 | |||
| 155 | if (!super.equals(o)) { | ||
| 156 | return false; | ||
| 157 | } | ||
| 158 | |||
| 143 | Chat chat = (Chat) o; | 159 | Chat chat = (Chat) o; |
| 144 | return Objects.equals(message, chat.message); | 160 | return Objects.equals(message, chat.message); |
| 145 | } | 161 | } |
| @@ -153,11 +169,9 @@ public abstract class Message { | |||
| 153 | public String toString() { | 169 | public String toString() { |
| 154 | return String.format("Message.Chat { user: '%s', message: '%s' }", user, message); | 170 | return String.format("Message.Chat { user: '%s', message: '%s' }", user, message); |
| 155 | } | 171 | } |
| 156 | |||
| 157 | } | 172 | } |
| 158 | 173 | ||
| 159 | public static final class Connect extends Message { | 174 | public static final class Connect extends Message { |
| 160 | |||
| 161 | private Connect(String user) { | 175 | private Connect(String user) { |
| 162 | super(user); | 176 | super(user); |
| 163 | } | 177 | } |
| @@ -176,11 +190,9 @@ public abstract class Message { | |||
| 176 | public String toString() { | 190 | public String toString() { |
| 177 | return String.format("Message.Connect { user: '%s' }", user); | 191 | return String.format("Message.Connect { user: '%s' }", user); |
| 178 | } | 192 | } |
| 179 | |||
| 180 | } | 193 | } |
| 181 | 194 | ||
| 182 | public static final class Disconnect extends Message { | 195 | public static final class Disconnect extends Message { |
| 183 | |||
| 184 | private Disconnect(String user) { | 196 | private Disconnect(String user) { |
| 185 | super(user); | 197 | super(user); |
| 186 | } | 198 | } |
| @@ -199,11 +211,9 @@ public abstract class Message { | |||
| 199 | public String toString() { | 211 | public String toString() { |
| 200 | return String.format("Message.Disconnect { user: '%s' }", user); | 212 | return String.format("Message.Disconnect { user: '%s' }", user); |
| 201 | } | 213 | } |
| 202 | |||
| 203 | } | 214 | } |
| 204 | 215 | ||
| 205 | public static final class EditDocs extends Message { | 216 | public static final class EditDocs extends Message { |
| 206 | |||
| 207 | public final Entry<?> entry; | 217 | public final Entry<?> entry; |
| 208 | 218 | ||
| 209 | private EditDocs(String user, Entry<?> entry) { | 219 | private EditDocs(String user, Entry<?> entry) { |
| @@ -229,9 +239,18 @@ public abstract class Message { | |||
| 229 | 239 | ||
| 230 | @Override | 240 | @Override |
| 231 | public boolean equals(Object o) { | 241 | public boolean equals(Object o) { |
| 232 | if (this == o) return true; | 242 | if (this == o) { |
| 233 | if (o == null || getClass() != o.getClass()) return false; | 243 | return true; |
| 234 | if (!super.equals(o)) return false; | 244 | } |
| 245 | |||
| 246 | if (o == null || getClass() != o.getClass()) { | ||
| 247 | return false; | ||
| 248 | } | ||
| 249 | |||
| 250 | if (!super.equals(o)) { | ||
| 251 | return false; | ||
| 252 | } | ||
| 253 | |||
| 235 | EditDocs editDocs = (EditDocs) o; | 254 | EditDocs editDocs = (EditDocs) o; |
| 236 | return Objects.equals(entry, editDocs.entry); | 255 | return Objects.equals(entry, editDocs.entry); |
| 237 | } | 256 | } |
| @@ -245,11 +264,9 @@ public abstract class Message { | |||
| 245 | public String toString() { | 264 | public String toString() { |
| 246 | return String.format("Message.EditDocs { user: '%s', entry: %s }", user, entry); | 265 | return String.format("Message.EditDocs { user: '%s', entry: %s }", user, entry); |
| 247 | } | 266 | } |
| 248 | |||
| 249 | } | 267 | } |
| 250 | 268 | ||
| 251 | public static final class MarkDeobf extends Message { | 269 | public static final class MarkDeobf extends Message { |
| 252 | |||
| 253 | public final Entry<?> entry; | 270 | public final Entry<?> entry; |
| 254 | 271 | ||
| 255 | private MarkDeobf(String user, Entry<?> entry) { | 272 | private MarkDeobf(String user, Entry<?> entry) { |
| @@ -275,9 +292,18 @@ public abstract class Message { | |||
| 275 | 292 | ||
| 276 | @Override | 293 | @Override |
| 277 | public boolean equals(Object o) { | 294 | public boolean equals(Object o) { |
| 278 | if (this == o) return true; | 295 | if (this == o) { |
| 279 | if (o == null || getClass() != o.getClass()) return false; | 296 | return true; |
| 280 | if (!super.equals(o)) return false; | 297 | } |
| 298 | |||
| 299 | if (o == null || getClass() != o.getClass()) { | ||
| 300 | return false; | ||
| 301 | } | ||
| 302 | |||
| 303 | if (!super.equals(o)) { | ||
| 304 | return false; | ||
| 305 | } | ||
| 306 | |||
| 281 | MarkDeobf markDeobf = (MarkDeobf) o; | 307 | MarkDeobf markDeobf = (MarkDeobf) o; |
| 282 | return Objects.equals(entry, markDeobf.entry); | 308 | return Objects.equals(entry, markDeobf.entry); |
| 283 | } | 309 | } |
| @@ -291,11 +317,9 @@ public abstract class Message { | |||
| 291 | public String toString() { | 317 | public String toString() { |
| 292 | return String.format("Message.MarkDeobf { user: '%s', entry: %s }", user, entry); | 318 | return String.format("Message.MarkDeobf { user: '%s', entry: %s }", user, entry); |
| 293 | } | 319 | } |
| 294 | |||
| 295 | } | 320 | } |
| 296 | 321 | ||
| 297 | public static final class RemoveMapping extends Message { | 322 | public static final class RemoveMapping extends Message { |
| 298 | |||
| 299 | public final Entry<?> entry; | 323 | public final Entry<?> entry; |
| 300 | 324 | ||
| 301 | private RemoveMapping(String user, Entry<?> entry) { | 325 | private RemoveMapping(String user, Entry<?> entry) { |
| @@ -321,9 +345,18 @@ public abstract class Message { | |||
| 321 | 345 | ||
| 322 | @Override | 346 | @Override |
| 323 | public boolean equals(Object o) { | 347 | public boolean equals(Object o) { |
| 324 | if (this == o) return true; | 348 | if (this == o) { |
| 325 | if (o == null || getClass() != o.getClass()) return false; | 349 | return true; |
| 326 | if (!super.equals(o)) return false; | 350 | } |
| 351 | |||
| 352 | if (o == null || getClass() != o.getClass()) { | ||
| 353 | return false; | ||
| 354 | } | ||
| 355 | |||
| 356 | if (!super.equals(o)) { | ||
| 357 | return false; | ||
| 358 | } | ||
| 359 | |||
| 327 | RemoveMapping that = (RemoveMapping) o; | 360 | RemoveMapping that = (RemoveMapping) o; |
| 328 | return Objects.equals(entry, that.entry); | 361 | return Objects.equals(entry, that.entry); |
| 329 | } | 362 | } |
| @@ -337,11 +370,9 @@ public abstract class Message { | |||
| 337 | public String toString() { | 370 | public String toString() { |
| 338 | return String.format("Message.RemoveMapping { user: '%s', entry: %s }", user, entry); | 371 | return String.format("Message.RemoveMapping { user: '%s', entry: %s }", user, entry); |
| 339 | } | 372 | } |
| 340 | |||
| 341 | } | 373 | } |
| 342 | 374 | ||
| 343 | public static final class Rename extends Message { | 375 | public static final class Rename extends Message { |
| 344 | |||
| 345 | public final Entry<?> entry; | 376 | public final Entry<?> entry; |
| 346 | public final String newName; | 377 | public final String newName; |
| 347 | 378 | ||
| @@ -370,12 +401,20 @@ public abstract class Message { | |||
| 370 | 401 | ||
| 371 | @Override | 402 | @Override |
| 372 | public boolean equals(Object o) { | 403 | public boolean equals(Object o) { |
| 373 | if (this == o) return true; | 404 | if (this == o) { |
| 374 | if (o == null || getClass() != o.getClass()) return false; | 405 | return true; |
| 375 | if (!super.equals(o)) return false; | 406 | } |
| 407 | |||
| 408 | if (o == null || getClass() != o.getClass()) { | ||
| 409 | return false; | ||
| 410 | } | ||
| 411 | |||
| 412 | if (!super.equals(o)) { | ||
| 413 | return false; | ||
| 414 | } | ||
| 415 | |||
| 376 | Rename rename = (Rename) o; | 416 | Rename rename = (Rename) o; |
| 377 | return Objects.equals(entry, rename.entry) && | 417 | return Objects.equals(entry, rename.entry) && Objects.equals(newName, rename.newName); |
| 378 | Objects.equals(newName, rename.newName); | ||
| 379 | } | 418 | } |
| 380 | 419 | ||
| 381 | @Override | 420 | @Override |
| @@ -387,7 +426,5 @@ public abstract class Message { | |||
| 387 | public String toString() { | 426 | public String toString() { |
| 388 | return String.format("Message.Rename { user: '%s', entry: %s, newName: '%s' }", user, entry, newName); | 427 | return String.format("Message.Rename { user: '%s', entry: %s, newName: '%s' }", user, entry, newName); |
| 389 | } | 428 | } |
| 390 | |||
| 391 | } | 429 | } |
| 392 | |||
| 393 | } | 430 | } |
diff --git a/enigma-server/src/main/java/cuchaz/enigma/network/ServerAddress.java b/enigma-server/src/main/java/cuchaz/enigma/network/ServerAddress.java index 45e0750..a8a1029 100644 --- a/enigma-server/src/main/java/cuchaz/enigma/network/ServerAddress.java +++ b/enigma-server/src/main/java/cuchaz/enigma/network/ServerAddress.java | |||
| @@ -5,7 +5,6 @@ import java.util.Objects; | |||
| 5 | import javax.annotation.Nullable; | 5 | import javax.annotation.Nullable; |
| 6 | 6 | ||
| 7 | public class ServerAddress { | 7 | public class ServerAddress { |
| 8 | |||
| 9 | public final String address; | 8 | public final String address; |
| 10 | public final int port; | 9 | public final int port; |
| 11 | 10 | ||
| @@ -16,11 +15,26 @@ public class ServerAddress { | |||
| 16 | 15 | ||
| 17 | @Nullable | 16 | @Nullable |
| 18 | public static ServerAddress of(String address, int port) { | 17 | public static ServerAddress of(String address, int port) { |
| 19 | if (port < 0 || port > 65535) return null; | 18 | if (port < 0 || port > 65535) { |
| 20 | if (address == null) return null; | 19 | return null; |
| 21 | if (address.equals("")) return null; | 20 | } |
| 22 | if (!address.matches("[a-zA-Z0-9.:-]+")) return null; | 21 | |
| 23 | if (address.startsWith("-") || address.endsWith("-")) return null; | 22 | if (address == null) { |
| 23 | return null; | ||
| 24 | } | ||
| 25 | |||
| 26 | if (address.equals("")) { | ||
| 27 | return null; | ||
| 28 | } | ||
| 29 | |||
| 30 | if (!address.matches("[a-zA-Z0-9.:-]+")) { | ||
| 31 | return null; | ||
| 32 | } | ||
| 33 | |||
| 34 | if (address.startsWith("-") || address.endsWith("-")) { | ||
| 35 | return null; | ||
| 36 | } | ||
| 37 | |||
| 24 | return new ServerAddress(address, port); | 38 | return new ServerAddress(address, port); |
| 25 | } | 39 | } |
| 26 | 40 | ||
| @@ -28,6 +42,7 @@ public class ServerAddress { | |||
| 28 | public static ServerAddress from(String s, int defaultPort) { | 42 | public static ServerAddress from(String s, int defaultPort) { |
| 29 | String address; | 43 | String address; |
| 30 | int idx = s.indexOf(']'); | 44 | int idx = s.indexOf(']'); |
| 45 | |||
| 31 | if (s.startsWith("[") && idx != -1) { | 46 | if (s.startsWith("[") && idx != -1) { |
| 32 | address = s.substring(1, idx); | 47 | address = s.substring(1, idx); |
| 33 | s = s.substring(idx + 1); | 48 | s = s.substring(idx + 1); |
| @@ -41,10 +56,12 @@ public class ServerAddress { | |||
| 41 | } | 56 | } |
| 42 | 57 | ||
| 43 | int port; | 58 | int port; |
| 59 | |||
| 44 | if (s.isEmpty()) { | 60 | if (s.isEmpty()) { |
| 45 | port = defaultPort; | 61 | port = defaultPort; |
| 46 | } else if (s.startsWith(":")) { | 62 | } else if (s.startsWith(":")) { |
| 47 | s = s.substring(1); | 63 | s = s.substring(1); |
| 64 | |||
| 48 | try { | 65 | try { |
| 49 | port = Integer.parseInt(s); | 66 | port = Integer.parseInt(s); |
| 50 | } catch (NumberFormatException e) { | 67 | } catch (NumberFormatException e) { |
| @@ -53,16 +70,22 @@ public class ServerAddress { | |||
| 53 | } else { | 70 | } else { |
| 54 | return null; | 71 | return null; |
| 55 | } | 72 | } |
| 73 | |||
| 56 | return ServerAddress.of(address, port); | 74 | return ServerAddress.of(address, port); |
| 57 | } | 75 | } |
| 58 | 76 | ||
| 59 | @Override | 77 | @Override |
| 60 | public boolean equals(Object o) { | 78 | public boolean equals(Object o) { |
| 61 | if (this == o) return true; | 79 | if (this == o) { |
| 62 | if (o == null || getClass() != o.getClass()) return false; | 80 | return true; |
| 81 | } | ||
| 82 | |||
| 83 | if (o == null || getClass() != o.getClass()) { | ||
| 84 | return false; | ||
| 85 | } | ||
| 86 | |||
| 63 | ServerAddress that = (ServerAddress) o; | 87 | ServerAddress that = (ServerAddress) o; |
| 64 | return port == that.port && | 88 | return port == that.port && Objects.equals(address, that.address); |
| 65 | Objects.equals(address, that.address); | ||
| 66 | } | 89 | } |
| 67 | 90 | ||
| 68 | @Override | 91 | @Override |
| @@ -74,5 +97,4 @@ public class ServerAddress { | |||
| 74 | public String toString() { | 97 | public String toString() { |
| 75 | return String.format("ServerAddress { address: '%s', port: %d }", address, port); | 98 | return String.format("ServerAddress { address: '%s', port: %d }", address, port); |
| 76 | } | 99 | } |
| 77 | |||
| 78 | } | 100 | } |
diff --git a/enigma-server/src/main/java/cuchaz/enigma/network/ServerPacketHandler.java b/enigma-server/src/main/java/cuchaz/enigma/network/ServerPacketHandler.java index 8618553..5b5b0e6 100644 --- a/enigma-server/src/main/java/cuchaz/enigma/network/ServerPacketHandler.java +++ b/enigma-server/src/main/java/cuchaz/enigma/network/ServerPacketHandler.java | |||
| @@ -3,7 +3,6 @@ package cuchaz.enigma.network; | |||
| 3 | import java.net.Socket; | 3 | import java.net.Socket; |
| 4 | 4 | ||
| 5 | public class ServerPacketHandler { | 5 | public class ServerPacketHandler { |
| 6 | |||
| 7 | private final Socket client; | 6 | private final Socket client; |
| 8 | private final EnigmaServer server; | 7 | private final EnigmaServer server; |
| 9 | 8 | ||
diff --git a/enigma-server/src/main/java/cuchaz/enigma/network/packet/ConfirmChangeC2SPacket.java b/enigma-server/src/main/java/cuchaz/enigma/network/packet/ConfirmChangeC2SPacket.java index 78ef964..ab4f5a1 100644 --- a/enigma-server/src/main/java/cuchaz/enigma/network/packet/ConfirmChangeC2SPacket.java +++ b/enigma-server/src/main/java/cuchaz/enigma/network/packet/ConfirmChangeC2SPacket.java | |||
| @@ -1,11 +1,11 @@ | |||
| 1 | package cuchaz.enigma.network.packet; | 1 | package cuchaz.enigma.network.packet; |
| 2 | 2 | ||
| 3 | import cuchaz.enigma.network.ServerPacketHandler; | ||
| 4 | |||
| 5 | import java.io.DataInput; | 3 | import java.io.DataInput; |
| 6 | import java.io.DataOutput; | 4 | import java.io.DataOutput; |
| 7 | import java.io.IOException; | 5 | import java.io.IOException; |
| 8 | 6 | ||
| 7 | import cuchaz.enigma.network.ServerPacketHandler; | ||
| 8 | |||
| 9 | public class ConfirmChangeC2SPacket implements Packet<ServerPacketHandler> { | 9 | public class ConfirmChangeC2SPacket implements Packet<ServerPacketHandler> { |
| 10 | private int syncId; | 10 | private int syncId; |
| 11 | 11 | ||
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 index b97877c..6a7ffe9 100644 --- a/enigma-server/src/main/java/cuchaz/enigma/network/packet/EntryChangeC2SPacket.java +++ b/enigma-server/src/main/java/cuchaz/enigma/network/packet/EntryChangeC2SPacket.java | |||
| @@ -12,7 +12,6 @@ import cuchaz.enigma.utils.validation.PrintValidatable; | |||
| 12 | import cuchaz.enigma.utils.validation.ValidationContext; | 12 | import cuchaz.enigma.utils.validation.ValidationContext; |
| 13 | 13 | ||
| 14 | public class EntryChangeC2SPacket implements Packet<ServerPacketHandler> { | 14 | public class EntryChangeC2SPacket implements Packet<ServerPacketHandler> { |
| 15 | |||
| 16 | private EntryChange<?> change; | 15 | private EntryChange<?> change; |
| 17 | 16 | ||
| 18 | EntryChangeC2SPacket() { | 17 | EntryChangeC2SPacket() { |
| @@ -62,5 +61,4 @@ public class EntryChangeC2SPacket implements Packet<ServerPacketHandler> { | |||
| 62 | handler.getServer().sendMessage(Message.editDocs(handler.getServer().getUsername(handler.getClient()), this.change.getTarget())); | 61 | handler.getServer().sendMessage(Message.editDocs(handler.getServer().getUsername(handler.getClient()), this.change.getTarget())); |
| 63 | } | 62 | } |
| 64 | } | 63 | } |
| 65 | |||
| 66 | } | 64 | } |
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 index a237b91..8e4688e 100644 --- a/enigma-server/src/main/java/cuchaz/enigma/network/packet/EntryChangeS2CPacket.java +++ b/enigma-server/src/main/java/cuchaz/enigma/network/packet/EntryChangeS2CPacket.java | |||
| @@ -8,7 +8,6 @@ import cuchaz.enigma.network.ClientPacketHandler; | |||
| 8 | import cuchaz.enigma.translation.mapping.EntryChange; | 8 | import cuchaz.enigma.translation.mapping.EntryChange; |
| 9 | 9 | ||
| 10 | public class EntryChangeS2CPacket implements Packet<ClientPacketHandler> { | 10 | public class EntryChangeS2CPacket implements Packet<ClientPacketHandler> { |
| 11 | |||
| 12 | private int syncId; | 11 | private int syncId; |
| 13 | private EntryChange<?> change; | 12 | private EntryChange<?> change; |
| 14 | 13 | ||
| @@ -38,5 +37,4 @@ public class EntryChangeS2CPacket implements Packet<ClientPacketHandler> { | |||
| 38 | handler.sendPacket(new ConfirmChangeC2SPacket(this.syncId)); | 37 | handler.sendPacket(new ConfirmChangeC2SPacket(this.syncId)); |
| 39 | } | 38 | } |
| 40 | } | 39 | } |
| 41 | |||
| 42 | } | 40 | } |
diff --git a/enigma-server/src/main/java/cuchaz/enigma/network/packet/KickS2CPacket.java b/enigma-server/src/main/java/cuchaz/enigma/network/packet/KickS2CPacket.java index 9a112a8..bd238dc 100644 --- a/enigma-server/src/main/java/cuchaz/enigma/network/packet/KickS2CPacket.java +++ b/enigma-server/src/main/java/cuchaz/enigma/network/packet/KickS2CPacket.java | |||
| @@ -1,11 +1,11 @@ | |||
| 1 | package cuchaz.enigma.network.packet; | 1 | package cuchaz.enigma.network.packet; |
| 2 | 2 | ||
| 3 | import cuchaz.enigma.network.ClientPacketHandler; | ||
| 4 | |||
| 5 | import java.io.DataInput; | 3 | import java.io.DataInput; |
| 6 | import java.io.DataOutput; | 4 | import java.io.DataOutput; |
| 7 | import java.io.IOException; | 5 | import java.io.IOException; |
| 8 | 6 | ||
| 7 | import cuchaz.enigma.network.ClientPacketHandler; | ||
| 8 | |||
| 9 | public class KickS2CPacket implements Packet<ClientPacketHandler> { | 9 | public class KickS2CPacket implements Packet<ClientPacketHandler> { |
| 10 | private String reason; | 10 | private String reason; |
| 11 | 11 | ||
diff --git a/enigma-server/src/main/java/cuchaz/enigma/network/packet/LoginC2SPacket.java b/enigma-server/src/main/java/cuchaz/enigma/network/packet/LoginC2SPacket.java index da0f44a..e93c1d4 100644 --- a/enigma-server/src/main/java/cuchaz/enigma/network/packet/LoginC2SPacket.java +++ b/enigma-server/src/main/java/cuchaz/enigma/network/packet/LoginC2SPacket.java | |||
| @@ -1,14 +1,14 @@ | |||
| 1 | package cuchaz.enigma.network.packet; | 1 | package cuchaz.enigma.network.packet; |
| 2 | 2 | ||
| 3 | import cuchaz.enigma.network.EnigmaServer; | ||
| 4 | import cuchaz.enigma.network.ServerPacketHandler; | ||
| 5 | import cuchaz.enigma.network.Message; | ||
| 6 | |||
| 7 | import java.io.DataInput; | 3 | import java.io.DataInput; |
| 8 | import java.io.DataOutput; | 4 | import java.io.DataOutput; |
| 9 | import java.io.IOException; | 5 | import java.io.IOException; |
| 10 | import java.util.Arrays; | 6 | import java.util.Arrays; |
| 11 | 7 | ||
| 8 | import cuchaz.enigma.network.EnigmaServer; | ||
| 9 | import cuchaz.enigma.network.Message; | ||
| 10 | import cuchaz.enigma.network.ServerPacketHandler; | ||
| 11 | |||
| 12 | public class LoginC2SPacket implements Packet<ServerPacketHandler> { | 12 | public class LoginC2SPacket implements Packet<ServerPacketHandler> { |
| 13 | private byte[] jarChecksum; | 13 | private byte[] jarChecksum; |
| 14 | private char[] password; | 14 | private char[] password; |
| @@ -28,12 +28,15 @@ public class LoginC2SPacket implements Packet<ServerPacketHandler> { | |||
| 28 | if (input.readUnsignedShort() != EnigmaServer.PROTOCOL_VERSION) { | 28 | if (input.readUnsignedShort() != EnigmaServer.PROTOCOL_VERSION) { |
| 29 | throw new IOException("Mismatching protocol"); | 29 | throw new IOException("Mismatching protocol"); |
| 30 | } | 30 | } |
| 31 | |||
| 31 | this.jarChecksum = new byte[EnigmaServer.CHECKSUM_SIZE]; | 32 | this.jarChecksum = new byte[EnigmaServer.CHECKSUM_SIZE]; |
| 32 | input.readFully(jarChecksum); | 33 | input.readFully(jarChecksum); |
| 33 | this.password = new char[input.readUnsignedByte()]; | 34 | this.password = new char[input.readUnsignedByte()]; |
| 35 | |||
| 34 | for (int i = 0; i < password.length; i++) { | 36 | for (int i = 0; i < password.length; i++) { |
| 35 | password[i] = input.readChar(); | 37 | password[i] = input.readChar(); |
| 36 | } | 38 | } |
| 39 | |||
| 37 | this.username = PacketHelper.readString(input); | 40 | this.username = PacketHelper.readString(input); |
| 38 | } | 41 | } |
| 39 | 42 | ||
| @@ -42,9 +45,11 @@ public class LoginC2SPacket implements Packet<ServerPacketHandler> { | |||
| 42 | output.writeShort(EnigmaServer.PROTOCOL_VERSION); | 45 | output.writeShort(EnigmaServer.PROTOCOL_VERSION); |
| 43 | output.write(jarChecksum); | 46 | output.write(jarChecksum); |
| 44 | output.writeByte(password.length); | 47 | output.writeByte(password.length); |
| 48 | |||
| 45 | for (char c : password) { | 49 | for (char c : password) { |
| 46 | output.writeChar(c); | 50 | output.writeChar(c); |
| 47 | } | 51 | } |
| 52 | |||
| 48 | PacketHelper.writeString(output, username); | 53 | PacketHelper.writeString(output, username); |
| 49 | } | 54 | } |
| 50 | 55 | ||
diff --git a/enigma-server/src/main/java/cuchaz/enigma/network/packet/MessageC2SPacket.java b/enigma-server/src/main/java/cuchaz/enigma/network/packet/MessageC2SPacket.java index 3bc09e7..b0610b0 100644 --- a/enigma-server/src/main/java/cuchaz/enigma/network/packet/MessageC2SPacket.java +++ b/enigma-server/src/main/java/cuchaz/enigma/network/packet/MessageC2SPacket.java | |||
| @@ -4,11 +4,10 @@ import java.io.DataInput; | |||
| 4 | import java.io.DataOutput; | 4 | import java.io.DataOutput; |
| 5 | import java.io.IOException; | 5 | import java.io.IOException; |
| 6 | 6 | ||
| 7 | import cuchaz.enigma.network.ServerPacketHandler; | ||
| 8 | import cuchaz.enigma.network.Message; | 7 | import cuchaz.enigma.network.Message; |
| 8 | import cuchaz.enigma.network.ServerPacketHandler; | ||
| 9 | 9 | ||
| 10 | public class MessageC2SPacket implements Packet<ServerPacketHandler> { | 10 | public class MessageC2SPacket implements Packet<ServerPacketHandler> { |
| 11 | |||
| 12 | private String message; | 11 | private String message; |
| 13 | 12 | ||
| 14 | MessageC2SPacket() { | 13 | MessageC2SPacket() { |
| @@ -31,9 +30,9 @@ public class MessageC2SPacket implements Packet<ServerPacketHandler> { | |||
| 31 | @Override | 30 | @Override |
| 32 | public void handle(ServerPacketHandler handler) { | 31 | public void handle(ServerPacketHandler handler) { |
| 33 | String message = this.message.trim(); | 32 | String message = this.message.trim(); |
| 33 | |||
| 34 | if (!message.isEmpty()) { | 34 | if (!message.isEmpty()) { |
| 35 | handler.getServer().sendMessage(Message.chat(handler.getServer().getUsername(handler.getClient()), message)); | 35 | handler.getServer().sendMessage(Message.chat(handler.getServer().getUsername(handler.getClient()), message)); |
| 36 | } | 36 | } |
| 37 | } | 37 | } |
| 38 | |||
| 39 | } | 38 | } |
diff --git a/enigma-server/src/main/java/cuchaz/enigma/network/packet/MessageS2CPacket.java b/enigma-server/src/main/java/cuchaz/enigma/network/packet/MessageS2CPacket.java index 2b07968..9833eeb 100644 --- a/enigma-server/src/main/java/cuchaz/enigma/network/packet/MessageS2CPacket.java +++ b/enigma-server/src/main/java/cuchaz/enigma/network/packet/MessageS2CPacket.java | |||
| @@ -8,7 +8,6 @@ import cuchaz.enigma.network.ClientPacketHandler; | |||
| 8 | import cuchaz.enigma.network.Message; | 8 | import cuchaz.enigma.network.Message; |
| 9 | 9 | ||
| 10 | public class MessageS2CPacket implements Packet<ClientPacketHandler> { | 10 | public class MessageS2CPacket implements Packet<ClientPacketHandler> { |
| 11 | |||
| 12 | private Message message; | 11 | private Message message; |
| 13 | 12 | ||
| 14 | MessageS2CPacket() { | 13 | MessageS2CPacket() { |
| @@ -32,5 +31,4 @@ public class MessageS2CPacket implements Packet<ClientPacketHandler> { | |||
| 32 | public void handle(ClientPacketHandler handler) { | 31 | public void handle(ClientPacketHandler handler) { |
| 33 | handler.addMessage(message); | 32 | handler.addMessage(message); |
| 34 | } | 33 | } |
| 35 | |||
| 36 | } | 34 | } |
diff --git a/enigma-server/src/main/java/cuchaz/enigma/network/packet/Packet.java b/enigma-server/src/main/java/cuchaz/enigma/network/packet/Packet.java index 2f16dfb..15054e7 100644 --- a/enigma-server/src/main/java/cuchaz/enigma/network/packet/Packet.java +++ b/enigma-server/src/main/java/cuchaz/enigma/network/packet/Packet.java | |||
| @@ -5,11 +5,9 @@ import java.io.DataOutput; | |||
| 5 | import java.io.IOException; | 5 | import java.io.IOException; |
| 6 | 6 | ||
| 7 | public interface Packet<H> { | 7 | public interface Packet<H> { |
| 8 | |||
| 9 | void read(DataInput input) throws IOException; | 8 | void read(DataInput input) throws IOException; |
| 10 | 9 | ||
| 11 | void write(DataOutput output) throws IOException; | 10 | void write(DataOutput output) throws IOException; |
| 12 | 11 | ||
| 13 | void handle(H handler); | 12 | void handle(H handler); |
| 14 | |||
| 15 | } | 13 | } |
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 2649cdc..ce767c3 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 | |||
| @@ -9,11 +9,14 @@ import cuchaz.enigma.translation.mapping.AccessModifier; | |||
| 9 | import cuchaz.enigma.translation.mapping.EntryChange; | 9 | import cuchaz.enigma.translation.mapping.EntryChange; |
| 10 | import cuchaz.enigma.translation.representation.MethodDescriptor; | 10 | import cuchaz.enigma.translation.representation.MethodDescriptor; |
| 11 | import cuchaz.enigma.translation.representation.TypeDescriptor; | 11 | import cuchaz.enigma.translation.representation.TypeDescriptor; |
| 12 | import cuchaz.enigma.translation.representation.entry.*; | 12 | import cuchaz.enigma.translation.representation.entry.ClassEntry; |
| 13 | import cuchaz.enigma.translation.representation.entry.Entry; | ||
| 14 | import cuchaz.enigma.translation.representation.entry.FieldEntry; | ||
| 15 | import cuchaz.enigma.translation.representation.entry.LocalVariableEntry; | ||
| 16 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | ||
| 13 | import cuchaz.enigma.utils.TristateChange; | 17 | import cuchaz.enigma.utils.TristateChange; |
| 14 | 18 | ||
| 15 | public class PacketHelper { | 19 | public class PacketHelper { |
| 16 | |||
| 17 | private static final int ENTRY_CLASS = 0, ENTRY_FIELD = 1, ENTRY_METHOD = 2, ENTRY_LOCAL_VAR = 3; | 20 | private static final int ENTRY_CLASS = 0, ENTRY_FIELD = 1, ENTRY_METHOD = 2, ENTRY_LOCAL_VAR = 3; |
| 18 | private static final int MAX_STRING_LENGTH = 65535; | 21 | private static final int MAX_STRING_LENGTH = 65535; |
| 19 | 22 | ||
| @@ -31,45 +34,46 @@ public class PacketHelper { | |||
| 31 | String name = readString(input); | 34 | String name = readString(input); |
| 32 | 35 | ||
| 33 | String javadocs = null; | 36 | String javadocs = null; |
| 37 | |||
| 34 | if (input.readBoolean()) { | 38 | if (input.readBoolean()) { |
| 35 | javadocs = readString(input); | 39 | javadocs = readString(input); |
| 36 | } | 40 | } |
| 37 | 41 | ||
| 38 | switch (type) { | 42 | switch (type) { |
| 39 | case ENTRY_CLASS: { | 43 | case ENTRY_CLASS: { |
| 40 | if (parent != null && !(parent instanceof ClassEntry)) { | 44 | if (parent != null && !(parent instanceof ClassEntry)) { |
| 41 | throw new IOException("Class requires class parent"); | 45 | throw new IOException("Class requires class parent"); |
| 42 | } | ||
| 43 | |||
| 44 | return new ClassEntry((ClassEntry) parent, name, javadocs); | ||
| 45 | } | 46 | } |
| 46 | case ENTRY_FIELD: { | ||
| 47 | if (!(parent instanceof ClassEntry parentClass)) { | ||
| 48 | throw new IOException("Field requires class parent"); | ||
| 49 | } | ||
| 50 | 47 | ||
| 51 | TypeDescriptor desc = new TypeDescriptor(readString(input)); | 48 | return new ClassEntry((ClassEntry) parent, name, javadocs); |
| 52 | return new FieldEntry(parentClass, name, desc, javadocs); | 49 | } |
| 50 | case ENTRY_FIELD: { | ||
| 51 | if (!(parent instanceof ClassEntry parentClass)) { | ||
| 52 | throw new IOException("Field requires class parent"); | ||
| 53 | } | 53 | } |
| 54 | case ENTRY_METHOD: { | ||
| 55 | if (!(parent instanceof ClassEntry parentClass)) { | ||
| 56 | throw new IOException("Method requires class parent"); | ||
| 57 | } | ||
| 58 | 54 | ||
| 59 | MethodDescriptor desc = new MethodDescriptor(readString(input)); | 55 | TypeDescriptor desc = new TypeDescriptor(readString(input)); |
| 60 | return new MethodEntry(parentClass, name, desc, javadocs); | 56 | return new FieldEntry(parentClass, name, desc, javadocs); |
| 57 | } | ||
| 58 | case ENTRY_METHOD: { | ||
| 59 | if (!(parent instanceof ClassEntry parentClass)) { | ||
| 60 | throw new IOException("Method requires class parent"); | ||
| 61 | } | 61 | } |
| 62 | case ENTRY_LOCAL_VAR: { | 62 | |
| 63 | if (!(parent instanceof MethodEntry parentMethod)) { | 63 | MethodDescriptor desc = new MethodDescriptor(readString(input)); |
| 64 | throw new IOException("Local variable requires method parent"); | 64 | return new MethodEntry(parentClass, name, desc, javadocs); |
| 65 | } | 65 | } |
| 66 | 66 | case ENTRY_LOCAL_VAR: { | |
| 67 | int index = input.readUnsignedShort(); | 67 | if (!(parent instanceof MethodEntry parentMethod)) { |
| 68 | boolean parameter = input.readBoolean(); | 68 | throw new IOException("Local variable requires method parent"); |
| 69 | return new LocalVariableEntry(parentMethod, index, name, parameter, javadocs); | ||
| 70 | } | 69 | } |
| 71 | default: | 70 | |
| 72 | throw new IOException("Received unknown entry type " + type); | 71 | int index = input.readUnsignedShort(); |
| 72 | boolean parameter = input.readBoolean(); | ||
| 73 | return new LocalVariableEntry(parentMethod, index, name, parameter, javadocs); | ||
| 74 | } | ||
| 75 | default: | ||
| 76 | throw new IOException("Received unknown entry type " + type); | ||
| 73 | } | 77 | } |
| 74 | } | 78 | } |
| 75 | 79 | ||
| @@ -94,6 +98,7 @@ public class PacketHelper { | |||
| 94 | // parent | 98 | // parent |
| 95 | if (includeParent) { | 99 | if (includeParent) { |
| 96 | output.writeBoolean(entry.getParent() != null); | 100 | output.writeBoolean(entry.getParent() != null); |
| 101 | |||
| 97 | if (entry.getParent() != null) { | 102 | if (entry.getParent() != null) { |
| 98 | writeEntry(output, entry.getParent(), true); | 103 | writeEntry(output, entry.getParent(), true); |
| 99 | } | 104 | } |
| @@ -104,6 +109,7 @@ public class PacketHelper { | |||
| 104 | 109 | ||
| 105 | // javadocs | 110 | // javadocs |
| 106 | output.writeBoolean(entry.getJavadocs() != null); | 111 | output.writeBoolean(entry.getJavadocs() != null); |
| 112 | |||
| 107 | if (entry.getJavadocs() != null) { | 113 | if (entry.getJavadocs() != null) { |
| 108 | writeString(output, entry.getJavadocs()); | 114 | writeString(output, entry.getJavadocs()); |
| 109 | } | 115 | } |
| @@ -129,9 +135,11 @@ public class PacketHelper { | |||
| 129 | 135 | ||
| 130 | public static void writeString(DataOutput output, String str) throws IOException { | 136 | public static void writeString(DataOutput output, String str) throws IOException { |
| 131 | byte[] bytes = str.getBytes(StandardCharsets.UTF_8); | 137 | byte[] bytes = str.getBytes(StandardCharsets.UTF_8); |
| 138 | |||
| 132 | if (bytes.length > MAX_STRING_LENGTH) { | 139 | if (bytes.length > MAX_STRING_LENGTH) { |
| 133 | throw new IOException("String too long, was " + bytes.length + " bytes, max " + MAX_STRING_LENGTH + " allowed"); | 140 | throw new IOException("String too long, was " + bytes.length + " bytes, max " + MAX_STRING_LENGTH + " allowed"); |
| 134 | } | 141 | } |
| 142 | |||
| 135 | output.writeShort(bytes.length); | 143 | output.writeShort(bytes.length); |
| 136 | output.write(bytes); | 144 | output.write(bytes); |
| 137 | } | 145 | } |
| @@ -146,30 +154,30 @@ public class PacketHelper { | |||
| 146 | TristateChange.Type javadocT = TristateChange.Type.values()[flags >> 4 & 0x3]; | 154 | TristateChange.Type javadocT = TristateChange.Type.values()[flags >> 4 & 0x3]; |
| 147 | 155 | ||
| 148 | switch (deobfNameT) { | 156 | switch (deobfNameT) { |
| 149 | case RESET: | 157 | case RESET: |
| 150 | change = change.clearDeobfName(); | 158 | change = change.clearDeobfName(); |
| 151 | break; | 159 | break; |
| 152 | case SET: | 160 | case SET: |
| 153 | change = change.withDeobfName(readString(input)); | 161 | change = change.withDeobfName(readString(input)); |
| 154 | break; | 162 | break; |
| 155 | } | 163 | } |
| 156 | 164 | ||
| 157 | switch (accessT) { | 165 | switch (accessT) { |
| 158 | case RESET: | 166 | case RESET: |
| 159 | change = change.clearAccess(); | 167 | change = change.clearAccess(); |
| 160 | break; | 168 | break; |
| 161 | case SET: | 169 | case SET: |
| 162 | change = change.withAccess(AccessModifier.values()[flags >> 6 & 0x3]); | 170 | change = change.withAccess(AccessModifier.values()[flags >> 6 & 0x3]); |
| 163 | break; | 171 | break; |
| 164 | } | 172 | } |
| 165 | 173 | ||
| 166 | switch (javadocT) { | 174 | switch (javadocT) { |
| 167 | case RESET: | 175 | case RESET: |
| 168 | change = change.clearJavadoc(); | 176 | change = change.clearJavadoc(); |
| 169 | break; | 177 | break; |
| 170 | case SET: | 178 | case SET: |
| 171 | change = change.withJavadoc(readString(input)); | 179 | change = change.withJavadoc(readString(input)); |
| 172 | break; | 180 | break; |
| 173 | } | 181 | } |
| 174 | 182 | ||
| 175 | return change; | 183 | return change; |
| @@ -177,9 +185,7 @@ public class PacketHelper { | |||
| 177 | 185 | ||
| 178 | public static void writeEntryChange(DataOutput output, EntryChange<?> change) throws IOException { | 186 | public static void writeEntryChange(DataOutput output, EntryChange<?> change) throws IOException { |
| 179 | writeEntry(output, change.getTarget()); | 187 | writeEntry(output, change.getTarget()); |
| 180 | int flags = change.getDeobfName().getType().ordinal() | | 188 | int flags = change.getDeobfName().getType().ordinal() | change.getAccess().getType().ordinal() << 2 | change.getJavadoc().getType().ordinal() << 4; |
| 181 | change.getAccess().getType().ordinal() << 2 | | ||
| 182 | change.getJavadoc().getType().ordinal() << 4; | ||
| 183 | 189 | ||
| 184 | if (change.getAccess().isSet()) { | 190 | if (change.getAccess().isSet()) { |
| 185 | flags |= change.getAccess().getNewValue().ordinal() << 6; | 191 | flags |= change.getAccess().getNewValue().ordinal() << 6; |
| @@ -195,5 +201,4 @@ public class PacketHelper { | |||
| 195 | writeString(output, change.getJavadoc().getNewValue()); | 201 | writeString(output, change.getJavadoc().getNewValue()); |
| 196 | } | 202 | } |
| 197 | } | 203 | } |
| 198 | |||
| 199 | } | 204 | } |
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 59999cc..49d56fd 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 | |||
| @@ -8,7 +8,6 @@ import cuchaz.enigma.network.ClientPacketHandler; | |||
| 8 | import cuchaz.enigma.network.ServerPacketHandler; | 8 | import cuchaz.enigma.network.ServerPacketHandler; |
| 9 | 9 | ||
| 10 | public class PacketRegistry { | 10 | public class PacketRegistry { |
| 11 | |||
| 12 | private static final Map<Class<? extends Packet<ServerPacketHandler>>, Integer> c2sPacketIds = new HashMap<>(); | 11 | private static final Map<Class<? extends Packet<ServerPacketHandler>>, Integer> c2sPacketIds = new HashMap<>(); |
| 13 | private static final Map<Integer, Supplier<? extends Packet<ServerPacketHandler>>> c2sPacketCreators = new HashMap<>(); | 12 | private static final Map<Integer, Supplier<? extends Packet<ServerPacketHandler>>> c2sPacketCreators = new HashMap<>(); |
| 14 | private static final Map<Class<? extends Packet<ClientPacketHandler>>, Integer> s2cPacketIds = new HashMap<>(); | 13 | private static final Map<Class<? extends Packet<ClientPacketHandler>>, Integer> s2cPacketIds = new HashMap<>(); |
| @@ -54,5 +53,4 @@ public class PacketRegistry { | |||
| 54 | Supplier<? extends Packet<ClientPacketHandler>> creator = s2cPacketCreators.get(id); | 53 | Supplier<? extends Packet<ClientPacketHandler>> creator = s2cPacketCreators.get(id); |
| 55 | return creator == null ? null : creator.get(); | 54 | return creator == null ? null : creator.get(); |
| 56 | } | 55 | } |
| 57 | |||
| 58 | } | 56 | } |
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 6d9c0bc..7e50938 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 | |||
| @@ -28,6 +28,7 @@ public class SyncMappingsS2CPacket implements Packet<ClientPacketHandler> { | |||
| 28 | public void read(DataInput input) throws IOException { | 28 | public void read(DataInput input) throws IOException { |
| 29 | mappings = new HashEntryTree<>(); | 29 | mappings = new HashEntryTree<>(); |
| 30 | int size = input.readInt(); | 30 | int size = input.readInt(); |
| 31 | |||
| 31 | for (int i = 0; i < size; i++) { | 32 | for (int i = 0; i < size; i++) { |
| 32 | readEntryTreeNode(input, null); | 33 | readEntryTreeNode(input, null); |
| 33 | } | 34 | } |
| @@ -40,6 +41,7 @@ public class SyncMappingsS2CPacket implements Packet<ClientPacketHandler> { | |||
| 40 | EntryMapping mapping = new EntryMapping(!name.isEmpty() ? name : null, !javadoc.isEmpty() ? javadoc : null); | 41 | EntryMapping mapping = new EntryMapping(!name.isEmpty() ? name : null, !javadoc.isEmpty() ? javadoc : null); |
| 41 | mappings.insert(entry, mapping); | 42 | mappings.insert(entry, mapping); |
| 42 | int size = input.readUnsignedShort(); | 43 | int size = input.readUnsignedShort(); |
| 44 | |||
| 43 | for (int i = 0; i < size; i++) { | 45 | for (int i = 0; i < size; i++) { |
| 44 | readEntryTreeNode(input, entry); | 46 | readEntryTreeNode(input, entry); |
| 45 | } | 47 | } |
| @@ -49,6 +51,7 @@ public class SyncMappingsS2CPacket implements Packet<ClientPacketHandler> { | |||
| 49 | public void write(DataOutput output) throws IOException { | 51 | public void write(DataOutput output) throws IOException { |
| 50 | List<EntryTreeNode<EntryMapping>> roots = mappings.getRootNodes().toList(); | 52 | List<EntryTreeNode<EntryMapping>> roots = mappings.getRootNodes().toList(); |
| 51 | output.writeInt(roots.size()); | 53 | output.writeInt(roots.size()); |
| 54 | |||
| 52 | for (EntryTreeNode<EntryMapping> node : roots) { | 55 | for (EntryTreeNode<EntryMapping> node : roots) { |
| 53 | writeEntryTreeNode(output, node); | 56 | writeEntryTreeNode(output, node); |
| 54 | } | 57 | } |
| @@ -57,12 +60,16 @@ public class SyncMappingsS2CPacket implements Packet<ClientPacketHandler> { | |||
| 57 | private static void writeEntryTreeNode(DataOutput output, EntryTreeNode<EntryMapping> node) throws IOException { | 60 | private static void writeEntryTreeNode(DataOutput output, EntryTreeNode<EntryMapping> node) throws IOException { |
| 58 | PacketHelper.writeEntry(output, node.getEntry(), false); | 61 | PacketHelper.writeEntry(output, node.getEntry(), false); |
| 59 | EntryMapping value = node.getValue(); | 62 | EntryMapping value = node.getValue(); |
| 60 | if (value == null) value = EntryMapping.DEFAULT; | 63 | |
| 64 | if (value == null) { | ||
| 65 | value = EntryMapping.DEFAULT; | ||
| 66 | } | ||
| 61 | 67 | ||
| 62 | PacketHelper.writeString(output, value.targetName() != null ? value.targetName() : ""); | 68 | PacketHelper.writeString(output, value.targetName() != null ? value.targetName() : ""); |
| 63 | PacketHelper.writeString(output, value.javadoc() != null ? value.javadoc() : ""); | 69 | PacketHelper.writeString(output, value.javadoc() != null ? value.javadoc() : ""); |
| 64 | Collection<? extends EntryTreeNode<EntryMapping>> children = node.getChildNodes(); | 70 | Collection<? extends EntryTreeNode<EntryMapping>> children = node.getChildNodes(); |
| 65 | output.writeShort(children.size()); | 71 | output.writeShort(children.size()); |
| 72 | |||
| 66 | for (EntryTreeNode<EntryMapping> child : children) { | 73 | for (EntryTreeNode<EntryMapping> child : children) { |
| 67 | writeEntryTreeNode(output, child); | 74 | writeEntryTreeNode(output, child); |
| 68 | } | 75 | } |
diff --git a/enigma-server/src/main/java/cuchaz/enigma/network/packet/UserListS2CPacket.java b/enigma-server/src/main/java/cuchaz/enigma/network/packet/UserListS2CPacket.java index b4a277a..baac2b3 100644 --- a/enigma-server/src/main/java/cuchaz/enigma/network/packet/UserListS2CPacket.java +++ b/enigma-server/src/main/java/cuchaz/enigma/network/packet/UserListS2CPacket.java | |||
| @@ -1,15 +1,14 @@ | |||
| 1 | package cuchaz.enigma.network.packet; | 1 | package cuchaz.enigma.network.packet; |
| 2 | 2 | ||
| 3 | import cuchaz.enigma.network.ClientPacketHandler; | ||
| 4 | |||
| 5 | import java.io.DataInput; | 3 | import java.io.DataInput; |
| 6 | import java.io.DataOutput; | 4 | import java.io.DataOutput; |
| 7 | import java.io.IOException; | 5 | import java.io.IOException; |
| 8 | import java.util.ArrayList; | 6 | import java.util.ArrayList; |
| 9 | import java.util.List; | 7 | import java.util.List; |
| 10 | 8 | ||
| 11 | public class UserListS2CPacket implements Packet<ClientPacketHandler> { | 9 | import cuchaz.enigma.network.ClientPacketHandler; |
| 12 | 10 | ||
| 11 | public class UserListS2CPacket implements Packet<ClientPacketHandler> { | ||
| 13 | private List<String> users; | 12 | private List<String> users; |
| 14 | 13 | ||
| 15 | UserListS2CPacket() { | 14 | UserListS2CPacket() { |
| @@ -23,6 +22,7 @@ public class UserListS2CPacket implements Packet<ClientPacketHandler> { | |||
| 23 | public void read(DataInput input) throws IOException { | 22 | public void read(DataInput input) throws IOException { |
| 24 | int len = input.readUnsignedShort(); | 23 | int len = input.readUnsignedShort(); |
| 25 | users = new ArrayList<>(len); | 24 | users = new ArrayList<>(len); |
| 25 | |||
| 26 | for (int i = 0; i < len; i++) { | 26 | for (int i = 0; i < len; i++) { |
| 27 | users.add(input.readUTF()); | 27 | users.add(input.readUTF()); |
| 28 | } | 28 | } |
| @@ -31,6 +31,7 @@ public class UserListS2CPacket implements Packet<ClientPacketHandler> { | |||
| 31 | @Override | 31 | @Override |
| 32 | public void write(DataOutput output) throws IOException { | 32 | public void write(DataOutput output) throws IOException { |
| 33 | output.writeShort(users.size()); | 33 | output.writeShort(users.size()); |
| 34 | |||
| 34 | for (String user : users) { | 35 | for (String user : users) { |
| 35 | PacketHelper.writeString(output, user); | 36 | PacketHelper.writeString(output, user); |
| 36 | } | 37 | } |
| @@ -40,5 +41,4 @@ public class UserListS2CPacket implements Packet<ClientPacketHandler> { | |||
| 40 | public void handle(ClientPacketHandler handler) { | 41 | public void handle(ClientPacketHandler handler) { |
| 41 | handler.updateUserList(users); | 42 | handler.updateUserList(users); |
| 42 | } | 43 | } |
| 43 | |||
| 44 | } | 44 | } |
diff --git a/enigma-server/src/test/java/cuchaz/enigma/network/ServerAddressTest.java b/enigma-server/src/test/java/cuchaz/enigma/network/ServerAddressTest.java index 3765f7a..c2920e0 100644 --- a/enigma-server/src/test/java/cuchaz/enigma/network/ServerAddressTest.java +++ b/enigma-server/src/test/java/cuchaz/enigma/network/ServerAddressTest.java | |||
| @@ -1,12 +1,11 @@ | |||
| 1 | package cuchaz.enigma.network; | 1 | package cuchaz.enigma.network; |
| 2 | 2 | ||
| 3 | import org.junit.Test; | ||
| 4 | |||
| 5 | import static org.junit.Assert.assertEquals; | 3 | import static org.junit.Assert.assertEquals; |
| 6 | import static org.junit.Assert.assertNull; | 4 | import static org.junit.Assert.assertNull; |
| 7 | 5 | ||
| 8 | public class ServerAddressTest { | 6 | import org.junit.Test; |
| 9 | 7 | ||
| 8 | public class ServerAddressTest { | ||
| 10 | @Test | 9 | @Test |
| 11 | public void validAddresses() { | 10 | public void validAddresses() { |
| 12 | assertEquals(ServerAddress.of("127.0.0.1", 22), ServerAddress.from("127.0.0.1", 22)); | 11 | assertEquals(ServerAddress.of("127.0.0.1", 22), ServerAddress.from("127.0.0.1", 22)); |
| @@ -24,5 +23,4 @@ public class ServerAddressTest { | |||
| 24 | assertNull(ServerAddress.from("127.0.0.1:100000000", 22)); | 23 | assertNull(ServerAddress.from("127.0.0.1:100000000", 22)); |
| 25 | assertNull(ServerAddress.from("127.0.0.1:lmao", 22)); | 24 | assertNull(ServerAddress.from("127.0.0.1:lmao", 22)); |
| 26 | } | 25 | } |
| 27 | |||
| 28 | } | 26 | } |