Skip to content

Commit d6d19b0

Browse files
authored
Fix #5089 and don't auto-load Registries (#5093)
* Fix #5089 and made Registries instance based * Instead of using instance based Registries, manually initialize them * Address review * Commit this too pls
1 parent 6331cb6 commit d6d19b0

27 files changed

+633
-431
lines changed

core/src/main/java/org/geysermc/geyser/entity/EntityDefinition.java

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@
3737
import org.geysermc.geyser.entity.type.Entity;
3838
import org.geysermc.geyser.registry.Registries;
3939
import org.geysermc.geyser.translator.entity.EntityMetadataTranslator;
40-
import org.geysermc.geyser.util.EnvironmentUtils;
4140
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata;
4241
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.MetadataType;
4342
import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType;
@@ -146,13 +145,8 @@ public Builder<T> addTranslator(EntityMetadataTranslator<T, ?, ?> translator) {
146145
return this;
147146
}
148147

149-
/**
150-
* Build the given entity. If a testing environment has been discovered the entity is not registered,
151-
* otherwise it is. This is to prevent all the registries from loading, which will fail (and should
152-
* not be loaded) while testing
153-
*/
154148
public EntityDefinition<T> build() {
155-
return build(!EnvironmentUtils.isUnitTesting);
149+
return build(true);
156150
}
157151

