Intern strings and other values

This should reduce memory usage at startup by preventing multiple identicals objects being present in memory.
This commit is contained in:
Camotoy 2021-08-11 20:16:10 -04:00
parent 71e2ec989c
commit 0c5b39f35b
No known key found for this signature in database
GPG key ID: 7EEFB66FE798081F
4 changed files with 39 additions and 27 deletions

View file

@ -71,6 +71,10 @@
<groupId>com.nukkitx.network</groupId> <groupId>com.nukkitx.network</groupId>
<artifactId>raknet</artifactId> <artifactId>raknet</artifactId>
</exclusion> </exclusion>
<exclusion>
<groupId>com.nukkitx</groupId>
<artifactId>nbt</artifactId>
</exclusion>
</exclusions> </exclusions>
</dependency> </dependency>
<dependency> <dependency>
@ -85,6 +89,13 @@
</exclusion> </exclusion>
</exclusions> </exclusions>
</dependency> </dependency>
<dependency>
<groupId>com.nukkitx</groupId>
<artifactId>nbt</artifactId>
<!-- Used for key/value interning -->
<version>2.1.0</version>
<scope>compile</scope>
</dependency>
<dependency> <dependency>
<groupId>com.nukkitx.fastutil</groupId> <groupId>com.nukkitx.fastutil</groupId>
<artifactId>fastutil-int-int-maps</artifactId> <artifactId>fastutil-int-int-maps</artifactId>

View file

