1
0
mirror of https://github.com/GeyserMC/Geyser.git synced 2025-12-19 14:59:27 +00:00

Add loading of new util.json mappings (#5823)

* Add loading of new util.json mappings

* Remove now unused set

* Switch to loading util mappings through registries

* Add Javadocs for UtilMappings

* Target mappings with util.json
This commit is contained in:
Eclipse
2025-09-17 12:22:34 +00:00
committed by GitHub
parent 4236036833
commit e8e4e80fe8
5 changed files with 119 additions and 12 deletions

View File

@@ -29,6 +29,7 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import net.kyori.adventure.key.Key;
import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.protocol.bedrock.data.biome.BiomeDefinitions; import org.cloudburstmc.protocol.bedrock.data.biome.BiomeDefinitions;
@@ -56,6 +57,7 @@ import org.geysermc.geyser.registry.provider.ProviderSupplier;
import org.geysermc.geyser.registry.type.ItemMappings; import org.geysermc.geyser.registry.type.ItemMappings;
import org.geysermc.geyser.registry.type.ParticleMapping; import org.geysermc.geyser.registry.type.ParticleMapping;
import org.geysermc.geyser.registry.type.SoundMapping; import org.geysermc.geyser.registry.type.SoundMapping;
import org.geysermc.geyser.registry.type.UtilMappings;
import org.geysermc.geyser.translator.level.block.entity.BlockEntityTranslator; import org.geysermc.geyser.translator.level.block.entity.BlockEntityTranslator;
import org.geysermc.geyser.translator.level.event.LevelEventTranslator; import org.geysermc.geyser.translator.level.event.LevelEventTranslator;
import org.geysermc.geyser.translator.sound.SoundInteractionTranslator; import org.geysermc.geyser.translator.sound.SoundInteractionTranslator;
@@ -197,6 +199,21 @@ public final class Registries {
*/ */
public static final SimpleMappedDeferredRegistry<SoundTranslator, SoundInteractionTranslator<?>> SOUND_TRANSLATORS = SimpleMappedDeferredRegistry.create("org.geysermc.geyser.translator.sound.SoundTranslator", SoundTranslatorRegistryLoader::new); public static final SimpleMappedDeferredRegistry<SoundTranslator, SoundInteractionTranslator<?>> SOUND_TRANSLATORS = SimpleMappedDeferredRegistry.create("org.geysermc.geyser.translator.sound.SoundTranslator", SoundTranslatorRegistryLoader::new);
/**
* A registry containing all of Java's "game master blocks" - blocks that can't be broken without operator permission level 2 or higher.
*/
public static final ListDeferredRegistry<Key> GAME_MASTER_BLOCKS = ListDeferredRegistry.create(UtilMappings::gameMasterBlocks, RegistryLoaders.UTIL_MAPPINGS_KEYS);
/**
* A registry containing all block entities Java considers "dangerous" - these have a red warning in the item tooltip on Java.
*/
public static final ListDeferredRegistry<Key> DANGEROUS_BLOCK_ENTITIES = ListDeferredRegistry.create(UtilMappings::dangerousBlockEntities, RegistryLoaders.UTIL_MAPPINGS_KEYS);
/**
* A registry containing all entities Java considers "dangerous" - spawn eggs of these entities have a red warning in the item tooltip on Java.
*/
public static final ListDeferredRegistry<Key> DANGEROUS_ENTITIES = ListDeferredRegistry.create(UtilMappings::dangerousEntities, RegistryLoaders.UTIL_MAPPINGS_KEYS);
public static void load() { public static void load() {
if (loaded) return; if (loaded) return;
loaded = true; loaded = true;
@@ -216,6 +233,10 @@ public final class Registries {
SOUNDS.load(); SOUNDS.load();
SOUND_LEVEL_EVENTS.load(); SOUND_LEVEL_EVENTS.load();
SOUND_TRANSLATORS.load(); SOUND_TRANSLATORS.load();
GAME_MASTER_BLOCKS.load();
DANGEROUS_BLOCK_ENTITIES.load();
DANGEROUS_ENTITIES.load();
} }
public static void populate() { public static void populate() {

View File

@@ -25,8 +25,11 @@
package org.geysermc.geyser.registry.loader; package org.geysermc.geyser.registry.loader;
import net.kyori.adventure.key.Key;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.geyser.registry.type.UtilMappings;
import java.util.List;
import java.util.function.Supplier; import java.util.function.Supplier;
/** /**
@@ -48,6 +51,8 @@ public final class RegistryLoaders {
*/ */
public static final ResourcePackLoader RESOURCE_PACKS = new ResourcePackLoader(); public static final ResourcePackLoader RESOURCE_PACKS = new ResourcePackLoader();
public static final UtilMappings.Loader<List<Key>> UTIL_MAPPINGS_KEYS = new UtilMappings.Loader<>();
/** /**
* Wraps the surrounding {@link Supplier} in a {@link RegistryLoader} which does * Wraps the surrounding {@link Supplier} in a {@link RegistryLoader} which does
* not take in any input value. * not take in any input value.

View File

@@ -0,0 +1,90 @@
/*
* Copyright (c) 2025 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.registry.type;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import net.kyori.adventure.key.Key;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.registry.loader.RegistryLoader;
import org.geysermc.geyser.util.MinecraftKey;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
/**
* Used to load and store the {@code mappings/util.json} file. When adding new fields to util mappings, be sure to create a proper registry for them
* in {@link org.geysermc.geyser.registry.Registries}. Use {@link org.geysermc.geyser.registry.loader.RegistryLoaders#UTIL_MAPPINGS_KEYS} (or create a new loader if loading something
* other than keys).
*/
public record UtilMappings(List<Key> gameMasterBlocks, List<Key> dangerousBlockEntities, List<Key> dangerousEntities) {
private static final String INPUT = "mappings/util.json";
private static UtilMappings loaded = null;
/**
* Gets the loaded util mappings, or loads them if they weren't yet.
*/
private static UtilMappings get() {
if (loaded == null) {
try (InputStream utilInput = GeyserImpl.getInstance().getBootstrap().getResourceOrThrow(INPUT)) {
JsonObject utilJson = JsonParser.parseReader(new InputStreamReader(utilInput)).getAsJsonObject();
List<Key> gameMasterBlocks = new ArrayList<>();
List<Key> dangerousBlockEntities = new ArrayList<>();
List<Key> dangerousEntities = new ArrayList<>();
utilJson.get("game_master_blocks").getAsJsonArray()
.forEach(element -> gameMasterBlocks.add(MinecraftKey.key(element.getAsString())));
utilJson.get("dangerous_block_entities").getAsJsonArray()
.forEach(element -> dangerousBlockEntities.add(MinecraftKey.key(element.getAsString())));
utilJson.get("dangerous_entities").getAsJsonArray()
.forEach(element -> dangerousEntities.add(MinecraftKey.key(element.getAsString())));
loaded = new UtilMappings(List.copyOf(gameMasterBlocks), List.copyOf(dangerousBlockEntities), List.copyOf(dangerousEntities));
} catch (IOException e) {
throw new AssertionError("Failed to load " + INPUT);
}
}
return loaded;
}
/**
* Simply gets a field of the loaded {@link UtilMappings} object. Instead of re-opening the util mappings file every time a field is loaded,
* the mappings are parsed once by {@link UtilMappings#get()} and kept in a static variable.
* Loader input is a function that extracts the field to get from the {@link UtilMappings} object.
*/
public static class Loader<T> implements RegistryLoader<Function<UtilMappings, T>, T> {
@Override
public T load(Function<UtilMappings, T> input) {
return input.apply(UtilMappings.get());
}
}
}

View File

@@ -50,6 +50,7 @@ import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.level.physics.Direction; import org.geysermc.geyser.level.physics.Direction;
import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.registry.Registries;
import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.item.CustomItemTranslator; import org.geysermc.geyser.translator.item.CustomItemTranslator;
@@ -76,16 +77,6 @@ import java.util.concurrent.TimeUnit;
*/ */
public class BlockBreakHandler { public class BlockBreakHandler {
private final static Set<Block> GAME_MASTER_BLOCKS = Set.of(
Blocks.COMMAND_BLOCK,
Blocks.CHAIN_COMMAND_BLOCK,
Blocks.REPEATING_COMMAND_BLOCK,
Blocks.JIGSAW,
Blocks.STRUCTURE_BLOCK,
Blocks.TEST_BLOCK,
Blocks.TEST_INSTANCE_BLOCK
);
protected final GeyserSession session; protected final GeyserSession session;
/** /**
@@ -457,7 +448,7 @@ public class BlockBreakHandler {
} }
} }
if (GAME_MASTER_BLOCKS.contains(state.block())) { if (Registries.GAME_MASTER_BLOCKS.get().contains(state.block().javaIdentifier())) {
if (!instabuild || session.getOpPermissionLevel() < 2) { if (!instabuild || session.getOpPermissionLevel() < 2) {
return false; return false;
} }