summaryrefslogtreecommitdiff
path: root/enigma-server/src
diff options
context:
space:
mode:
Diffstat (limited to 'enigma-server/src')
-rw-r--r--enigma-server/src/main/java/cuchaz/enigma/network/ClientPacketHandler.java18
-rw-r--r--enigma-server/src/main/java/cuchaz/enigma/network/DedicatedEnigmaServer.java74
-rw-r--r--enigma-server/src/main/java/cuchaz/enigma/network/EnigmaClient.java25
-rw-r--r--enigma-server/src/main/java/cuchaz/enigma/network/EnigmaServer.java47
-rw-r--r--enigma-server/src/main/java/cuchaz/enigma/network/IntegratedEnigmaServer.java4
-rw-r--r--enigma-server/src/main/java/cuchaz/enigma/network/Message.java155
-rw-r--r--enigma-server/src/main/java/cuchaz/enigma/network/ServerAddress.java44
-rw-r--r--enigma-server/src/main/java/cuchaz/enigma/network/ServerPacketHandler.java1
-rw-r--r--enigma-server/src/main/java/cuchaz/enigma/network/packet/ConfirmChangeC2SPacket.java4
-rw-r--r--enigma-server/src/main/java/cuchaz/enigma/network/packet/EntryChangeC2SPacket.java2
-rw-r--r--enigma-server/src/main/java/cuchaz/enigma/network/packet/EntryChangeS2CPacket.java2
-rw-r--r--enigma-server/src/main/java/cuchaz/enigma/network/packet/KickS2CPacket.java4
-rw-r--r--enigma-server/src/main/java/cuchaz/enigma/network/packet/LoginC2SPacket.java13
-rw-r--r--enigma-server/src/main/java/cuchaz/enigma/network/packet/MessageC2SPacket.java5
-rw-r--r--enigma-server/src/main/java/cuchaz/enigma/network/packet/MessageS2CPacket.java2
-rw-r--r--enigma-server/src/main/java/cuchaz/enigma/network/packet/Packet.java2
-rw-r--r--enigma-server/src/main/java/cuchaz/enigma/network/packet/PacketHelper.java109
-rw-r--r--enigma-server/src/main/java/cuchaz/enigma/network/packet/PacketRegistry.java2
-rw-r--r--enigma-server/src/main/java/cuchaz/enigma/network/packet/SyncMappingsS2CPacket.java9
-rw-r--r--enigma-server/src/main/java/cuchaz/enigma/network/packet/UserListS2CPacket.java8
-rw-r--r--enigma-server/src/test/java/cuchaz/enigma/network/ServerAddressTest.java6
21 files changed, 313 insertions, 223 deletions
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 a651fe84..8fcd4372 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 @@
1package cuchaz.enigma.network; 1package cuchaz.enigma.network;
2 2
3import java.util.List;
4
5import cuchaz.enigma.network.packet.Packet;
3import cuchaz.enigma.translation.mapping.EntryChange; 6import cuchaz.enigma.translation.mapping.EntryChange;
4import cuchaz.enigma.translation.mapping.EntryMapping; 7import cuchaz.enigma.translation.mapping.EntryMapping;
5import cuchaz.enigma.translation.mapping.tree.EntryTree; 8import cuchaz.enigma.translation.mapping.tree.EntryTree;
6import cuchaz.enigma.network.packet.Packet;
7
8import java.util.List;
9 9
10public interface ClientPacketHandler { 10public 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 41f08342..eb22a506 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 @@
1package cuchaz.enigma.network; 1package cuchaz.enigma.network;
2 2
3import com.google.common.io.MoreFiles;
4import cuchaz.enigma.*;
5import cuchaz.enigma.classprovider.ClasspathClassProvider;
6import cuchaz.enigma.translation.mapping.serde.MappingParseException;
7import cuchaz.enigma.translation.mapping.EntryRemapper;
8import cuchaz.enigma.translation.mapping.serde.MappingFormat;
9import cuchaz.enigma.utils.Utils;
10import joptsimple.OptionParser;
11import joptsimple.OptionSet;
12import joptsimple.OptionSpec;
13import joptsimple.ValueConverter;
14
15import java.io.IOException; 3import java.io.IOException;
16import java.io.PrintWriter; 4import java.io.PrintWriter;
17import java.nio.file.Files; 5import java.nio.file.Files;
@@ -22,24 +10,30 @@ import java.util.concurrent.Executors;
22import java.util.concurrent.LinkedBlockingDeque; 10import java.util.concurrent.LinkedBlockingDeque;
23import java.util.concurrent.TimeUnit; 11import java.util.concurrent.TimeUnit;
24 12
25public class DedicatedEnigmaServer extends EnigmaServer { 13import com.google.common.io.MoreFiles;
14import joptsimple.OptionParser;
15import joptsimple.OptionSet;
16import joptsimple.OptionSpec;
17import joptsimple.ValueConverter;
18
19import cuchaz.enigma.Enigma;
20import cuchaz.enigma.EnigmaProfile;
21import cuchaz.enigma.EnigmaProject;
22import cuchaz.enigma.ProgressListener;
23import cuchaz.enigma.classprovider.ClasspathClassProvider;
24import cuchaz.enigma.translation.mapping.EntryRemapper;
25import cuchaz.enigma.translation.mapping.serde.MappingFormat;
26import cuchaz.enigma.translation.mapping.serde.MappingParseException;
27import cuchaz.enigma.utils.Utils;
26 28
29public 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 71bd011c..69e4f5ef 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 @@
1package cuchaz.enigma.network; 1package cuchaz.enigma.network;
2 2
3import cuchaz.enigma.network.packet.Packet; 3import java.io.DataInput;
4import cuchaz.enigma.network.packet.PacketRegistry; 4import java.io.DataInputStream;
5 5import java.io.DataOutput;
6import javax.swing.*; 6import java.io.DataOutputStream;
7import java.io.*; 7import java.io.EOFException;
8import java.io.IOException;
8import java.net.Socket; 9import java.net.Socket;
9import java.net.SocketException; 10import java.net.SocketException;
10 11
11public class EnigmaClient { 12import javax.swing.SwingUtilities;
12 13
14import cuchaz.enigma.network.packet.Packet;
15import cuchaz.enigma.network.packet.PacketRegistry;
16
17public 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 1ce359b6..8872735d 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 @@
1package cuchaz.enigma.network; 1package cuchaz.enigma.network;
2 2
3import java.io.*; 3import java.io.DataInput;
4import java.io.DataInputStream;
5import java.io.DataOutput;
6import java.io.DataOutputStream;
7import java.io.EOFException;
8import java.io.IOException;
4import java.net.ServerSocket; 9import java.net.ServerSocket;
5import java.net.Socket; 10import java.net.Socket;
6import java.net.SocketException; 11import java.net.SocketException;
7import java.util.*; 12import java.util.ArrayList;
13import java.util.Collections;
14import java.util.HashMap;
15import java.util.HashSet;
16import java.util.List;
17import java.util.Map;
18import java.util.Set;
8import java.util.concurrent.CopyOnWriteArrayList; 19import java.util.concurrent.CopyOnWriteArrayList;
9 20
10import cuchaz.enigma.network.packet.*; 21import cuchaz.enigma.network.packet.EntryChangeS2CPacket;
22import cuchaz.enigma.network.packet.KickS2CPacket;
23import cuchaz.enigma.network.packet.MessageS2CPacket;
24import cuchaz.enigma.network.packet.Packet;
25import cuchaz.enigma.network.packet.PacketRegistry;
26import cuchaz.enigma.network.packet.UserListS2CPacket;
11import cuchaz.enigma.translation.mapping.EntryChange; 27import cuchaz.enigma.translation.mapping.EntryChange;
12import cuchaz.enigma.translation.mapping.EntryMapping; 28import cuchaz.enigma.translation.mapping.EntryMapping;
13import cuchaz.enigma.translation.mapping.EntryRemapper; 29import cuchaz.enigma.translation.mapping.EntryRemapper;
14import cuchaz.enigma.translation.representation.entry.Entry; 30import cuchaz.enigma.translation.representation.entry.Entry;
15 31
16public abstract class EnigmaServer { 32public 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 21c6825b..99e4e99e 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 @@
1package cuchaz.enigma.network; 1package cuchaz.enigma.network;
2 2
3import cuchaz.enigma.translation.mapping.EntryRemapper; 3import javax.swing.SwingUtilities;
4 4
5import javax.swing.*; 5import cuchaz.enigma.translation.mapping.EntryRemapper;
6 6
7public class IntegratedEnigmaServer extends EnigmaServer { 7public 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 c1578387..d49e60cb 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;
10import cuchaz.enigma.utils.I18n; 10import cuchaz.enigma.utils.I18n;
11 11
12public abstract class Message { 12public 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 45e07508..a8a10296 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;
5import javax.annotation.Nullable; 5import javax.annotation.Nullable;
6 6
7public class ServerAddress { 7public 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 86185536..5b5b0e66 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;
3import java.net.Socket; 3import java.net.Socket;
4 4
5public class ServerPacketHandler { 5public 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 78ef9645..ab4f5a16 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 @@
1package cuchaz.enigma.network.packet; 1package cuchaz.enigma.network.packet;
2 2
3import cuchaz.enigma.network.ServerPacketHandler;
4
5import java.io.DataInput; 3import java.io.DataInput;
6import java.io.DataOutput; 4import java.io.DataOutput;
7import java.io.IOException; 5import java.io.IOException;
8 6
7import cuchaz.enigma.network.ServerPacketHandler;
8
9public class ConfirmChangeC2SPacket implements Packet<ServerPacketHandler> { 9public 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 b97877c6..6a7ffe99 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;
12import cuchaz.enigma.utils.validation.ValidationContext; 12import cuchaz.enigma.utils.validation.ValidationContext;
13 13
14public class EntryChangeC2SPacket implements Packet<ServerPacketHandler> { 14public 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 a237b916..8e4688e3 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;
8import cuchaz.enigma.translation.mapping.EntryChange; 8import cuchaz.enigma.translation.mapping.EntryChange;
9 9
10public class EntryChangeS2CPacket implements Packet<ClientPacketHandler> { 10public 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 9a112a80..bd238dc1 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 @@
1package cuchaz.enigma.network.packet; 1package cuchaz.enigma.network.packet;
2 2
3import cuchaz.enigma.network.ClientPacketHandler;
4
5import java.io.DataInput; 3import java.io.DataInput;
6import java.io.DataOutput; 4import java.io.DataOutput;
7import java.io.IOException; 5import java.io.IOException;
8 6
7import cuchaz.enigma.network.ClientPacketHandler;
8
9public class KickS2CPacket implements Packet<ClientPacketHandler> { 9public 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 da0f44a5..e93c1d4d 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 @@
1package cuchaz.enigma.network.packet; 1package cuchaz.enigma.network.packet;
2 2
3import cuchaz.enigma.network.EnigmaServer;
4import cuchaz.enigma.network.ServerPacketHandler;
5import cuchaz.enigma.network.Message;
6
7import java.io.DataInput; 3import java.io.DataInput;
8import java.io.DataOutput; 4import java.io.DataOutput;
9import java.io.IOException; 5import java.io.IOException;
10import java.util.Arrays; 6import java.util.Arrays;
11 7
8import cuchaz.enigma.network.EnigmaServer;
9import cuchaz.enigma.network.Message;
10import cuchaz.enigma.network.ServerPacketHandler;
11
12public class LoginC2SPacket implements Packet<ServerPacketHandler> { 12public 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 3bc09e79..b0610b04 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;
4import java.io.DataOutput; 4import java.io.DataOutput;
5import java.io.IOException; 5import java.io.IOException;
6 6
7import cuchaz.enigma.network.ServerPacketHandler;
8import cuchaz.enigma.network.Message; 7import cuchaz.enigma.network.Message;
8import cuchaz.enigma.network.ServerPacketHandler;
9 9
10public class MessageC2SPacket implements Packet<ServerPacketHandler> { 10public 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 2b07968d..9833eebc 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;
8import cuchaz.enigma.network.Message; 8import cuchaz.enigma.network.Message;
9 9
10public class MessageS2CPacket implements Packet<ClientPacketHandler> { 10public 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 2f16dfb9..15054e7b 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;
5import java.io.IOException; 5import java.io.IOException;
6 6
7public interface Packet<H> { 7public 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 2649cdc4..ce767c3c 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;
9import cuchaz.enigma.translation.mapping.EntryChange; 9import cuchaz.enigma.translation.mapping.EntryChange;
10import cuchaz.enigma.translation.representation.MethodDescriptor; 10import cuchaz.enigma.translation.representation.MethodDescriptor;
11import cuchaz.enigma.translation.representation.TypeDescriptor; 11import cuchaz.enigma.translation.representation.TypeDescriptor;
12import cuchaz.enigma.translation.representation.entry.*; 12import cuchaz.enigma.translation.representation.entry.ClassEntry;
13import cuchaz.enigma.translation.representation.entry.Entry;
14import cuchaz.enigma.translation.representation.entry.FieldEntry;
15import cuchaz.enigma.translation.representation.entry.LocalVariableEntry;
16import cuchaz.enigma.translation.representation.entry.MethodEntry;
13import cuchaz.enigma.utils.TristateChange; 17import cuchaz.enigma.utils.TristateChange;
14 18
15public class PacketHelper { 19public 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 59999ccc..49d56fd8 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;
8import cuchaz.enigma.network.ServerPacketHandler; 8import cuchaz.enigma.network.ServerPacketHandler;
9 9
10public class PacketRegistry { 10public 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 6d9c0bcb..7e50938e 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 b4a277a4..baac2b35 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 @@
1package cuchaz.enigma.network.packet; 1package cuchaz.enigma.network.packet;
2 2
3import cuchaz.enigma.network.ClientPacketHandler;
4
5import java.io.DataInput; 3import java.io.DataInput;
6import java.io.DataOutput; 4import java.io.DataOutput;
7import java.io.IOException; 5import java.io.IOException;
8import java.util.ArrayList; 6import java.util.ArrayList;
9import java.util.List; 7import java.util.List;
10 8
11public class UserListS2CPacket implements Packet<ClientPacketHandler> { 9import cuchaz.enigma.network.ClientPacketHandler;
12 10
11public 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 3765f7a5..c2920e02 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 @@
1package cuchaz.enigma.network; 1package cuchaz.enigma.network;
2 2
3import org.junit.Test;
4
5import static org.junit.Assert.assertEquals; 3import static org.junit.Assert.assertEquals;
6import static org.junit.Assert.assertNull; 4import static org.junit.Assert.assertNull;
7 5
8public class ServerAddressTest { 6import org.junit.Test;
9 7
8public 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}