@ -40,7 +40,7 @@ public class NbtRegistryLoader implements RegistryLoader<String, NbtMap> {
@Override @Override
public NbtMap load(String input) { public NbtMap load(String input) {
InputStream stream = FileUtils.getResource(input); InputStream stream = FileUtils.getResource(input);
try (NBTInputStream nbtInputStream = NbtUtils.createNetworkReader(stream)) { try (NBTInputStream nbtInputStream = NbtUtils.createNetworkReader(stream, true, true)) {
return (NbtMap) nbtInputStream.readTag(); return (NbtMap) nbtInputStream.readTag();
} catch (Exception e) { } catch (Exception e) {
throw new AssertionError("Failed to load registrations for " + input, e); throw new AssertionError("Failed to load registrations for " + input, e);

View file

@ -107,7 +107,7 @@ public class BlockRegistryPopulator {
for (Map.Entry<String, BiFunction<String, NbtMapBuilder, String>> palette : STATE_MAPPER.entrySet()) { for (Map.Entry<String, BiFunction<String, NbtMapBuilder, String>> palette : STATE_MAPPER.entrySet()) {
InputStream stream = FileUtils.getResource(String.format("bedrock/block_palette.%s.nbt", palette.getKey())); InputStream stream = FileUtils.getResource(String.format("bedrock/block_palette.%s.nbt", palette.getKey()));
NbtList<NbtMap> blocksTag; NbtList<NbtMap> blocksTag;
try (NBTInputStream nbtInputStream = new NBTInputStream(new DataInputStream(new GZIPInputStream(stream)))) { try (NBTInputStream nbtInputStream = new NBTInputStream(new DataInputStream(new GZIPInputStream(stream)), true, true)) {
NbtMap blockPalette = (NbtMap) nbtInputStream.readTag(); NbtMap blockPalette = (NbtMap) nbtInputStream.readTag();
blocksTag = (NbtList<NbtMap>) blockPalette.getList("blocks", NbtType.COMPOUND); blocksTag = (NbtList<NbtMap>) blockPalette.getList("blocks", NbtType.COMPOUND);
} catch (Exception e) { } catch (Exception e) {
@ -149,10 +149,10 @@ public class BlockRegistryPopulator {
Map.Entry<String, JsonNode> entry = blocksIterator.next(); Map.Entry<String, JsonNode> entry = blocksIterator.next();
String javaId = entry.getKey(); String javaId = entry.getKey();
NbtMap blockTag = buildBedrockState(entry.getValue(), stateVersion, stateMapper); int bedrockRuntimeId = blockStateOrderedMap.getOrDefault(buildBedrockState(entry.getValue(), stateVersion, stateMapper), -1);
int bedrockRuntimeId = blockStateOrderedMap.getOrDefault(blockTag, -1);
if (bedrockRuntimeId == -1) { if (bedrockRuntimeId == -1) {
throw new RuntimeException("Unable to find " + javaId + " Bedrock runtime ID! Built compound tag: \n" + blockTag); throw new RuntimeException("Unable to find " + javaId + " Bedrock runtime ID! Built NBT tag: \n" +
buildBedrockState(entry.getValue(), stateVersion, stateMapper));
} }
switch (javaId) { switch (javaId) {
@ -182,11 +182,11 @@ public class BlockRegistryPopulator {
// Get the tag needed for non-empty flower pots // Get the tag needed for non-empty flower pots
if (entry.getValue().get("pottable") != null) { if (entry.getValue().get("pottable") != null) {
flowerPotBlocks.put(cleanJavaIdentifier, blockTag); flowerPotBlocks.put(cleanJavaIdentifier.intern(), blocksTag.get(bedrockRuntimeId));
} }
if (!cleanJavaIdentifier.equals(entry.getValue().get("bedrock_identifier").asText())) { if (!cleanJavaIdentifier.equals(entry.getValue().get("bedrock_identifier").asText())) {
javaIdentifierToBedrockTag.put(cleanJavaIdentifier, blockTag); javaIdentifierToBedrockTag.put(cleanJavaIdentifier.intern(), blocksTag.get(bedrockRuntimeId));
} }
javaToBedrockBlockMap.put(javaRuntimeId, bedrockRuntimeId); javaToBedrockBlockMap.put(javaRuntimeId, bedrockRuntimeId);
@ -274,7 +274,7 @@ public class BlockRegistryPopulator {
JsonNode pickItemNode = entry.getValue().get("pick_item"); JsonNode pickItemNode = entry.getValue().get("pick_item");
if (pickItemNode != null) { if (pickItemNode != null) {
builder.pickItem(pickItemNode.textValue()); builder.pickItem(pickItemNode.textValue().intern());
} }
BlockStateValues.storeBlockStateValues(entry.getKey(), javaRuntimeId, entry.getValue()); BlockStateValues.storeBlockStateValues(entry.getKey(), javaRuntimeId, entry.getValue());
@ -284,7 +284,7 @@ public class BlockRegistryPopulator {
if (!cleanIdentifiers.contains(cleanJavaIdentifier)) { if (!cleanIdentifiers.contains(cleanJavaIdentifier)) {
uniqueJavaId++; uniqueJavaId++;
cleanIdentifiers.add(cleanJavaIdentifier); cleanIdentifiers.add(cleanJavaIdentifier.intern());
} }
builder.javaIdentifier(javaId); builder.javaIdentifier(javaId);
@ -295,7 +295,7 @@ public class BlockRegistryPopulator {
// Keeping this here since this is currently unchanged between versions // Keeping this here since this is currently unchanged between versions
if (!cleanJavaIdentifier.equals(bedrockIdentifier)) { if (!cleanJavaIdentifier.equals(bedrockIdentifier)) {
BlockRegistries.JAVA_TO_BEDROCK_IDENTIFIERS.register(cleanJavaIdentifier, bedrockIdentifier); BlockRegistries.JAVA_TO_BEDROCK_IDENTIFIERS.register(cleanJavaIdentifier.intern(), bedrockIdentifier.intern());
} }
if (javaId.startsWith("minecraft:bell[")) { if (javaId.startsWith("minecraft:bell[")) {

View file

@ -249,24 +249,25 @@ public class ItemRegistryPopulator {
javaOnlyItems.addAll(palette.getValue().getAdditionalTranslatedItems().keySet()); javaOnlyItems.addAll(palette.getValue().getAdditionalTranslatedItems().keySet());
for (Map.Entry<String, GeyserMappingItem> entry : items.entrySet()) { for (Map.Entry<String, GeyserMappingItem> entry : items.entrySet()) {
String javaIdentifier = entry.getKey().intern();
GeyserMappingItem mappingItem; GeyserMappingItem mappingItem;
String replacementItem = palette.getValue().getAdditionalTranslatedItems().get(entry.getKey()); String replacementItem = palette.getValue().getAdditionalTranslatedItems().get(javaIdentifier);
if (replacementItem != null) { if (replacementItem != null) {
mappingItem = items.get(replacementItem); mappingItem = items.get(replacementItem);
} else { } else {
// This items has a mapping specifically for this version of the game // This items has a mapping specifically for this version of the game
mappingItem = entry.getValue(); mappingItem = entry.getValue();
} }
if (entry.getKey().equals("minecraft:sculk_sensor") && GeyserConnector.getInstance().getConfig().isExtendedWorldHeight()) { if (javaIdentifier.equals("minecraft:sculk_sensor") && GeyserConnector.getInstance().getConfig().isExtendedWorldHeight()) {
mappingItem.setBedrockIdentifier("minecraft:sculk_sensor"); mappingItem.setBedrockIdentifier("minecraft:sculk_sensor");
} }
if (usingFurnaceMinecart && entry.getKey().equals("minecraft:furnace_minecart")) { if (usingFurnaceMinecart && javaIdentifier.equals("minecraft:furnace_minecart")) {
javaFurnaceMinecartId = itemIndex; javaFurnaceMinecartId = itemIndex;
itemIndex++; itemIndex++;
continue; continue;
} }
String bedrockIdentifier = mappingItem.getBedrockIdentifier(); String bedrockIdentifier = mappingItem.getBedrockIdentifier().intern();
int bedrockId = bedrockIdentifierToId.getInt(bedrockIdentifier); int bedrockId = bedrockIdentifierToId.getInt(bedrockIdentifier);
if (bedrockId == Short.MIN_VALUE) { if (bedrockId == Short.MIN_VALUE) {
throw new RuntimeException("Missing Bedrock ID in mappings: " + bedrockIdentifier); throw new RuntimeException("Missing Bedrock ID in mappings: " + bedrockIdentifier);
@ -389,7 +390,7 @@ public class ItemRegistryPopulator {
} }
ItemMapping.ItemMappingBuilder mappingBuilder = ItemMapping.builder() ItemMapping.ItemMappingBuilder mappingBuilder = ItemMapping.builder()
.javaIdentifier(entry.getKey()) .javaIdentifier(javaIdentifier)
.javaId(itemIndex) .javaId(itemIndex)
.bedrockIdentifier(bedrockIdentifier) .bedrockIdentifier(bedrockIdentifier)
.bedrockId(bedrockId) .bedrockId(bedrockId)
@ -399,14 +400,14 @@ public class ItemRegistryPopulator {
if (mappingItem.getToolType() != null) { if (mappingItem.getToolType() != null) {
if (mappingItem.getToolTier() != null) { if (mappingItem.getToolTier() != null) {
mappingBuilder = mappingBuilder.toolType(mappingItem.getToolType()) mappingBuilder = mappingBuilder.toolType(mappingItem.getToolType().intern())
.toolTier(mappingItem.getToolTier()); .toolTier(mappingItem.getToolTier().intern());
} else { } else {
mappingBuilder = mappingBuilder.toolType(mappingItem.getToolType()) mappingBuilder = mappingBuilder.toolType(mappingItem.getToolType().intern())
.toolTier(""); .toolTier("");
} }
} }
if (javaOnlyItems.contains(entry.getKey())) { if (javaOnlyItems.contains(javaIdentifier)) {
// These items don't exist on Bedrock, so set up a variable that indicates they should have custom names // These items don't exist on Bedrock, so set up a variable that indicates they should have custom names
mappingBuilder = mappingBuilder.translationString((bedrockBlockId != -1 ? "block." : "item.") + entry.getKey().replace(":", ".")); mappingBuilder = mappingBuilder.translationString((bedrockBlockId != -1 ? "block." : "item.") + entry.getKey().replace(":", "."));
GeyserConnector.getInstance().getLogger().debug("Adding " + entry.getKey() + " as an item that needs to be translated."); GeyserConnector.getInstance().getLogger().debug("Adding " + entry.getKey() + " as an item that needs to be translated.");
@ -414,11 +415,11 @@ public class ItemRegistryPopulator {
ItemMapping mapping = mappingBuilder.build(); ItemMapping mapping = mappingBuilder.build();
if (entry.getKey().contains("boat")) { if (javaIdentifier.contains("boat")) {
boats.add(bedrockId); boats.add(bedrockId);
} else if (entry.getKey().contains("bucket") && !entry.getKey().contains("milk")) { } else if (javaIdentifier.contains("bucket") && !javaIdentifier.contains("milk")) {
buckets.add(bedrockId); buckets.add(bedrockId);
} else if (entry.getKey().contains("_carpet") && !entry.getKey().contains("moss")) { } else if (javaIdentifier.contains("_carpet") && !javaIdentifier.contains("moss")) {
// This should be the numerical order Java sends as an integer value for llamas // This should be the numerical order Java sends as an integer value for llamas
carpets.add(ItemData.builder() carpets.add(ItemData.builder()
.id(mapping.getBedrockId()) .id(mapping.getBedrockId())
@ -426,18 +427,18 @@ public class ItemRegistryPopulator {
.count(1) .count(1)
.blockRuntimeId(mapping.getBedrockBlockId()) .blockRuntimeId(mapping.getBedrockBlockId())
.build()); .build());
} else if (entry.getKey().startsWith("minecraft:music_disc_")) { } else if (javaIdentifier.startsWith("minecraft:music_disc_")) {
// The Java record level event uses the item ID as the "key" to play the record // The Java record level event uses the item ID as the "key" to play the record
Registries.RECORDS.register(itemIndex, SoundEvent.valueOf("RECORD_" + Registries.RECORDS.register(itemIndex, SoundEvent.valueOf("RECORD_" +
entry.getKey().replace("minecraft:music_disc_", "").toUpperCase(Locale.ENGLISH))); javaIdentifier.replace("minecraft:music_disc_", "").toUpperCase(Locale.ENGLISH).intern()));
} else if (entry.getKey().endsWith("_spawn_egg")) { } else if (javaIdentifier.endsWith("_spawn_egg")) {
spawnEggs.add(mapping.getBedrockId()); spawnEggs.add(mapping.getBedrockId());
} }
mappings.put(itemIndex, mapping); mappings.put(itemIndex, mapping);
identifierToMapping.put(entry.getKey(), mapping); identifierToMapping.put(javaIdentifier, mapping);
itemNames.add(entry.getKey()); itemNames.add(javaIdentifier);
itemIndex++; itemIndex++;
} }