Skip to content

Commit edbb264

Browse files
authored
Merge pull request #21 from halotroop2288/pr/entity-type
Entity Type Registry
2 parents 6c60e19 + 60fd67f commit edbb264

File tree

11 files changed

+260
-60
lines changed

11 files changed

+260
-60
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.fox2code.foxloader.client.mixins;
2+
3+
import net.minecraft.src.game.entity.*;
4+
import org.spongepowered.asm.mixin.*;
5+
import org.spongepowered.asm.mixin.gen.*;
6+
7+
@Mixin(EntityList.class)
8+
public interface AccessorEntityList {
9+
@Invoker
10+
static void invokeAddMapping(Class<?> entityClass, String entityTypeName, int entityTypeID) {
11+
throw new IllegalStateException();
12+
}
13+
}

client/src/main/java/com/fox2code/foxloader/registry/GameRegistryClient.java

Lines changed: 61 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import static com.fox2code.foxloader.loader.ClientMod.*;
44

55
import com.fox2code.foxloader.client.CreativeItems;
6+
import com.fox2code.foxloader.client.mixins.AccessorEntityList;
67
import com.fox2code.foxloader.client.registry.RegisteredBlockImpl;
78
import com.fox2code.foxloader.loader.ModLoader;
89
import com.fox2code.foxloader.loader.packet.ServerHello;
@@ -33,6 +34,11 @@ public class GameRegistryClient extends GameRegistry {
3334
public static final short[] blockIdMappingIn = new short[MAXIMUM_BLOCK_ID];
3435
public static final short[] blockIdMappingOut = new short[MAXIMUM_BLOCK_ID];
3536
public static final String[] itemIdMappingInNames = new String[MAXIMUM_ITEM_ID];
37+
38+
public static final int[] entityTypeIdMappingIn = new int[MAXIMUM_ENTITY_TYPE_ID];
39+
public static final int[] entityTypeIdMappingOut = new int[MAXIMUM_ENTITY_TYPE_ID];
40+
public static final String[] entityTypeIdMappingNames = new String[MAXIMUM_ENTITY_TYPE_ID];
41+
3642
private static MappingState idMappingState = MappingState.CLIENT;
3743
private enum MappingState {
3844
CLIENT, SERVER, CUSTOM
@@ -75,6 +81,7 @@ public static void freeze() {
7581

7682
private int nextBlockId = INITIAL_BLOCK_ID;
7783
private int nextItemId = INITIAL_ITEM_ID;
84+
private int nextEntityTypeId = INITIAL_ENTITY_TYPE_ID;
7885

7986
private GameRegistryClient() {}
8087

@@ -127,18 +134,43 @@ public int generateNewItemId(String name, int fallbackId) {
127134
if (registryEntries.containsKey(name)) {
128135
throw new RuntimeException("Duplicate item/block string id: " + name);
129136
}
137+
130138
if (fallbackId < 0 || fallbackId > 255) {
131139
throw new IllegalArgumentException("Invalid fallback id: " + fallbackId);
132140
}
141+
133142
int itemId = nextItemId++;
143+
134144
if (itemId > MAXIMUM_ITEM_ID) {
135145
throw new RuntimeException("Maximum block count registered! (Too many mods?)");
136146
}
147+
137148
registryEntries.put(name, new RegistryEntry((short) itemId, (short) fallbackId, name,
138149
StringTranslate.getInstance().translateKey("item." + name.replace(':', '.'))));
139150
return itemId;
140151
}
141152

153+
@Override
154+
public int generateNewEntityTypeId(String name, int fallbackId) {
155+
if (registryEntries.containsKey(name)) {
156+
throw new RuntimeException("Duplicate entity string id: " + name);
157+
}
158+
159+
if (fallbackId < 0 || fallbackId > 202) {
160+
throw new IllegalArgumentException("Invalid fallback id: " + fallbackId);
161+
}
162+
163+
int entityTypeId = nextEntityTypeId++;
164+
165+
if (entityTypeId > MAXIMUM_ENTITY_TYPE_ID) {
166+
// This is extremely unlikely
167+
throw new RuntimeException("Maximum entity type count registered! (Too many mods?)");
168+
}
169+
170+
entityTypeEntries.put(name, new EntityTypeRegistryEntry(entityTypeId, fallbackId, name));
171+
return entityTypeId;
172+
}
173+
142174
@Override
143175
public RegisteredBlock registerNewBlock(String name, BlockBuilder blockBuilder, int fallbackId) {
144176
name = validateAndFixRegistryName(name);
@@ -297,6 +329,11 @@ private RegisteredItem registerNewItem0(String name, ItemBuilder itemBuilder,
297329
return (RegisteredItem) item;
298330
}
299331

332+
@Override
333+
public void registerNewEntityType(String name, Class<? extends RegisteredEntity> entityClass, int fallbackId) {
334+
AccessorEntityList.invokeAddMapping(entityClass, name, generateNewEntityTypeId(name, fallbackId));
335+
}
336+
300337
@Override
301338
public void registerRecipe(RegisteredItemStack result, Object... recipe) {
302339
if (recipeFrozen) throw new UnsupportedOperationException(LATE_RECIPE_MESSAGE);
@@ -376,11 +413,11 @@ public static void resetMappings(boolean singlePlayer) {
376413
itemIdMappingIn[i] = DEFAULT_FALLBACK_BLOCK_ID;
377414
itemIdMappingOut[i] = DEFAULT_FALLBACK_BLOCK_ID;
378415
}
379-
for (int i = INITIAL_BLOCK_ID; i < MAXIMUM_BLOCK_ID; i++) {
416+
for (short i = INITIAL_BLOCK_ID; i < MAXIMUM_BLOCK_ID; i++) {
380417
blockIdMappingIn[i] = DEFAULT_FALLBACK_BLOCK_ID;
381418
blockIdMappingOut[i] = DEFAULT_FALLBACK_BLOCK_ID;
382419
}
383-
for (int i = INITIAL_ITEM_ID; i < MAXIMUM_ITEM_ID; i++) {
420+
for (short i = INITIAL_ITEM_ID; i < MAXIMUM_ITEM_ID; i++) {
384421
itemIdMappingIn[i] = DEFAULT_FALLBACK_ITEM_ID;
385422
itemIdMappingOut[i] = DEFAULT_FALLBACK_ITEM_ID;
386423
}
@@ -400,35 +437,46 @@ public static void initializeMappings(ServerHello serverHello) {
400437
return;
401438
}
402439
idMappingState = MappingState.CUSTOM;
403-
for (RegistryEntry registryEntry : serverHello.registryEntries.values()) {
404-
final short remoteId = registryEntry.realId;
440+
for (RegistryEntry entry : serverHello.registryEntries.values()) {
441+
final short remoteId = entry.realId;
405442
if (isLoaderReservedItemId(remoteId)) {
406-
RegistryEntry local = registryEntries.get(
407-
itemIdMappingInNames[remoteId] = registryEntry.name);
443+
RegistryEntry local = registryEntries.get(itemIdMappingInNames[remoteId] = entry.name);
408444
if (local == null) {
409-
itemIdMappingIn[remoteId] = registryEntry.fallbackId;
445+
itemIdMappingIn[remoteId] = entry.fallbackId;
410446
if (remoteId >= INITIAL_TRANSLATED_BLOCK_ID &&
411447
remoteId < MAXIMUM_TRANSLATED_BLOCK_ID) {
412-
blockIdMappingIn[convertItemIdToBlockId(remoteId)] = registryEntry.fallbackId;
448+
blockIdMappingIn[convertItemIdToBlockId(remoteId)] = entry.fallbackId;
413449
}
414450
} else {
415451
itemIdMappingIn[remoteId] = local.realId;
416452
itemIdMappingOut[local.realId] = remoteId;
417-
if (remoteId >= INITIAL_TRANSLATED_BLOCK_ID &&
418-
remoteId < MAXIMUM_TRANSLATED_BLOCK_ID) {
419-
if (local.realId >= INITIAL_TRANSLATED_BLOCK_ID &&
420-
local.realId < MAXIMUM_TRANSLATED_BLOCK_ID) {
453+
if (remoteId >= INITIAL_TRANSLATED_BLOCK_ID && remoteId < MAXIMUM_TRANSLATED_BLOCK_ID) {
454+
if (local.realId >= INITIAL_TRANSLATED_BLOCK_ID && local.realId < MAXIMUM_TRANSLATED_BLOCK_ID) {
421455
final short remoteBlockId = (short) convertItemIdToBlockId(remoteId);
422456
final short localBlockId = (short) convertItemIdToBlockId(local.realId);
423457
blockIdMappingIn[remoteBlockId] = localBlockId;
424458
blockIdMappingOut[localBlockId] = remoteBlockId;
425459
} else {
426460
// We should never reach here, but let still "support" this extreme case.
427-
blockIdMappingIn[convertItemIdToBlockId(remoteId)] = registryEntry.fallbackId;
461+
blockIdMappingIn[convertItemIdToBlockId(remoteId)] = entry.fallbackId;
428462
}
429463
}
430464
}
431465
}
432466
}
467+
468+
for (EntityTypeRegistryEntry entry : serverHello.entityTypeRegistryEntries.values()) {
469+
final int remoteId = entry.realId;
470+
if (isLoaderReservedEntityTypeId(remoteId)) {
471+
EntityTypeRegistryEntry local = entityTypeEntries.get(entityTypeIdMappingNames[remoteId] = entry.name);
472+
if (local == null) {
473+
entityTypeIdMappingIn[remoteId] = entry.fallbackId;
474+
continue;
475+
}
476+
477+
entityTypeIdMappingIn[remoteId] = local.realId;
478+
entityTypeIdMappingOut[local.realId] = remoteId;
479+
}
480+
}
433481
}
434482
}

client/src/main/resources/foxloader.client.mixins.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"package": "com.fox2code.foxloader.client.mixins",
55
"compatibilityLevel": "JAVA_8",
66
"mixins": [
7+
"AccessorEntityList",
78
"MixinBlock",
89
"MixinBlockFire",
910
"MixinChunk",

common/src/main/java/com/fox2code/foxloader/loader/Mod.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,13 @@ public RegisteredBlock registerNewBlock(String name, BlockBuilder blockBuilder)
255255
return GameRegistry.getInstance().registerNewBlock(getModContainer().id + ":" + name, blockBuilder);
256256
}
257257

258+
/**
259+
* @see GameRegistry#registerNewEntityType(String, Class, int)
260+
*/
261+
public void registerNewEntityType(String name, Class<? extends RegisteredEntity> entityClass) {
262+
GameRegistry.getInstance().registerNewEntityType(name, entityClass);
263+
}
264+
258265
/**
259266
* @see GameRegistry#registerRecipe(RegisteredItemStack, Object...)
260267
*/
Lines changed: 76 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,116 @@
11
package com.fox2code.foxloader.loader.packet;
22

3+
import com.fox2code.foxloader.loader.ModLoader;
4+
import com.fox2code.foxloader.registry.EntityTypeRegistryEntry;
35
import com.fox2code.foxloader.registry.RegistryEntry;
46

57
import java.io.DataInputStream;
68
import java.io.DataOutputStream;
79
import java.io.IOException;
810
import java.util.HashMap;
911
import java.util.Map;
12+
import java.util.logging.Level;
1013

1114
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;
1426

1527
public HashMap<String, RegistryEntry> registryEntries;
1628
public HashMap<String, String> metadata;
29+
public HashMap<String, EntityTypeRegistryEntry> entityTypeRegistryEntries;
1730

1831
public ServerHello() {
1932
super(0, false);
2033
}
2134

2235
public ServerHello(HashMap<String, RegistryEntry> registryEntries,
23-
HashMap<String, String> metadata) {
36+
HashMap<String, String> metadata,
37+
HashMap<String, EntityTypeRegistryEntry> entityTypeRegistryEntries) {
2438
super(0, false);
2539
this.registryEntries = registryEntries;
2640
this.metadata = metadata;
41+
this.entityTypeRegistryEntries = entityTypeRegistryEntries;
2742
}
2843

44+
/**
45+
* @throws IOException if the data cannot be read as instructed.
46+
*/
2947
@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.");
3653
}
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);
4462
}
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();
4670
metadata = new HashMap<>();
47-
return;
71+
while (entries-- > 0) {
72+
metadata.put(inStream.readUTF(), inStream.readUTF());
73+
}
4874
}
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+
}
5387
}
5488
}
5589

5690
@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());
6096
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);
65101
}
66-
dataOutputStream.writeShort(this.metadata.size());
102+
103+
outStream.writeShort(this.metadata.size());
67104
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);
70114
}
71115
}
72116
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.fox2code.foxloader.registry;
2+
3+
import org.jetbrains.annotations.ApiStatus;
4+
5+
public class EntityTypeRegistryEntry {
6+
public final int realId, fallbackId;
7+
public final String name;
8+
9+
@ApiStatus.Internal
10+
public EntityTypeRegistryEntry(int realId, int fallbackId, String name) {
11+
this.realId = realId;
12+
this.fallbackId = fallbackId;
13+
this.name = name;
14+
}
15+
}

0 commit comments

Comments
 (0)