158152
/**

core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,6 @@
145145
import org.geysermc.geyser.entity.type.player.PlayerEntity;
146146
import org.geysermc.geyser.registry.Registries;
147147
import org.geysermc.geyser.translator.text.MessageTranslator;
148-
import org.geysermc.geyser.util.EnvironmentUtils;
149148
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.MetadataType;
150149
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
151150
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.FloatEntityMetadata;
@@ -1122,10 +1121,7 @@ public final class EntityDefinitions {
11221121
.identifier("minecraft:armor_stand") // Emulated
11231122
.build(false); // Never sent over the network
11241123

1125-
// causes the registries to load
1126-
if (!EnvironmentUtils.isUnitTesting) {
1127-
Registries.JAVA_ENTITY_IDENTIFIERS.get().put("minecraft:marker", null); // We don't need an entity definition for this as it is never sent over the network
1128-
}
1124+
Registries.JAVA_ENTITY_IDENTIFIERS.get().put("minecraft:marker", null); // We don't need an entity definition for this as it is never sent over the network
11291125
}
11301126

11311127
public static void init() {

core/src/main/java/org/geysermc/geyser/entity/GeyserDirtyMetadata.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
import java.util.Map;
3333

3434
/**
35-
* A write-only wrapper for temporarily storing entity metadata that will be sent to Bedrock.
35+
* A wrapper for temporarily storing entity metadata that will be sent to Bedrock.
3636
*/
3737
public final class GeyserDirtyMetadata {
3838
private final Map<EntityDataType<?>, Object> metadata = new Object2ObjectLinkedOpenHashMap<>();
@@ -53,6 +53,14 @@ public boolean hasEntries() {
5353
return !metadata.isEmpty();
5454
}
5555

56+
/**
57+
* Intended for testing purposes only
58+
*/
59+
public <T> T get(EntityDataType<T> entityData) {
60+
//noinspection unchecked
61+
return (T) metadata.get(entityData);
62+
}
63+
5664
@Override
5765
public String toString() {
5866
return metadata.toString();

core/src/main/java/org/geysermc/geyser/entity/type/living/ArmorStandEntity.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
import lombok.Getter;
2929
import net.kyori.adventure.text.Component;
30+
import org.checkerframework.checker.nullness.qual.Nullable;
3031
import org.cloudburstmc.math.vector.Vector3f;
3132
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataType;
3233
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
@@ -36,6 +37,7 @@
3637
import org.geysermc.geyser.entity.EntityDefinitions;
3738
import org.geysermc.geyser.entity.type.LivingEntity;
3839
import org.geysermc.geyser.item.Items;
40+
import org.geysermc.geyser.scoreboard.Team;
3941
import org.geysermc.geyser.session.GeyserSession;
4042
import org.geysermc.geyser.util.InteractionResult;
4143
import org.geysermc.geyser.util.MathUtils;
@@ -123,6 +125,12 @@ public void moveAbsolute(Vector3f position, float yaw, float pitch, float headYa
123125
this.position = position;
124126
}
125127

128+
@Override
129+
public void updateNametag(@Nullable Team team) {
130+
// unlike all other LivingEntities, armor stands are not affected by team nametag visibility
131+
super.updateNametag(team, true);
132+
}
133+
126134
@Override
127135
public void setDisplayName(EntityMetadata<Optional<Component>, ?> entityMetadata) {
128136
super.setDisplayName(entityMetadata);

core/src/main/java/org/geysermc/geyser/entity/type/player/PlayerEntity.java

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@
4343
import org.cloudburstmc.protocol.bedrock.data.GameType;
4444
import org.cloudburstmc.protocol.bedrock.data.PlayerPermission;
4545
import org.cloudburstmc.protocol.bedrock.data.command.CommandPermission;
46-
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataMap;
4746
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
4847
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
4948
import org.cloudburstmc.protocol.bedrock.data.entity.EntityLinkData;
@@ -112,20 +111,6 @@ public PlayerEntity(GeyserSession session, int entityId, long geyserId, UUID uui
112111
this.texturesProperty = texturesProperty;
113112
}
114113

115-
/**
116-
* Do not use! For testing purposes only
117-
*/
118-
public PlayerEntity(GeyserSession session, long geyserId, UUID uuid, String username) {
119-
super(session, -1, geyserId, uuid, EntityDefinitions.PLAYER, Vector3f.ZERO, Vector3f.ZERO, 0, 0, 0);
120-
this.username = username;
121-
this.nametag = username;
122-
this.texturesProperty = null;
123-
124-
// clear initial metadata
125-
dirtyMetadata.apply(new EntityDataMap());
126-
setFlagsDirty(false);
127-
}
128-
129114
@Override
130115
protected void initializeMetadata() {
131116
super.initializeMetadata();
@@ -193,11 +178,7 @@ public void sendPlayer() {
193178
if (session.getEntityCache().getPlayerEntity(uuid) == null)
194179
return;
195180

196-
if (session.getEntityCache().getEntityByGeyserId(geyserId) == null) {
197-
session.getEntityCache().spawnEntity(this);
198-
} else {
199-
spawnEntity();
200-
}
181+
session.getEntityCache().spawnEntity(this);
201182
}
202183

203184
@Override

core/src/main/java/org/geysermc/geyser/registry/Registries.java

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -62,14 +62,16 @@
6262
* Holds all the common registries in Geyser.
6363
*/
6464
public final class Registries {
65+
private static boolean initialized = false;
66+
6567
/**
6668
* A registry holding all the providers.
6769
* This has to be initialized first to allow extensions to access providers during other registry events.
6870
*/
6971
public static final SimpleMappedRegistry<Class<?>, ProviderSupplier> PROVIDERS = SimpleMappedRegistry.create(new IdentityHashMap<>(), ProviderRegistryLoader::new);
7072

7173
/**
72-
* A registry holding a CompoundTag of the known entity identifiers.
74+
* A registry holding a NbtMap of the known entity identifiers.
7375
*/
7476
public static final SimpleRegistry<NbtMap> BEDROCK_ENTITY_IDENTIFIERS = SimpleRegistry.create("bedrock/entity_identifiers.dat", RegistryLoaders.NBT);
7577

@@ -79,7 +81,7 @@ public final class Registries {
7981
public static final PacketTranslatorRegistry<BedrockPacket> BEDROCK_PACKET_TRANSLATORS = PacketTranslatorRegistry.create();
8082

8183
/**
82-
* A registry holding a CompoundTag of all the known biomes.
84+
* A registry holding a NbtMap of all the known biomes.
8385
*/
8486
public static final SimpleRegistry<NbtMap> BIOMES_NBT = SimpleRegistry.create("bedrock/biome_definitions.dat", RegistryLoaders.NBT);
8587

@@ -118,6 +120,9 @@ public final class Registries {
118120
*/
119121
public static final ListRegistry<Item> JAVA_ITEMS = ListRegistry.create(RegistryLoaders.empty(ArrayList::new));
120122

123+
/**
124+
* A registry containing item identifiers.
125+
*/
121126
public static final SimpleMappedRegistry<String, Item> JAVA_ITEM_IDENTIFIERS = SimpleMappedRegistry.create(RegistryLoaders.empty(Object2ObjectOpenHashMap::new));
122127

123128
/**
@@ -135,7 +140,7 @@ public final class Registries {
135140
/**
136141
* A registry holding all the potion mixes.
137142
*/
138-
public static final VersionedRegistry<Set<PotionMixData>> POTION_MIXES;
143+
public static final VersionedRegistry<Set<PotionMixData>> POTION_MIXES = VersionedRegistry.create(PotionMixRegistryLoader::new);
139144

140145
/**
141146
* A versioned registry holding all the recipes, with the net ID being the key, and {@link GeyserRecipe} as the value.
@@ -163,15 +168,35 @@ public final class Registries {
163168
public static final SimpleMappedRegistry<SoundTranslator, SoundInteractionTranslator<?>> SOUND_TRANSLATORS = SimpleMappedRegistry.create("org.geysermc.geyser.translator.sound.SoundTranslator", SoundTranslatorRegistryLoader::new);
164169

165170
public static void init() {
166-
// no-op
167-
}
171+
if (initialized) return;
172+
initialized = true;
173+
174+
PROVIDERS.load();
175+
BEDROCK_ENTITY_IDENTIFIERS.load();
176+
BEDROCK_PACKET_TRANSLATORS.load();
177+
BIOMES_NBT.load();
178+
BIOME_IDENTIFIERS.load();
179+
BLOCK_ENTITIES.load();
180+
ENTITY_DEFINITIONS.load();
181+
BEDROCK_ENTITY_PROPERTIES.load();
182+
JAVA_ENTITY_IDENTIFIERS.load();
183+
JAVA_PACKET_TRANSLATORS.load();
184+
JAVA_ITEMS.load();
185+
JAVA_ITEM_IDENTIFIERS.load();
186+
ITEMS.load();
187+
PARTICLES.load();
188+
// load potion mixes later
189+
RECIPES.load();
190+
RESOURCE_PACKS.load();
191+
SOUNDS.load();
192+
SOUND_LEVEL_EVENTS.load();
193+
SOUND_TRANSLATORS.load();
168194

169-
static {
170195
PacketRegistryPopulator.populate();
171196
ItemRegistryPopulator.populate();
172197

173-
// Create registries that require other registries to load first
174-
POTION_MIXES = VersionedRegistry.create(PotionMixRegistryLoader::new);
198+
// potion mixes depend on other registries
199+
POTION_MIXES.load();
175200

176201
// Remove unneeded client generation data from NbtMapBuilder
177202
NbtMapBuilder biomesNbt = NbtMap.builder();

core/src/main/java/org/geysermc/geyser/registry/Registry.java

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@
2525

2626
package org.geysermc.geyser.registry;
2727

28-
import org.geysermc.geyser.registry.loader.RegistryLoader;
29-
3028
import java.util.function.Consumer;
29+
import org.geysermc.geyser.registry.loader.RegistryLoader;
30+
import org.geysermc.geyser.registry.loader.RegistryLoaderHolder;
3131

3232
/**
3333
* A wrapper around a value which is loaded based on the output from the provided
@@ -63,7 +63,9 @@
6363
*
6464
* @param <M> the value being held by the registry
6565
*/
66+
@SuppressWarnings("rawtypes")
6667
public abstract class Registry<M> implements IRegistry<M> {
68+
protected RegistryLoaderHolder loaderHolder;
6769
protected M mappings;
6870

6971
/**
@@ -76,7 +78,17 @@ public abstract class Registry<M> implements IRegistry<M> {
7678
* @param <I> the input type
7779
*/
7880
protected <I> Registry(I input, RegistryLoader<I, M> registryLoader) {
79-
this.mappings = registryLoader.load(input);
81+
this.loaderHolder = new RegistryLoaderHolder<>(input, registryLoader);
82+
}
83+
84+
public void load() {
85+
// don't load twice
86+
if (this.mappings != null) return;
87+
88+
var holder = this.loaderHolder;
89+
this.loaderHolder = null;
90+
//noinspection unchecked
91+
this.mappings = (M) holder.registryLoader().load(holder.input());
8092
}
8193

8294
/**
@@ -111,4 +123,4 @@ public void set(M mappings) {
111123
public void register(Consumer<M> consumer) {
112124
consumer.accept(this.mappings);
113125
}
114-
}
126+
}

core/src/main/java/org/geysermc/geyser/registry/loader/PotionMixRegistryLoader.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,4 +125,4 @@ private static ItemMapping getNonNull(ItemMappings mappings, Item javaItem) {
125125

126126
return itemMapping;
127127
}
128-
}
128+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright (c) 2024 GeyserMC. http://geysermc.org
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a copy
5+
* of this software and associated documentation files (the "Software"), to deal
6+
* in the Software without restriction, including without limitation the rights
7+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
* copies of the Software, and to permit persons to whom the Software is
9+
* furnished to do so, subject to the following conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be included in
12+
* all copies or substantial portions of the Software.
13+
*
14+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+
* THE SOFTWARE.
21+
*
22+
* @author GeyserMC
23+
* @link https://github.com/GeyserMC/Geyser
24+
*/
25+
26+
package org.geysermc.geyser.registry.loader;
27+
28+
/**
29+
* A holder of the constructor parameters to prevent them from automatically loading,
30+
* and instead load them when the load method is called.
31+
*/
32+
public record RegistryLoaderHolder<I, M>(I input, RegistryLoader<I, M> registryLoader) {
33+
}

core/src/main/java/org/geysermc/geyser/scoreboard/Team.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ public void addEntities(String... names) {
9090
// Remove old team from this map, and from the set of players of the old team.
9191
// Java 1.19.3 Mojmap: Scoreboard#addPlayerToTeam calls #removePlayerFromTeam
9292
oldTeam.entities.remove(player);
93+
// also remove the managed entity if there is one
94+
removeManagedEntity(player);
9395
}
9496
return this;
9597
});
@@ -282,6 +284,15 @@ private void removeRemovedEntities(Set<String> names) {
282284
}
283285
}
284286

287+
/**
288+
* Used internally to remove a managed entity without causing an update.
289+
* This is fine because its only used when the entity is added to another team,
290+
* which will fire the correct nametag updates etc.
291+
*/
292+
private void removeManagedEntity(String name) {
293+
managedEntities.removeIf(entity -> name.equals(entity.teamIdentifier()));
294+
}
295+
285296
private void refreshAllEntities() {
286297
for (Entity entity : session().getEntityCache().getEntities().values()) {
287298
entity.updateNametag(scoreboard.getTeamFor(entity.teamIdentifier()));

0 commit comments

Comments
 (0)