|
1 | 1 | package com.fox2code.foxloader.loader.packet; |
2 | 2 |
|
| 3 | +import com.fox2code.foxloader.loader.ModLoader; |
| 4 | +import com.fox2code.foxloader.registry.EntityTypeRegistryEntry; |
3 | 5 | import com.fox2code.foxloader.registry.RegistryEntry; |
4 | 6 |
|
5 | 7 | import java.io.DataInputStream; |
6 | 8 | import java.io.DataOutputStream; |
7 | 9 | import java.io.IOException; |
8 | 10 | import java.util.HashMap; |
9 | 11 | import java.util.Map; |
| 12 | +import java.util.logging.Level; |
10 | 13 |
|
11 | 14 | public final class ServerHello extends FoxPacket { |
12 | | - public static final int SERVER_HELLO_VERSION = 0; |
13 | | - private static final int SERVER_HELLO_VERSION_NEXT = 1; |
| 15 | + /** |
| 16 | + * <p>The current version of the Server Hello packet.</p> |
| 17 | + * <b>V0</b> - <i>Block and Item registry entries and metadata</i>.<br/> |
| 18 | + * <b>V1</b> - <i>Entity type registry metadata appended to the end</i>. |
| 19 | + */ |
| 20 | + public static final short SERVER_HELLO_VERSION = 1; |
| 21 | + /** |
| 22 | + * <p>The minimum version of ServerHello on older clients for the server to be compatible with.</p> |
| 23 | + * V0 clients will always expect exactly {@literal 0}. |
| 24 | + */ |
| 25 | + private static final short CLIENT_BACKWARD_COMPATIBILITY_VERSION = 0; |
14 | 26 |
|
15 | 27 | public HashMap<String, RegistryEntry> registryEntries; |
16 | 28 | public HashMap<String, String> metadata; |
| 29 | + public HashMap<String, EntityTypeRegistryEntry> entityTypeRegistryEntries; |
17 | 30 |
|
18 | 31 | public ServerHello() { |
19 | 32 | super(0, false); |
20 | 33 | } |
21 | 34 |
|
22 | 35 | public ServerHello(HashMap<String, RegistryEntry> registryEntries, |
23 | | - HashMap<String, String> metadata) { |
| 36 | + HashMap<String, String> metadata, |
| 37 | + HashMap<String, EntityTypeRegistryEntry> entityTypeRegistryEntries) { |
24 | 38 | super(0, false); |
25 | 39 | this.registryEntries = registryEntries; |
26 | 40 | this.metadata = metadata; |
| 41 | + this.entityTypeRegistryEntries = entityTypeRegistryEntries; |
27 | 42 | } |
28 | 43 |
|
| 44 | + /** |
| 45 | + * @throws IOException if the data cannot be read as instructed. |
| 46 | + */ |
29 | 47 | @Override |
30 | | - public void readData(DataInputStream dataInputStream) throws IOException { |
31 | | - int serverHelloVersion = dataInputStream.readUnsignedShort(); |
32 | | - if (serverHelloVersion >= SERVER_HELLO_VERSION_NEXT && |
33 | | - // Next field is how much backward compatible is the packet |
34 | | - dataInputStream.readUnsignedShort() > SERVER_HELLO_VERSION_NEXT) { |
35 | | - throw new RuntimeException("Client is critically out of date, please update FoxLoader"); |
| 48 | + public void readData(DataInputStream inStream) throws IOException { |
| 49 | + int serverHelloVersion = inStream.readUnsignedShort(); |
| 50 | + int clientBackwardCompatibilityVersion = inStream.readUnsignedShort(); |
| 51 | + if (SERVER_HELLO_VERSION < clientBackwardCompatibilityVersion) { |
| 52 | + throw new IOException("Client is critically out of date, please update FoxLoader."); |
36 | 53 | } |
37 | | - int entries = dataInputStream.readUnsignedShort(); |
38 | | - registryEntries = new HashMap<>(entries); |
39 | | - while (entries-->0) { |
40 | | - RegistryEntry registryEntry = new RegistryEntry( |
41 | | - dataInputStream.readShort(), dataInputStream.readShort(), |
42 | | - dataInputStream.readUTF(), dataInputStream.readUTF()); |
43 | | - registryEntries.put(registryEntry.name, registryEntry); |
| 54 | + |
| 55 | + int entries = inStream.readUnsignedShort(); |
| 56 | + this.registryEntries = new HashMap<>(entries); |
| 57 | + while (entries-- > 0) { |
| 58 | + RegistryEntry entry = new RegistryEntry( |
| 59 | + inStream.readShort(), inStream.readShort(), |
| 60 | + inStream.readUTF(), inStream.readUTF()); |
| 61 | + this.registryEntries.put(entry.name, entry); |
44 | 62 | } |
45 | | - if (dataInputStream.available() == 0) { |
| 63 | + |
| 64 | + if (inStream.available() < 2) { |
| 65 | + // Too few bytes to read the next short. |
| 66 | + this.metadata = new HashMap<>(); |
| 67 | + ModLoader.getModLoaderLogger().log(Level.WARNING, "Server Hello: Too few bytes to read metadata."); |
| 68 | + } else { |
| 69 | + entries = inStream.readUnsignedShort(); |
46 | 70 | metadata = new HashMap<>(); |
47 | | - return; |
| 71 | + while (entries-- > 0) { |
| 72 | + metadata.put(inStream.readUTF(), inStream.readUTF()); |
| 73 | + } |
48 | 74 | } |
49 | | - entries = dataInputStream.readUnsignedShort(); |
50 | | - metadata = new HashMap<>(); |
51 | | - while (entries-->0) { |
52 | | - metadata.put(dataInputStream.readUTF(), dataInputStream.readUTF()); |
| 75 | + |
| 76 | + if (inStream.available() < 4) { |
| 77 | + this.entityTypeRegistryEntries = new HashMap<>(); |
| 78 | + ModLoader.getModLoaderLogger().log(Level.WARNING, "Server Hello: Too few bytes to read entity data."); |
| 79 | + } else { |
| 80 | + int entityEntries = inStream.readInt(); |
| 81 | + entityTypeRegistryEntries = new HashMap<>(entityEntries); |
| 82 | + while (entityEntries-- > 0) { |
| 83 | + EntityTypeRegistryEntry entry = new EntityTypeRegistryEntry( |
| 84 | + inStream.readInt(), inStream.readInt(), inStream.readUTF()); |
| 85 | + this.entityTypeRegistryEntries.put(entry.name, entry); |
| 86 | + } |
53 | 87 | } |
54 | 88 | } |
55 | 89 |
|
56 | 90 | @Override |
57 | | - public void writeData(DataOutputStream dataOutputStream) throws IOException { |
58 | | - dataOutputStream.writeShort(SERVER_HELLO_VERSION); |
59 | | - dataOutputStream.writeShort(this.registryEntries.size()); |
| 91 | + public void writeData(DataOutputStream outStream) throws IOException { |
| 92 | + outStream.writeShort(SERVER_HELLO_VERSION); |
| 93 | + outStream.writeShort(CLIENT_BACKWARD_COMPATIBILITY_VERSION); |
| 94 | + |
| 95 | + outStream.writeShort(this.registryEntries.size()); |
60 | 96 | for (RegistryEntry registryEntry : registryEntries.values()) { |
61 | | - dataOutputStream.writeShort(registryEntry.realId); |
62 | | - dataOutputStream.writeByte(registryEntry.fallbackId); |
63 | | - dataOutputStream.writeUTF(registryEntry.name); |
64 | | - dataOutputStream.writeUTF(registryEntry.fallbackDisplayName); |
| 97 | + outStream.writeShort(registryEntry.realId); |
| 98 | + outStream.writeByte(registryEntry.fallbackId); |
| 99 | + outStream.writeUTF(registryEntry.name); |
| 100 | + outStream.writeUTF(registryEntry.fallbackDisplayName); |
65 | 101 | } |
66 | | - dataOutputStream.writeShort(this.metadata.size()); |
| 102 | + |
| 103 | + outStream.writeShort(this.metadata.size()); |
67 | 104 | for (Map.Entry<String, String> metadata : this.metadata.entrySet()) { |
68 | | - dataOutputStream.writeUTF(metadata.getKey()); |
69 | | - dataOutputStream.writeUTF(metadata.getValue()); |
| 105 | + outStream.writeUTF(metadata.getKey()); |
| 106 | + outStream.writeUTF(metadata.getValue()); |
| 107 | + } |
| 108 | + |
| 109 | + outStream.writeInt(this.entityTypeRegistryEntries.size()); |
| 110 | + for (EntityTypeRegistryEntry entry : entityTypeRegistryEntries.values()) { |
| 111 | + outStream.writeInt(entry.realId); |
| 112 | + outStream.writeInt(entry.fallbackId); |
| 113 | + outStream.writeUTF(entry.name); |
70 | 114 | } |
71 | 115 | } |
72 | 116 | } |
0 commit comments