From 1d005e71f19293be64e8ed0b9e3e03765fcda5a7 Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Tue, 26 May 2026 21:23:25 +0200 Subject: [PATCH 01/10] add: KeyedRegistry --- .../bootstrap/registries/KeyedRegistry.java | 23 +++++++++++++++++++ .../CustomEnchantmentRegistry.java | 16 ++++++------- .../registry/items/CustomItemRegistry.java | 17 +++++--------- .../loottable/CustomLootTableRegistry.java | 14 ++++------- .../core/registry/mobs/CustomMobRegistry.java | 21 +++++++---------- 5 files changed, 50 insertions(+), 41 deletions(-) create mode 100644 src/main/java/fr/openmc/core/bootstrap/registries/KeyedRegistry.java diff --git a/src/main/java/fr/openmc/core/bootstrap/registries/KeyedRegistry.java b/src/main/java/fr/openmc/core/bootstrap/registries/KeyedRegistry.java new file mode 100644 index 000000000..0988b9ad7 --- /dev/null +++ b/src/main/java/fr/openmc/core/bootstrap/registries/KeyedRegistry.java @@ -0,0 +1,23 @@ +package fr.openmc.core.bootstrap.registries; + +public interface KeyedRegistry { + K key(V registryObject); + + void register(K key, V value); + + default void register(V value) { + register(key(value), value); + } + + default void register(V... values) { + for (V value : values) { + register(value); + } + } + + default void register(Iterable values) { + for (V value : values) { + register(value); + } + } +} diff --git a/src/main/java/fr/openmc/core/registry/enchantments/CustomEnchantmentRegistry.java b/src/main/java/fr/openmc/core/registry/enchantments/CustomEnchantmentRegistry.java index 691754efc..fe98ee9b2 100644 --- a/src/main/java/fr/openmc/core/registry/enchantments/CustomEnchantmentRegistry.java +++ b/src/main/java/fr/openmc/core/registry/enchantments/CustomEnchantmentRegistry.java @@ -2,6 +2,7 @@ import fr.openmc.core.OMCPlugin; import fr.openmc.core.OMCRegistry; +import fr.openmc.core.bootstrap.registries.KeyedRegistry; import fr.openmc.core.bootstrap.registries.Registry; import fr.openmc.core.features.dream.registries.enchantements.DreamSleeper; import fr.openmc.core.features.dream.registries.enchantements.Experientastic; @@ -17,11 +18,16 @@ import org.bukkit.inventory.EquipmentSlotGroup; @SuppressWarnings("UnstableApiUsage") -public class CustomEnchantmentRegistry extends Registry { +public class CustomEnchantmentRegistry extends Registry implements KeyedRegistry { + + @Override + public Key key(CustomEnchantment registryObject) { + return registryObject.getKey(); + } @Override public void bootstrap(BootstrapContext context) { - registerAll( + register( new Soulbound(), new Experientastic(), new DreamSleeper() @@ -64,10 +70,4 @@ public void postInit() { } } } - - public void registerAll(CustomEnchantment... enchantments) { - for (CustomEnchantment e : enchantments) { - register(e.getKey(), e); - } - } } \ No newline at end of file diff --git a/src/main/java/fr/openmc/core/registry/items/CustomItemRegistry.java b/src/main/java/fr/openmc/core/registry/items/CustomItemRegistry.java index 7236ba298..a49ffd7dc 100644 --- a/src/main/java/fr/openmc/core/registry/items/CustomItemRegistry.java +++ b/src/main/java/fr/openmc/core/registry/items/CustomItemRegistry.java @@ -2,6 +2,7 @@ import dev.lone.itemsadder.api.CustomStack; import fr.openmc.core.CommandsManager; +import fr.openmc.core.bootstrap.registries.KeyedRegistry; import fr.openmc.core.bootstrap.registries.Registry; import fr.openmc.core.hooks.itemsadder.ItemsAdderHook; import fr.openmc.core.registry.items.contents.AywenCap; @@ -15,11 +16,15 @@ import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.persistence.PersistentDataType; -public class CustomItemRegistry extends Registry { +public class CustomItemRegistry extends Registry implements KeyedRegistry { public static final NamespacedKey CUSTOM_ITEM_KEY = new NamespacedKey("openmc", "custom_item"); + @Override + public String key(CustomItem registryObject) { + return registryObject.getId(); + } @Override public void postInit() { CommandsManager.getHandler().register(new CustomItemsDebugCommand()); @@ -118,10 +123,6 @@ public CustomItem get(ItemStack stack) { } } - public void register(CustomItem item) { - register(item.getId(), item); - } - public void register(String name, ItemStack item) { register(name, new CustomItem(name) { @Override @@ -147,10 +148,4 @@ public ItemStack getVanilla() { } }); } - - public void register(Iterable items) { - for (CustomItem item : items) { - register(item); - } - } } diff --git a/src/main/java/fr/openmc/core/registry/loottable/CustomLootTableRegistry.java b/src/main/java/fr/openmc/core/registry/loottable/CustomLootTableRegistry.java index e79b25177..f966c85cd 100644 --- a/src/main/java/fr/openmc/core/registry/loottable/CustomLootTableRegistry.java +++ b/src/main/java/fr/openmc/core/registry/loottable/CustomLootTableRegistry.java @@ -1,8 +1,9 @@ package fr.openmc.core.registry.loottable; +import fr.openmc.core.bootstrap.registries.KeyedRegistry; import fr.openmc.core.bootstrap.registries.Registry; -public class CustomLootTableRegistry extends Registry { +public class CustomLootTableRegistry extends Registry implements KeyedRegistry { @Override public void postInit() { @@ -10,13 +11,8 @@ public void postInit() { } - public void register(CustomLootTable table) { - register(table.getName(), table); - } - - public void register(CustomLootTable... tables) { - for (CustomLootTable table : tables) { - register(table); - } + @Override + public String key(CustomLootTable registryObject) { + return registryObject.getName(); } } \ No newline at end of file diff --git a/src/main/java/fr/openmc/core/registry/mobs/CustomMobRegistry.java b/src/main/java/fr/openmc/core/registry/mobs/CustomMobRegistry.java index f82fad275..e09ac6c9e 100644 --- a/src/main/java/fr/openmc/core/registry/mobs/CustomMobRegistry.java +++ b/src/main/java/fr/openmc/core/registry/mobs/CustomMobRegistry.java @@ -1,6 +1,7 @@ package fr.openmc.core.registry.mobs; import fr.openmc.core.OMCPlugin; +import fr.openmc.core.bootstrap.registries.KeyedRegistry; import fr.openmc.core.bootstrap.registries.Registry; import org.bukkit.NamespacedKey; import org.bukkit.entity.Entity; @@ -8,7 +9,7 @@ import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.persistence.PersistentDataType; -public class CustomMobRegistry extends Registry { +public class CustomMobRegistry extends Registry implements KeyedRegistry { public static final NamespacedKey CUSTOM_MOB_KEY = new NamespacedKey("openmc", "custom_mob"); @@ -18,6 +19,12 @@ public void postInit() { // ** REGISTER MOBS ** } + @Override + public String key(CustomMobEntry registryObject) { + return registryObject.id(); + } + + @Override public void register(CustomMobEntry mob) { if (mob.factory().apply(mob.id()) instanceof Listener listener) { OMCPlugin.registerEvents(listener); @@ -25,18 +32,6 @@ public void register(CustomMobEntry mob) { register(mob.id(), mob); } - public void register(Iterable mobs) { - for (CustomMobEntry mob : mobs) { - register(mob); - } - } - - public void register(CustomMobEntry... mobs) { - for (CustomMobEntry mob : mobs) { - register(mob); - } - } - public CustomMob getMob(String id) { CustomMobEntry entry = get(id); return entry != null ? entry.factory().apply(id) : null; From ded23d3fa2cc042c29327bbb664204adb7eefdb4 Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Wed, 27 May 2026 18:58:18 +0200 Subject: [PATCH 02/10] add: OMCDatapack and injectors (only dimensions_type and pack.mcmeta, soon timelines and clock) --- .../api/datapacks/DatapackInjector.java | 12 + .../fr/openmc/api/datapacks/OMCDatapack.java | 56 +++++ .../injectors/DimensionTypesInjector.java | 206 ++++++++++++++++++ .../injectors/PackMetadataInjector.java | 36 +++ .../java/fr/openmc/core/OMCBootstrap.java | 4 - src/main/java/fr/openmc/core/OMCRegistry.java | 13 +- .../registries/LifecycleRegistry.java | 4 +- .../core/registry/ambient/CustomAmbient.java | 198 +++++++++++++++++ .../ambient/CustomAmbientRegistry.java | 32 +++ .../ambient/contents/DarkAmbient.java | 18 ++ 10 files changed, 572 insertions(+), 7 deletions(-) create mode 100644 src/main/java/fr/openmc/api/datapacks/DatapackInjector.java create mode 100644 src/main/java/fr/openmc/api/datapacks/OMCDatapack.java create mode 100644 src/main/java/fr/openmc/api/datapacks/injectors/DimensionTypesInjector.java create mode 100644 src/main/java/fr/openmc/api/datapacks/injectors/PackMetadataInjector.java create mode 100644 src/main/java/fr/openmc/core/registry/ambient/CustomAmbient.java create mode 100644 src/main/java/fr/openmc/core/registry/ambient/CustomAmbientRegistry.java create mode 100644 src/main/java/fr/openmc/core/registry/ambient/contents/DarkAmbient.java diff --git a/src/main/java/fr/openmc/api/datapacks/DatapackInjector.java b/src/main/java/fr/openmc/api/datapacks/DatapackInjector.java new file mode 100644 index 000000000..c5fe96d7b --- /dev/null +++ b/src/main/java/fr/openmc/api/datapacks/DatapackInjector.java @@ -0,0 +1,12 @@ +package fr.openmc.api.datapacks; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +import java.io.File; + +public interface DatapackInjector { + Gson GSON = new GsonBuilder().setPrettyPrinting().create(); + + void inject(File rootFile); +} diff --git a/src/main/java/fr/openmc/api/datapacks/OMCDatapack.java b/src/main/java/fr/openmc/api/datapacks/OMCDatapack.java new file mode 100644 index 000000000..996da0ee8 --- /dev/null +++ b/src/main/java/fr/openmc/api/datapacks/OMCDatapack.java @@ -0,0 +1,56 @@ +package fr.openmc.api.datapacks; + +import fr.openmc.api.datapacks.injectors.PackMetadataInjector; +import io.papermc.paper.plugin.bootstrap.BootstrapContext; +import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents; +import lombok.Getter; + +import java.io.IOException; +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.HashSet; +import java.util.Set; + +@Getter +@SuppressWarnings("UnstableApiUsage") +public class OMCDatapack { + private final String packName; + private final String namespace; + private final Set injectors = new HashSet<>(); + + public OMCDatapack(String packName, String namespace) { + this.packName=packName; + this.namespace=namespace; + } + + public void build(BootstrapContext context) throws IOException { + Path tempDir = Files.createTempDirectory("datapacks-openmc"); + + runInjector(tempDir, new PackMetadataInjector()); + + for (DatapackInjector injector : injectors) { + runInjector(tempDir, injector); + } + + context.getLifecycleManager().registerEventHandler(LifecycleEvents.DATAPACK_DISCOVERY.newHandler( + event -> { + try { + URI uri = tempDir.toUri(); + + event.registrar().discoverPack(uri, "openmc-injected"); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + )); + } + + public void addInjector(DatapackInjector injector) { + injectors.add(injector); + } + + private static void runInjector(Path datapackRoot, DatapackInjector injector) { + injector.inject(datapackRoot.toFile()); + } +} diff --git a/src/main/java/fr/openmc/api/datapacks/injectors/DimensionTypesInjector.java b/src/main/java/fr/openmc/api/datapacks/injectors/DimensionTypesInjector.java new file mode 100644 index 000000000..e5f3aa88d --- /dev/null +++ b/src/main/java/fr/openmc/api/datapacks/injectors/DimensionTypesInjector.java @@ -0,0 +1,206 @@ +package fr.openmc.api.datapacks.injectors; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; +import fr.openmc.api.datapacks.DatapackInjector; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.function.Consumer; + +/** + * Classe qui représente les données trouvable dans un dimension type + * Qui injecte directement cela sous forme .json dans le datapack + */ +public class DimensionTypesInjector implements DatapackInjector { + + private final String namespace; + private final Map entries = new LinkedHashMap<>(); + + public DimensionTypesInjector(String namespace) { + this.namespace = namespace; + } + + public DimensionTypesInjector add(String id, Consumer builder) { + DimensionTypeBuilder instance = new DimensionTypeBuilder(); + builder.accept(instance); + entries.put(id, instance); + return this; + } + + public DimensionTypesInjector add(String id, DimensionTypeBuilder builder) { + entries.put(id, builder); + return this; + } + + @Override + public void inject(File rootFile) { + if (entries.isEmpty()) return; + + Path root = rootFile.toPath().resolve("data").resolve(namespace).resolve("dimension_type"); + try { + Files.createDirectories(root); + for (var entry : entries.entrySet()) { + Path dimensionTypeFile = root.resolve(entry.getKey() + ".json"); + Files.writeString(dimensionTypeFile, GSON.toJson(entry.getValue().toJson())); + } + } catch (IOException e) { + throw new IllegalStateException("Cannot write dimension_type files", e); + } + } + + /** + * Exemple simple d'un dimension type : + * { + * "attributes": {}, + * "ambient_light": 0, + * "coordinate_scale": 1, + * "default_clock": "minecraft:overworld", + * "has_ceiling": false, + * "has_ender_dragon_fight": false, + * "has_skylight": true, + * "height": 384, + * "infiniburn": "#minecraft:infiniburn_overworld", + * "logical_height": 384, + * "min_y": -64, + * "monster_spawn_block_light_limit": 0, + * "monster_spawn_light_level": { + * "type": "minecraft:uniform", + * "max_inclusive": 7, + * "min_inclusive": 0 + * }, + * "timelines": "#minecraft:in_overworld" + * } + */ + public static final class DimensionTypeBuilder { + private JsonObject attributes; + private Double ambientLight = 0.0; + private Double coordinateScale = 1.0; + private String defaultClock = "overworld"; + private Boolean hasCeiling = false; + private Boolean hasEnderDragonFlight = false; + private Boolean hasSkylight = true; + private Integer height = 384; + private String infiniburn = "#infiniburn_overworld"; + private Integer logicalHeight = 384; + private Integer minY = -64; + private Integer monsterSpawnBlockLightLimit = 0; + private JsonElement monsterSpawnLightLevel = new JsonPrimitive(0); + private String timelines; + + public DimensionTypeBuilder attributes(Consumer builder) { + JsonObject obj = new JsonObject(); + builder.accept(obj); + this.attributes = obj; + return this; + } + + public DimensionTypeBuilder attributes(JsonObject attributes) { + this.attributes = attributes; + return this; + } + + public DimensionTypeBuilder ambientLight(double ambientLight) { + this.ambientLight = ambientLight; + return this; + } + + public DimensionTypeBuilder coordinateScale(double coordinateScale) { + this.coordinateScale = coordinateScale; + return this; + } + + public DimensionTypeBuilder defaultClock(String keyOfClock) { + this.defaultClock = keyOfClock; + return this; + } + + public DimensionTypeBuilder hasCeiling(boolean hasCeiling) { + this.hasCeiling = hasCeiling; + return this; + } + + public DimensionTypeBuilder hasEnderDragonFlight(boolean hasEnderDragonFlight) { + this.hasEnderDragonFlight = hasEnderDragonFlight; + return this; + } + + public DimensionTypeBuilder hasSkylight(boolean hasSkylight) { + this.hasSkylight = hasSkylight; + return this; + } + + public DimensionTypeBuilder height(int height) { + this.height = height; + return this; + } + + public DimensionTypeBuilder infiniburn(String infiniburn) { + this.infiniburn = infiniburn; + return this; + } + + public DimensionTypeBuilder logicalHeight(int logicalHeight) { + this.logicalHeight = logicalHeight; + return this; + } + + public DimensionTypeBuilder minY(int minY) { + this.minY = minY; + return this; + } + + public DimensionTypeBuilder monsterSpawnBlockLightLimit(int limit) { + this.monsterSpawnBlockLightLimit = limit; + return this; + } + + public DimensionTypeBuilder monsterSpawnLightLevelUniform(int minInclusive, int maxInclusive) { + JsonObject uniform = new JsonObject(); + uniform.addProperty("type", "minecraft:uniform"); + uniform.addProperty("min_inclusive", minInclusive); + uniform.addProperty("max_inclusive", maxInclusive); + this.monsterSpawnLightLevel = uniform; + return this; + } + + public DimensionTypeBuilder monsterSpawnLightLevel(int level) { + this.monsterSpawnLightLevel = new JsonPrimitive(level); + return this; + } + + public DimensionTypeBuilder monsterSpawnLightLevel(JsonElement monsterSpawnLightLevel) { + this.monsterSpawnLightLevel = monsterSpawnLightLevel; + return this; + } + + public DimensionTypeBuilder timelines(String timelines) { + this.timelines = timelines; + return this; + } + + private JsonObject toJson() { + JsonObject json = new JsonObject(); + if (attributes != null) json.add("attributes", attributes); + if (ambientLight != null) json.addProperty("ambient_light", ambientLight); + if (coordinateScale != null) json.addProperty("coordinate_scale", coordinateScale); + if (defaultClock != null) json.addProperty("default_clock", defaultClock); + if (hasCeiling != null) json.addProperty("has_ceiling", hasCeiling); + if (hasEnderDragonFlight != null) json.addProperty("has_ender_dragon_fight", hasEnderDragonFlight); + if (hasSkylight != null) json.addProperty("has_skylight", hasSkylight); + if (height != null) json.addProperty("height", height); + if (infiniburn != null) json.addProperty("infiniburn", infiniburn); + if (logicalHeight != null) json.addProperty("logical_height", logicalHeight); + if (minY != null) json.addProperty("min_y", minY); + if (monsterSpawnBlockLightLimit != null) json.addProperty("monster_spawn_block_light_limit", monsterSpawnBlockLightLimit); + if (monsterSpawnLightLevel != null) json.add("monster_spawn_light_level", monsterSpawnLightLevel); + if (timelines != null) json.addProperty("timelines", timelines); + return json; + } + } +} diff --git a/src/main/java/fr/openmc/api/datapacks/injectors/PackMetadataInjector.java b/src/main/java/fr/openmc/api/datapacks/injectors/PackMetadataInjector.java new file mode 100644 index 000000000..6a832aecc --- /dev/null +++ b/src/main/java/fr/openmc/api/datapacks/injectors/PackMetadataInjector.java @@ -0,0 +1,36 @@ +package fr.openmc.api.datapacks.injectors; + +import fr.openmc.api.datapacks.DatapackInjector; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +public class PackMetadataInjector implements DatapackInjector { + private static final double[] PACK_FORMAT = new double[] {101.1, 1}; + + @Override + public void inject(File rootFile) { + Path root = rootFile.toPath(); + try { + Path metaDataFile = root.resolve("pack.mcmeta"); + Files.writeString(metaDataFile, GSON.toJson(packMcMeta())); + } catch (IOException e) { + throw new IllegalStateException("Cannot write pack mcmeta file", e); + } + } + + private String packMcMeta() { + return String.format(""" + { + "pack": { + "description": "OMC generated datapack", + "pack_format": %s, + "min_format": [%s, %s], + "max_format": [%s, %s] + } + } + """, PACK_FORMAT[0], PACK_FORMAT[0], PACK_FORMAT[1], PACK_FORMAT[0], PACK_FORMAT[1]); + } +} diff --git a/src/main/java/fr/openmc/core/OMCBootstrap.java b/src/main/java/fr/openmc/core/OMCBootstrap.java index c8190388a..6dd3f886a 100644 --- a/src/main/java/fr/openmc/core/OMCBootstrap.java +++ b/src/main/java/fr/openmc/core/OMCBootstrap.java @@ -51,10 +51,6 @@ public void bootstrap(@NotNull BootstrapContext context) { // ** REGISTRY MANAGER ** OMCRegistry.bootstrapAll(context); -// context.getLifecycleManager().registerEventHandler(RegistryEvents.ENCHANTMENT.compose() -// .newHandler(CustomEnchantmentRegistry::loadEnchantmentInBootstrap) -// ); - // ** LOAD TRANSLATION ** // this creates resource pack who is needed for item adder TranslationManager.init( diff --git a/src/main/java/fr/openmc/core/OMCRegistry.java b/src/main/java/fr/openmc/core/OMCRegistry.java index 6569bebc7..b75e6f221 100644 --- a/src/main/java/fr/openmc/core/OMCRegistry.java +++ b/src/main/java/fr/openmc/core/OMCRegistry.java @@ -2,12 +2,14 @@ import fr.openmc.core.bootstrap.integration.OMCLogger; import fr.openmc.core.bootstrap.registries.LifecycleRegistry; +import fr.openmc.core.registry.ambient.CustomAmbientRegistry; import fr.openmc.core.registry.enchantments.CustomEnchantmentRegistry; import fr.openmc.core.registry.items.CustomItemRegistry; import fr.openmc.core.registry.loottable.CustomLootTableRegistry; import fr.openmc.core.registry.mobs.CustomMobRegistry; import io.papermc.paper.plugin.bootstrap.BootstrapContext; +import java.io.IOException; import java.util.List; @SuppressWarnings("UnstableApiUsage") @@ -17,12 +19,14 @@ public final class OMCRegistry { public static final CustomMobRegistry CUSTOM_MOBS = new CustomMobRegistry(); public static final CustomEnchantmentRegistry CUSTOM_ENCHANTS = new CustomEnchantmentRegistry(); public static final CustomLootTableRegistry CUSTOM_LOOT_TABLES = new CustomLootTableRegistry(); + public static final CustomAmbientRegistry CUSTOM_AMBIENT = new CustomAmbientRegistry(); private static final List ALL = List.of( CUSTOM_ITEMS, CUSTOM_MOBS, CUSTOM_ENCHANTS, - CUSTOM_LOOT_TABLES + CUSTOM_LOOT_TABLES, + CUSTOM_AMBIENT ); private OMCRegistry() {} @@ -30,7 +34,12 @@ private OMCRegistry() {} public static void bootstrapAll(BootstrapContext context) { for (LifecycleRegistry r : OMCRegistry.ALL) { if (isOverridden(r, "bootstrap", BootstrapContext.class)) { - r.bootstrap(context); + try { + r.bootstrap(context); + } catch (IOException e) { + OMCLogger.errorFormatted("Erreur lors du chargement du registre '{}' lors du bootstrap", r.getClass().getSimpleName()); + OMCLogger.error(e.getMessage()); + } OMCLogger.successFormatted("Registre {} chargé pendant le bootstrap", r.getClass().getSimpleName()); } } diff --git a/src/main/java/fr/openmc/core/bootstrap/registries/LifecycleRegistry.java b/src/main/java/fr/openmc/core/bootstrap/registries/LifecycleRegistry.java index 51990346f..541e7a503 100644 --- a/src/main/java/fr/openmc/core/bootstrap/registries/LifecycleRegistry.java +++ b/src/main/java/fr/openmc/core/bootstrap/registries/LifecycleRegistry.java @@ -2,9 +2,11 @@ import io.papermc.paper.plugin.bootstrap.BootstrapContext; +import java.io.IOException; + @SuppressWarnings("UnstableApiUsage") public interface LifecycleRegistry { - default void bootstrap(BootstrapContext context) {} + default void bootstrap(BootstrapContext context) throws IOException {} default void init() {} diff --git a/src/main/java/fr/openmc/core/registry/ambient/CustomAmbient.java b/src/main/java/fr/openmc/core/registry/ambient/CustomAmbient.java new file mode 100644 index 000000000..dbace4760 --- /dev/null +++ b/src/main/java/fr/openmc/core/registry/ambient/CustomAmbient.java @@ -0,0 +1,198 @@ +package fr.openmc.core.registry.ambient; + +import com.comphenix.protocol.PacketType; +import com.comphenix.protocol.ProtocolLibrary; +import com.comphenix.protocol.events.PacketContainer; +import fr.openmc.api.datapacks.DatapackInjector; +import fr.openmc.api.datapacks.injectors.DimensionTypesInjector; +import fr.openmc.core.OMCPlugin; +import net.minecraft.core.Holder; +import net.minecraft.core.Registry; +import net.minecraft.core.registries.Registries; +import net.minecraft.network.protocol.game.*; +import net.minecraft.resources.Identifier; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.players.PlayerList; +import net.minecraft.world.entity.PositionMoveRotation; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.dimension.DimensionType; +import net.minecraft.world.level.storage.LevelData; +import net.minecraft.world.phys.Vec3; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitRunnable; + +public abstract class CustomAmbient { + public abstract String getId(); + public abstract DimensionTypesInjector.DimensionTypeBuilder getDimensionType(); + + public DatapackInjector toDimensionTypeInjector() { + return new DimensionTypesInjector("omc_ambient").add(getId(), getDimensionType()); + } + public void apply(Player player) { + ServerPlayer nmsPlayer = ((CraftPlayer) player).getHandle(); + ServerLevel nmsWorld = nmsPlayer.level(); + + forceClientRespawnReload(nmsPlayer, getCommonPlayerSpawnInfo(nmsPlayer)); + sendPostRespawnPackets(player, nmsPlayer, nmsWorld); + resyncEntitiesAfterDimensionRefresh(player); + } + + public void reset(Player player) { + sendRealDimension(player); + } + + private CommonPlayerSpawnInfo getCommonPlayerSpawnInfo(ServerPlayer nmsPlayer) { + ServerLevel nmsWorld = (ServerLevel) nmsPlayer.level(); + CommonPlayerSpawnInfo spawnInfo = nmsPlayer.createCommonSpawnInfo(nmsPlayer.level()); + + ResourceKey key = ResourceKey.create( + Registries.DIMENSION_TYPE, + Identifier.fromNamespaceAndPath("openmc", "test") + ); + + Registry dimRegistry = + nmsWorld.registryAccess().lookupOrThrow(Registries.DIMENSION_TYPE); + + Holder dimensionTypeHolder = dimRegistry.get(key).orElseThrow(() -> + new IllegalStateException("DimensionType openmc:test introuvable") + ); + + return new CommonPlayerSpawnInfo( + dimensionTypeHolder, + spawnInfo.dimension(), + spawnInfo.seed(), + spawnInfo.gameType(), + spawnInfo.previousGameType(), + spawnInfo.isDebug(), + spawnInfo.isFlat(), + spawnInfo.lastDeathLocation(), + spawnInfo.portalCooldown(), + spawnInfo.seaLevel() + ); + } + + private CommonPlayerSpawnInfo withDimension(CommonPlayerSpawnInfo base, ResourceKey dimensionKey) { + return new CommonPlayerSpawnInfo( + base.dimensionType(), + dimensionKey, + base.seed(), + base.gameType(), + base.previousGameType(), + base.isDebug(), + base.isFlat(), + base.lastDeathLocation(), + base.portalCooldown(), + base.seaLevel() + ); + } + + private static void sendRespawnPacket(ServerPlayer nmsPlayer, CommonPlayerSpawnInfo spawnInfo) { + nmsPlayer.connection.send(new ClientboundRespawnPacket( + spawnInfo, + ClientboundRespawnPacket.KEEP_ALL_DATA + )); + } + + /** + * Procédure qu'a paper durant une teleportation entre 2 dimensions + */ + private void sendPostRespawnPackets(Player player, ServerPlayer nmsPlayer, ServerLevel nmsWorld) { + LevelData levelData = nmsWorld.getLevelData(); + PlayerList playerList = ((CraftServer) Bukkit.getServer()).getServer().getPlayerList(); + + nmsPlayer.connection.send(new ClientboundChangeDifficultyPacket( + levelData.getDifficulty(), levelData.isDifficultyLocked() + )); + playerList.sendPlayerPermissionLevel(nmsPlayer); + nmsPlayer.connection.send(new ClientboundPlayerAbilitiesPacket(nmsPlayer.getAbilities())); + playerList.sendLevelInfo(nmsPlayer, nmsWorld); + playerList.sendAllPlayerInfo(nmsPlayer); + playerList.sendActivePlayerEffects(nmsPlayer); + sendPos(player, player.getLocation()); + + nmsPlayer.connection.send(new ClientboundSetChunkCacheCenterPacket( + nmsPlayer.chunkPosition().x(), + nmsPlayer.chunkPosition().z() + )); + int viewDistance = nmsWorld.getServer().getPlayerList().getViewDistance(); + net.minecraft.world.level.ChunkPos center = nmsPlayer.chunkPosition(); + + for (int cx = center.x() - viewDistance; cx <= center.x() + viewDistance; cx++) { + for (int cz = center.z() - viewDistance; cz <= center.z() + viewDistance; cz++) { + LevelChunk chunk = nmsWorld.getChunkIfLoaded(cx, cz); + if (chunk != null) { + nmsPlayer.connection.send( + new ClientboundLevelChunkWithLightPacket(chunk, nmsWorld.getLightEngine(), null, null, false) + ); + } + } + } + } + + private ResourceKey getPivotDimension(ResourceKey currentDimension) { + return currentDimension.equals(Level.OVERWORLD) ? Level.END : Level.OVERWORLD; + } + + private void forceClientRespawnReload(ServerPlayer nmsPlayer, CommonPlayerSpawnInfo targetSpawnInfo) { + CommonPlayerSpawnInfo currentSpawnInfo = nmsPlayer.createCommonSpawnInfo(nmsPlayer.level()); + ResourceKey pivotDimension = getPivotDimension(currentSpawnInfo.dimension()); + + // changement de dimension car sinon l'ambience de la dimension n'est pas affiché + sendRespawnPacket(nmsPlayer, withDimension(currentSpawnInfo, pivotDimension)); + sendRespawnPacket(nmsPlayer, targetSpawnInfo); + } + + private void resyncEntitiesAfterDimensionRefresh(Player player) { + new BukkitRunnable() { + @Override + public void run() { + if (!player.isOnline()) { + return; + } + + double range = 96.0D; + for (Entity entity : player.getNearbyEntities(range, range, range)) { + if (entity.equals(player)) { + continue; + } + player.hideEntity(OMCPlugin.getInstance(), entity); + player.showEntity(OMCPlugin.getInstance(), entity); + } + } + }.runTaskLater(OMCPlugin.getInstance(), 2L); + } + + public void sendPos(Player player, Location location) { + PacketContainer positionPacket = new PacketContainer(PacketType.Play.Server.POSITION); + Vec3 position = new Vec3(location.getX(), location.getY(), location.getZ()); + PositionMoveRotation positionMoveRotation = new PositionMoveRotation(position, Vec3.ZERO, + location.getYaw(), location.getPitch()); + + positionPacket.getStructures() + .withType(PositionMoveRotation.class) + .write(0, positionMoveRotation); + + try { + ProtocolLibrary.getProtocolManager().sendServerPacket(player, positionPacket); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private void sendRealDimension(Player player) { + ServerPlayer nmsPlayer = ((CraftPlayer) player).getHandle(); + ServerLevel nmsWorld = (ServerLevel) nmsPlayer.level(); + + forceClientRespawnReload(nmsPlayer, nmsPlayer.createCommonSpawnInfo(nmsPlayer.level())); + sendPostRespawnPackets(player, nmsPlayer, nmsWorld); + resyncEntitiesAfterDimensionRefresh(player); + } +} diff --git a/src/main/java/fr/openmc/core/registry/ambient/CustomAmbientRegistry.java b/src/main/java/fr/openmc/core/registry/ambient/CustomAmbientRegistry.java new file mode 100644 index 000000000..748a38773 --- /dev/null +++ b/src/main/java/fr/openmc/core/registry/ambient/CustomAmbientRegistry.java @@ -0,0 +1,32 @@ +package fr.openmc.core.registry.ambient; + +import fr.openmc.api.datapacks.OMCDatapack; +import fr.openmc.core.bootstrap.registries.KeyedRegistry; +import fr.openmc.core.bootstrap.registries.Registry; +import fr.openmc.core.registry.ambient.contents.DarkAmbient; +import io.papermc.paper.plugin.bootstrap.BootstrapContext; + +import java.io.IOException; + +@SuppressWarnings("UnstableApiUsage") +public class CustomAmbientRegistry extends Registry implements KeyedRegistry { + private final OMCDatapack ambientDatapack = new OMCDatapack("openmc", "omc_ambient"); + + @Override + public String key(CustomAmbient registryObject) { + return registryObject.getId(); + } + + @Override + public void bootstrap(BootstrapContext context) throws IOException { + register( + new DarkAmbient() + ); + + for (CustomAmbient ambient : values()) { + ambientDatapack.addInjector(ambient.toDimensionTypeInjector()); + } + + ambientDatapack.build(context); + } +} diff --git a/src/main/java/fr/openmc/core/registry/ambient/contents/DarkAmbient.java b/src/main/java/fr/openmc/core/registry/ambient/contents/DarkAmbient.java new file mode 100644 index 000000000..1f21918d2 --- /dev/null +++ b/src/main/java/fr/openmc/core/registry/ambient/contents/DarkAmbient.java @@ -0,0 +1,18 @@ +package fr.openmc.core.registry.ambient.contents; + +import fr.openmc.api.datapacks.injectors.DimensionTypesInjector; +import fr.openmc.core.registry.ambient.CustomAmbient; + +public class DarkAmbient extends CustomAmbient { + @Override + public String getId() { + return "dark_ambient"; + } + + @Override + public DimensionTypesInjector.DimensionTypeBuilder getDimensionType() { + return new DimensionTypesInjector.DimensionTypeBuilder() + .hasCeiling(true) + .hasSkylight(true); + } +} From 4dc0a4728346efc0ee52832d978820d9fe6b8fc0 Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Thu, 28 May 2026 21:15:36 +0200 Subject: [PATCH 03/10] fixes datapack injector mcmeta + part 1/2 of restructuration --- .../injectors/PackMetadataInjector.java | 4 +- .../java/fr/openmc/core/CommandsManager.java | 4 +- src/main/java/fr/openmc/core/OMCRegistry.java | 4 +- .../core/registry/ambient/CustomAmbient.java | 165 +++--------------- .../commands/CustomAmbientCommands.java | 51 ++++++ .../CustomAmbientAutoComplete.java | 21 +++ .../core/utils/nms/PlayerPositionNMS.java | 33 ++++ .../core/utils/nms/PlayerRespawnNMS.java | 121 +++++++++++++ .../translations/default/commands.properties | 4 + 9 files changed, 259 insertions(+), 148 deletions(-) create mode 100644 src/main/java/fr/openmc/core/registry/ambient/commands/CustomAmbientCommands.java create mode 100644 src/main/java/fr/openmc/core/registry/ambient/commands/autocomplete/CustomAmbientAutoComplete.java create mode 100644 src/main/java/fr/openmc/core/utils/nms/PlayerPositionNMS.java create mode 100644 src/main/java/fr/openmc/core/utils/nms/PlayerRespawnNMS.java diff --git a/src/main/java/fr/openmc/api/datapacks/injectors/PackMetadataInjector.java b/src/main/java/fr/openmc/api/datapacks/injectors/PackMetadataInjector.java index 6a832aecc..ee06d15b2 100644 --- a/src/main/java/fr/openmc/api/datapacks/injectors/PackMetadataInjector.java +++ b/src/main/java/fr/openmc/api/datapacks/injectors/PackMetadataInjector.java @@ -15,7 +15,7 @@ public void inject(File rootFile) { Path root = rootFile.toPath(); try { Path metaDataFile = root.resolve("pack.mcmeta"); - Files.writeString(metaDataFile, GSON.toJson(packMcMeta())); + Files.writeString(metaDataFile, packMcMeta()); } catch (IOException e) { throw new IllegalStateException("Cannot write pack mcmeta file", e); } @@ -25,7 +25,7 @@ private String packMcMeta() { return String.format(""" { "pack": { - "description": "OMC generated datapack", + "description": "OMC datapack injected from plugin", "pack_format": %s, "min_format": [%s, %s], "max_format": [%s, %s] diff --git a/src/main/java/fr/openmc/core/CommandsManager.java b/src/main/java/fr/openmc/core/CommandsManager.java index 132065593..3b4766487 100644 --- a/src/main/java/fr/openmc/core/CommandsManager.java +++ b/src/main/java/fr/openmc/core/CommandsManager.java @@ -9,6 +9,7 @@ import fr.openmc.core.commands.utils.Restart; import fr.openmc.core.commands.utils.Socials; import fr.openmc.core.features.credits.CreditsCommand; +import fr.openmc.core.registry.ambient.commands.CustomAmbientCommands; import lombok.Getter; import revxrsal.commands.Lamp; import revxrsal.commands.bukkit.BukkitLamp; @@ -44,7 +45,8 @@ private static void registerCommands() { new ChronometerCommand(), new Restart(), new CreditsCommand(), - new CustomItemCommand() + new CustomItemCommand(), + new CustomAmbientCommands() ); } } diff --git a/src/main/java/fr/openmc/core/OMCRegistry.java b/src/main/java/fr/openmc/core/OMCRegistry.java index b75e6f221..5d29c6e7d 100644 --- a/src/main/java/fr/openmc/core/OMCRegistry.java +++ b/src/main/java/fr/openmc/core/OMCRegistry.java @@ -19,14 +19,14 @@ public final class OMCRegistry { public static final CustomMobRegistry CUSTOM_MOBS = new CustomMobRegistry(); public static final CustomEnchantmentRegistry CUSTOM_ENCHANTS = new CustomEnchantmentRegistry(); public static final CustomLootTableRegistry CUSTOM_LOOT_TABLES = new CustomLootTableRegistry(); - public static final CustomAmbientRegistry CUSTOM_AMBIENT = new CustomAmbientRegistry(); + public static final CustomAmbientRegistry CUSTOM_AMBIENTS = new CustomAmbientRegistry(); private static final List ALL = List.of( CUSTOM_ITEMS, CUSTOM_MOBS, CUSTOM_ENCHANTS, CUSTOM_LOOT_TABLES, - CUSTOM_AMBIENT + CUSTOM_AMBIENTS ); private OMCRegistry() {} diff --git a/src/main/java/fr/openmc/core/registry/ambient/CustomAmbient.java b/src/main/java/fr/openmc/core/registry/ambient/CustomAmbient.java index dbace4760..c1a7ed4cf 100644 --- a/src/main/java/fr/openmc/core/registry/ambient/CustomAmbient.java +++ b/src/main/java/fr/openmc/core/registry/ambient/CustomAmbient.java @@ -1,33 +1,19 @@ package fr.openmc.core.registry.ambient; -import com.comphenix.protocol.PacketType; -import com.comphenix.protocol.ProtocolLibrary; -import com.comphenix.protocol.events.PacketContainer; import fr.openmc.api.datapacks.DatapackInjector; import fr.openmc.api.datapacks.injectors.DimensionTypesInjector; -import fr.openmc.core.OMCPlugin; +import fr.openmc.core.utils.nms.PlayerRespawnNMS; import net.minecraft.core.Holder; import net.minecraft.core.Registry; import net.minecraft.core.registries.Registries; -import net.minecraft.network.protocol.game.*; +import net.minecraft.network.protocol.game.CommonPlayerSpawnInfo; import net.minecraft.resources.Identifier; import net.minecraft.resources.ResourceKey; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; -import net.minecraft.server.players.PlayerList; -import net.minecraft.world.entity.PositionMoveRotation; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.dimension.DimensionType; -import net.minecraft.world.level.storage.LevelData; -import net.minecraft.world.phys.Vec3; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.craftbukkit.CraftServer; import org.bukkit.craftbukkit.entity.CraftPlayer; -import org.bukkit.entity.Entity; import org.bukkit.entity.Player; -import org.bukkit.scheduler.BukkitRunnable; public abstract class CustomAmbient { public abstract String getId(); @@ -36,33 +22,43 @@ public abstract class CustomAmbient { public DatapackInjector toDimensionTypeInjector() { return new DimensionTypesInjector("omc_ambient").add(getId(), getDimensionType()); } + + /** + * Applique l'ambience sur un Joueur + * @param player Le joueur concerné + */ public void apply(Player player) { ServerPlayer nmsPlayer = ((CraftPlayer) player).getHandle(); - ServerLevel nmsWorld = nmsPlayer.level(); - forceClientRespawnReload(nmsPlayer, getCommonPlayerSpawnInfo(nmsPlayer)); - sendPostRespawnPackets(player, nmsPlayer, nmsWorld); - resyncEntitiesAfterDimensionRefresh(player); + // * On envoie le packet respawn qui applique l'ambience + PlayerRespawnNMS.sendRespawnPackets(nmsPlayer, getPlayerAmbientSpawnInfo(nmsPlayer)); } - public void reset(Player player) { - sendRealDimension(player); + /** + * Retire l'ambience du Joueur + * @param player le joueur ciblé + */ + public static void reset(Player player) { + ServerPlayer nmsPlayer = ((CraftPlayer) player).getHandle(); + + // * On envoie le packet respawn qui remets tout a la normale + PlayerRespawnNMS.sendRespawnPackets(nmsPlayer, nmsPlayer.createCommonSpawnInfo(nmsPlayer.level())); } - private CommonPlayerSpawnInfo getCommonPlayerSpawnInfo(ServerPlayer nmsPlayer) { - ServerLevel nmsWorld = (ServerLevel) nmsPlayer.level(); + private CommonPlayerSpawnInfo getPlayerAmbientSpawnInfo(ServerPlayer nmsPlayer) { + ServerLevel nmsWorld = nmsPlayer.level(); CommonPlayerSpawnInfo spawnInfo = nmsPlayer.createCommonSpawnInfo(nmsPlayer.level()); ResourceKey key = ResourceKey.create( Registries.DIMENSION_TYPE, - Identifier.fromNamespaceAndPath("openmc", "test") + Identifier.fromNamespaceAndPath("omc_ambient", this.getId()) ); Registry dimRegistry = nmsWorld.registryAccess().lookupOrThrow(Registries.DIMENSION_TYPE); Holder dimensionTypeHolder = dimRegistry.get(key).orElseThrow(() -> - new IllegalStateException("DimensionType openmc:test introuvable") + new IllegalStateException("DimensionType omc_ambient:"+ this.getId() +" introuvable") ); return new CommonPlayerSpawnInfo( @@ -78,121 +74,4 @@ private CommonPlayerSpawnInfo getCommonPlayerSpawnInfo(ServerPlayer nmsPlayer) { spawnInfo.seaLevel() ); } - - private CommonPlayerSpawnInfo withDimension(CommonPlayerSpawnInfo base, ResourceKey dimensionKey) { - return new CommonPlayerSpawnInfo( - base.dimensionType(), - dimensionKey, - base.seed(), - base.gameType(), - base.previousGameType(), - base.isDebug(), - base.isFlat(), - base.lastDeathLocation(), - base.portalCooldown(), - base.seaLevel() - ); - } - - private static void sendRespawnPacket(ServerPlayer nmsPlayer, CommonPlayerSpawnInfo spawnInfo) { - nmsPlayer.connection.send(new ClientboundRespawnPacket( - spawnInfo, - ClientboundRespawnPacket.KEEP_ALL_DATA - )); - } - - /** - * Procédure qu'a paper durant une teleportation entre 2 dimensions - */ - private void sendPostRespawnPackets(Player player, ServerPlayer nmsPlayer, ServerLevel nmsWorld) { - LevelData levelData = nmsWorld.getLevelData(); - PlayerList playerList = ((CraftServer) Bukkit.getServer()).getServer().getPlayerList(); - - nmsPlayer.connection.send(new ClientboundChangeDifficultyPacket( - levelData.getDifficulty(), levelData.isDifficultyLocked() - )); - playerList.sendPlayerPermissionLevel(nmsPlayer); - nmsPlayer.connection.send(new ClientboundPlayerAbilitiesPacket(nmsPlayer.getAbilities())); - playerList.sendLevelInfo(nmsPlayer, nmsWorld); - playerList.sendAllPlayerInfo(nmsPlayer); - playerList.sendActivePlayerEffects(nmsPlayer); - sendPos(player, player.getLocation()); - - nmsPlayer.connection.send(new ClientboundSetChunkCacheCenterPacket( - nmsPlayer.chunkPosition().x(), - nmsPlayer.chunkPosition().z() - )); - int viewDistance = nmsWorld.getServer().getPlayerList().getViewDistance(); - net.minecraft.world.level.ChunkPos center = nmsPlayer.chunkPosition(); - - for (int cx = center.x() - viewDistance; cx <= center.x() + viewDistance; cx++) { - for (int cz = center.z() - viewDistance; cz <= center.z() + viewDistance; cz++) { - LevelChunk chunk = nmsWorld.getChunkIfLoaded(cx, cz); - if (chunk != null) { - nmsPlayer.connection.send( - new ClientboundLevelChunkWithLightPacket(chunk, nmsWorld.getLightEngine(), null, null, false) - ); - } - } - } - } - - private ResourceKey getPivotDimension(ResourceKey currentDimension) { - return currentDimension.equals(Level.OVERWORLD) ? Level.END : Level.OVERWORLD; - } - - private void forceClientRespawnReload(ServerPlayer nmsPlayer, CommonPlayerSpawnInfo targetSpawnInfo) { - CommonPlayerSpawnInfo currentSpawnInfo = nmsPlayer.createCommonSpawnInfo(nmsPlayer.level()); - ResourceKey pivotDimension = getPivotDimension(currentSpawnInfo.dimension()); - - // changement de dimension car sinon l'ambience de la dimension n'est pas affiché - sendRespawnPacket(nmsPlayer, withDimension(currentSpawnInfo, pivotDimension)); - sendRespawnPacket(nmsPlayer, targetSpawnInfo); - } - - private void resyncEntitiesAfterDimensionRefresh(Player player) { - new BukkitRunnable() { - @Override - public void run() { - if (!player.isOnline()) { - return; - } - - double range = 96.0D; - for (Entity entity : player.getNearbyEntities(range, range, range)) { - if (entity.equals(player)) { - continue; - } - player.hideEntity(OMCPlugin.getInstance(), entity); - player.showEntity(OMCPlugin.getInstance(), entity); - } - } - }.runTaskLater(OMCPlugin.getInstance(), 2L); - } - - public void sendPos(Player player, Location location) { - PacketContainer positionPacket = new PacketContainer(PacketType.Play.Server.POSITION); - Vec3 position = new Vec3(location.getX(), location.getY(), location.getZ()); - PositionMoveRotation positionMoveRotation = new PositionMoveRotation(position, Vec3.ZERO, - location.getYaw(), location.getPitch()); - - positionPacket.getStructures() - .withType(PositionMoveRotation.class) - .write(0, positionMoveRotation); - - try { - ProtocolLibrary.getProtocolManager().sendServerPacket(player, positionPacket); - } catch (Exception e) { - e.printStackTrace(); - } - } - - private void sendRealDimension(Player player) { - ServerPlayer nmsPlayer = ((CraftPlayer) player).getHandle(); - ServerLevel nmsWorld = (ServerLevel) nmsPlayer.level(); - - forceClientRespawnReload(nmsPlayer, nmsPlayer.createCommonSpawnInfo(nmsPlayer.level())); - sendPostRespawnPackets(player, nmsPlayer, nmsWorld); - resyncEntitiesAfterDimensionRefresh(player); - } } diff --git a/src/main/java/fr/openmc/core/registry/ambient/commands/CustomAmbientCommands.java b/src/main/java/fr/openmc/core/registry/ambient/commands/CustomAmbientCommands.java new file mode 100644 index 000000000..8ee843dae --- /dev/null +++ b/src/main/java/fr/openmc/core/registry/ambient/commands/CustomAmbientCommands.java @@ -0,0 +1,51 @@ +package fr.openmc.core.registry.ambient.commands; + +import fr.openmc.core.OMCRegistry; +import fr.openmc.core.registry.ambient.CustomAmbient; +import fr.openmc.core.registry.ambient.commands.autocomplete.CustomAmbientAutoComplete; +import fr.openmc.core.utils.text.messages.MessageType; +import fr.openmc.core.utils.text.messages.MessagesManager; +import fr.openmc.core.utils.text.messages.Prefix; +import fr.openmc.core.utils.text.messages.TranslationManager; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.entity.Player; +import revxrsal.commands.annotation.Command; +import revxrsal.commands.annotation.Subcommand; +import revxrsal.commands.annotation.SuggestWith; +import revxrsal.commands.bukkit.annotation.CommandPermission; + +@Command({"ambient", "customambient"}) +@CommandPermission("omc.admins.commands.customambient") +public class CustomAmbientCommands { + @Subcommand("apply") + public void applyAmbient( + Player player, + Player toPlayer, + @SuggestWith(CustomAmbientAutoComplete.class) String id + ) { + CustomAmbient ambient = OMCRegistry.CUSTOM_AMBIENTS.get(id); + + if (ambient == null) { + MessagesManager.sendMessage(player, TranslationManager.translation("command.registry.custom_ambient.apply.null"), Prefix.STAFF, MessageType.ERROR, true); + return; + } + + ambient.apply(toPlayer); + MessagesManager.sendMessage(player, TranslationManager.translation("command.registry.custom_ambient.apply.success", + Component.text(id).color(NamedTextColor.YELLOW), + Component.text(toPlayer.getName()).color(NamedTextColor.YELLOW) + ), Prefix.STAFF, MessageType.ERROR, true); + } + + @Subcommand("reset") + public void resetAmbient( + Player player, + Player toPlayer + ) { + CustomAmbient.reset(toPlayer); + MessagesManager.sendMessage(player, TranslationManager.translation("command.registry.custom_ambient.reset.success", + Component.text(toPlayer.getName()).color(NamedTextColor.YELLOW) + ), Prefix.STAFF, MessageType.ERROR, true); + } +} diff --git a/src/main/java/fr/openmc/core/registry/ambient/commands/autocomplete/CustomAmbientAutoComplete.java b/src/main/java/fr/openmc/core/registry/ambient/commands/autocomplete/CustomAmbientAutoComplete.java new file mode 100644 index 000000000..e20a0b047 --- /dev/null +++ b/src/main/java/fr/openmc/core/registry/ambient/commands/autocomplete/CustomAmbientAutoComplete.java @@ -0,0 +1,21 @@ +package fr.openmc.core.registry.ambient.commands.autocomplete; + +import fr.openmc.core.OMCRegistry; +import fr.openmc.core.registry.ambient.CustomAmbient; +import org.jetbrains.annotations.NotNull; +import revxrsal.commands.autocomplete.SuggestionProvider; +import revxrsal.commands.bukkit.actor.BukkitCommandActor; +import revxrsal.commands.node.ExecutionContext; + +import java.util.List; + +public class CustomAmbientAutoComplete implements SuggestionProvider { + + @Override + public @NotNull List getSuggestions(@NotNull ExecutionContext context) { + return OMCRegistry.CUSTOM_AMBIENTS.values() + .stream() + .map(CustomAmbient::getId) + .toList(); + } +} \ No newline at end of file diff --git a/src/main/java/fr/openmc/core/utils/nms/PlayerPositionNMS.java b/src/main/java/fr/openmc/core/utils/nms/PlayerPositionNMS.java new file mode 100644 index 000000000..321e223e2 --- /dev/null +++ b/src/main/java/fr/openmc/core/utils/nms/PlayerPositionNMS.java @@ -0,0 +1,33 @@ +package fr.openmc.core.utils.nms; + +import net.minecraft.network.protocol.game.ClientboundPlayerPositionPacket; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.PositionMoveRotation; +import net.minecraft.world.phys.Vec3; +import org.bukkit.Location; +import org.bukkit.entity.Player; + +import java.util.Set; + +/** + * Classe receuillant les NMS lié au packet {@link ClientboundPlayerPositionPacket} + * Afin de simplifier l'utilisation des NMS + */ +public class PlayerPositionNMS { + public static void sendPos(ServerPlayer nmsPlayer, Vec3 location) { + PositionMoveRotation positionMoveRotation = new PositionMoveRotation( + location, + Vec3.ZERO, + nmsPlayer.getYRot(), + nmsPlayer.getXRot() + ); + + // je prefere utiliser la méthode au lieu de {@link ClientboundPlayerPositionPacket} + // car elle néccéssité un ID, qui je suppose ne doit pas etre dupli + nmsPlayer.connection.teleport(positionMoveRotation, Set.of()); + } + + public static void sendPos(Player player, Location location) { + sendPos((ServerPlayer) player, new Vec3(location.getX(), location.getY(), location.getZ())); + } +} diff --git a/src/main/java/fr/openmc/core/utils/nms/PlayerRespawnNMS.java b/src/main/java/fr/openmc/core/utils/nms/PlayerRespawnNMS.java new file mode 100644 index 000000000..25fff7982 --- /dev/null +++ b/src/main/java/fr/openmc/core/utils/nms/PlayerRespawnNMS.java @@ -0,0 +1,121 @@ +package fr.openmc.core.utils.nms; + +import fr.openmc.core.registry.ambient.CustomAmbient; +import net.minecraft.network.protocol.game.*; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.players.PlayerList; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.storage.LevelData; +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.CraftServer; + +/** + * Classe receuillant les NMS lié au packet {@link ClientboundRespawnPacket} + * Afin de simplifier l'utilisation des NMS + * + * @see CustomAmbient utilisation trés spécifique, on affiche une dimension_type sur le joueur, ds la dimension actuelle + */ +public class PlayerRespawnNMS { + // todo: continue this + public static void sendRespawnPacket(ServerPlayer nmsPlayer, CommonPlayerSpawnInfo spawnInfo) { + nmsPlayer.connection.send(new ClientboundRespawnPacket( + spawnInfo, + ClientboundRespawnPacket.KEEP_ALL_DATA + )); + + + // ** Procédure afin que le packet respawn soit valide + PlayerRespawnNMS.sendPostRespawnPackets(nmsPlayer); +// resyncEntitiesAfterDimensionRefresh(player); + } + +// private void resyncEntitiesAfterDimensionRefresh(Player player) { +// new BukkitRunnable() { +// @Override +// public void run() { +// if (!player.isOnline()) return; +// +// double range = 96.0D; +// for (Entity entity : player.getNearbyEntities(range, range, range)) { +// if (entity.equals(player)) continue; +// +// player.hideEntity(OMCPlugin.getInstance(), entity); +// player.showEntity(OMCPlugin.getInstance(), entity); +// } +// } +// }.runTaskLater(OMCPlugin.getInstance(), 2L); +// } + + public static void sendRespawnPackets(ServerPlayer nmsPlayer, CommonPlayerSpawnInfo targetSpawnInfo) { + CommonPlayerSpawnInfo currentSpawnInfo = nmsPlayer.createCommonSpawnInfo(nmsPlayer.level()); + ResourceKey pivotDimension = getPivotDimension(currentSpawnInfo.dimension()); + + // changement de dimension car sinon l'ambience de la dimension n'est pas affiché + sendRespawnPacket(nmsPlayer, getDimensionPlayerSpawnInfo(currentSpawnInfo, pivotDimension)); + sendRespawnPacket(nmsPlayer, targetSpawnInfo); + } + /** + * Procédure basée sur {@link ServerPlayer#teleport} afin de corriger que le packet RESPAWN invalide + * @param nmsPlayer le joueur (NMS) + */ + private static void sendPostRespawnPackets(ServerPlayer nmsPlayer) { + ServerLevel nmsWorld = nmsPlayer.level(); + LevelData levelData = nmsWorld.getLevelData(); + + PlayerList playerList = ((CraftServer) Bukkit.getServer()).getServer().getPlayerList(); + + nmsPlayer.connection.send(new ClientboundChangeDifficultyPacket( + levelData.getDifficulty(), levelData.isDifficultyLocked() + )); + playerList.sendPlayerPermissionLevel(nmsPlayer); + nmsPlayer.connection.send(new ClientboundPlayerAbilitiesPacket(nmsPlayer.getAbilities())); + playerList.sendLevelInfo(nmsPlayer, nmsWorld); + playerList.sendAllPlayerInfo(nmsPlayer); + playerList.sendActivePlayerEffects(nmsPlayer); + + PlayerPositionNMS.sendPos(nmsPlayer, nmsPlayer.position()); + + nmsPlayer.connection.send(new ClientboundSetChunkCacheCenterPacket( + nmsPlayer.chunkPosition().x(), + nmsPlayer.chunkPosition().z() + )); + + int viewDistance = nmsWorld.getServer().getPlayerList().getViewDistance(); + ChunkPos center = nmsPlayer.chunkPosition(); + for (int cx = center.x() - viewDistance; cx <= center.x() + viewDistance; cx++) { + for (int cz = center.z() - viewDistance; cz <= center.z() + viewDistance; cz++) { + LevelChunk chunk = nmsWorld.getChunkIfLoaded(cx, cz); + if (chunk != null) { + nmsPlayer.connection.send( + new ClientboundLevelChunkWithLightPacket(chunk, nmsWorld.getLightEngine(), null, null, false) + ); + } + } + } + } + + private static CommonPlayerSpawnInfo getDimensionPlayerSpawnInfo(CommonPlayerSpawnInfo base, ResourceKey dimensionKey) { + return new CommonPlayerSpawnInfo( + base.dimensionType(), + dimensionKey, + base.seed(), + base.gameType(), + base.previousGameType(), + base.isDebug(), + base.isFlat(), + base.lastDeathLocation(), + base.portalCooldown(), + base.seaLevel() + ); + } + + private static ResourceKey getPivotDimension(ResourceKey currentDimension) { + return currentDimension.equals(Level.OVERWORLD) ? Level.END : Level.OVERWORLD; + } + + +} diff --git a/src/main/resources/translations/default/commands.properties b/src/main/resources/translations/default/commands.properties index df2e5fd92..3f86e4b64 100644 --- a/src/main/resources/translations/default/commands.properties +++ b/src/main/resources/translations/default/commands.properties @@ -19,6 +19,10 @@ command.debug.chronometer.cant_90s_chronometer=Ne pas dépasser plus de 90s command.debug.cooldown.success=Succès, le cooldown est activé command.debug.cooldown.error=Erreur, vous pouvez refaire la commande +command.registry.custom_ambient.apply.null=Erreur, l'id renseigné est nul +command.registry.custom_ambient.apply.success=L'ambiance %1$s a été correctement appliqué sur %2$s ! +command.registry.custom_ambient.reset.success=L'ambiance a été correctement enlevé sur %1$s ! + command.utils.cooldowns.no_cooldown=Vous n'avez aucun cooldown actif. command.utils.cooldowns.list_cooldowns=Liste des cooldowns actifs : command.utils.cooldowns.list=- %1$s : %2$s From c434a7409c6b166594a84fefd9625dfff29b7460 Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Fri, 29 May 2026 22:55:05 +0200 Subject: [PATCH 04/10] improve structure --- .../core/registry/ambient/CustomAmbient.java | 18 +++- .../ambient/contents/DarkAmbient.java | 8 ++ .../core/utils/nms/PlayerRespawnNMS.java | 92 ++++++++++++------- 3 files changed, 82 insertions(+), 36 deletions(-) diff --git a/src/main/java/fr/openmc/core/registry/ambient/CustomAmbient.java b/src/main/java/fr/openmc/core/registry/ambient/CustomAmbient.java index c1a7ed4cf..0e86b756e 100644 --- a/src/main/java/fr/openmc/core/registry/ambient/CustomAmbient.java +++ b/src/main/java/fr/openmc/core/registry/ambient/CustomAmbient.java @@ -11,6 +11,7 @@ import net.minecraft.resources.ResourceKey; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.level.Level; import net.minecraft.world.level.dimension.DimensionType; import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.entity.Player; @@ -31,7 +32,11 @@ public void apply(Player player) { ServerPlayer nmsPlayer = ((CraftPlayer) player).getHandle(); // * On envoie le packet respawn qui applique l'ambience - PlayerRespawnNMS.sendRespawnPackets(nmsPlayer, getPlayerAmbientSpawnInfo(nmsPlayer)); + PlayerRespawnNMS.sendPacket( + nmsPlayer, + getPlayerAmbientSpawnInfo(nmsPlayer), + getPivotDimension(nmsPlayer) + ); } /** @@ -42,7 +47,11 @@ public static void reset(Player player) { ServerPlayer nmsPlayer = ((CraftPlayer) player).getHandle(); // * On envoie le packet respawn qui remets tout a la normale - PlayerRespawnNMS.sendRespawnPackets(nmsPlayer, nmsPlayer.createCommonSpawnInfo(nmsPlayer.level())); + PlayerRespawnNMS.sendPacket( + nmsPlayer, + nmsPlayer.createCommonSpawnInfo(nmsPlayer.level()), + getPivotDimension(nmsPlayer) + ); } private CommonPlayerSpawnInfo getPlayerAmbientSpawnInfo(ServerPlayer nmsPlayer) { @@ -74,4 +83,9 @@ private CommonPlayerSpawnInfo getPlayerAmbientSpawnInfo(ServerPlayer nmsPlayer) spawnInfo.seaLevel() ); } + + private static ResourceKey getPivotDimension(ServerPlayer nmsPlayer) { + return nmsPlayer.createCommonSpawnInfo(nmsPlayer.level()).dimension() + .equals(Level.OVERWORLD) ? Level.END : Level.NETHER; + } } diff --git a/src/main/java/fr/openmc/core/registry/ambient/contents/DarkAmbient.java b/src/main/java/fr/openmc/core/registry/ambient/contents/DarkAmbient.java index 1f21918d2..61ff0038e 100644 --- a/src/main/java/fr/openmc/core/registry/ambient/contents/DarkAmbient.java +++ b/src/main/java/fr/openmc/core/registry/ambient/contents/DarkAmbient.java @@ -12,6 +12,14 @@ public String getId() { @Override public DimensionTypesInjector.DimensionTypeBuilder getDimensionType() { return new DimensionTypesInjector.DimensionTypeBuilder() + .attributes(obj -> { + obj.addProperty("visual/ambient_light_color", "#DD37E6"); + obj.addProperty("visual/sky_color", "#684873"); + obj.addProperty("visual/sky_light_color", "#3B205E"); + obj.addProperty("visual/fog_start_distance", 78); + obj.addProperty("visual/fog_end_distance", 98); + obj.addProperty("visual/sunrise_sunset_color", "#F7BE27C4"); + }) .hasCeiling(true) .hasSkylight(true); } diff --git a/src/main/java/fr/openmc/core/utils/nms/PlayerRespawnNMS.java b/src/main/java/fr/openmc/core/utils/nms/PlayerRespawnNMS.java index 25fff7982..b942fb460 100644 --- a/src/main/java/fr/openmc/core/utils/nms/PlayerRespawnNMS.java +++ b/src/main/java/fr/openmc/core/utils/nms/PlayerRespawnNMS.java @@ -1,5 +1,6 @@ package fr.openmc.core.utils.nms; +import fr.openmc.core.OMCPlugin; import fr.openmc.core.registry.ambient.CustomAmbient; import net.minecraft.network.protocol.game.*; import net.minecraft.resources.ResourceKey; @@ -12,6 +13,9 @@ import net.minecraft.world.level.storage.LevelData; import org.bukkit.Bukkit; import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitRunnable; /** * Classe receuillant les NMS lié au packet {@link ClientboundRespawnPacket} @@ -20,8 +24,13 @@ * @see CustomAmbient utilisation trés spécifique, on affiche une dimension_type sur le joueur, ds la dimension actuelle */ public class PlayerRespawnNMS { - // todo: continue this - public static void sendRespawnPacket(ServerPlayer nmsPlayer, CommonPlayerSpawnInfo spawnInfo) { + /** + * Envoie le packet RESPAWN au joueur ciblé, avec des informations données + * En utilisant des procédures qui assurent le tout + * @param nmsPlayer le joueur en NMS + * @param spawnInfo Les informations de la dimension ou il est envoyé + */ + public static void sendPacket(ServerPlayer nmsPlayer, CommonPlayerSpawnInfo spawnInfo) { nmsPlayer.connection.send(new ClientboundRespawnPacket( spawnInfo, ClientboundRespawnPacket.KEEP_ALL_DATA @@ -29,35 +38,49 @@ public static void sendRespawnPacket(ServerPlayer nmsPlayer, CommonPlayerSpawnIn // ** Procédure afin que le packet respawn soit valide - PlayerRespawnNMS.sendPostRespawnPackets(nmsPlayer); -// resyncEntitiesAfterDimensionRefresh(player); + sendPostRespawnPackets(nmsPlayer); + resyncEntities(nmsPlayer.getBukkitEntity().getPlayer()); } -// private void resyncEntitiesAfterDimensionRefresh(Player player) { -// new BukkitRunnable() { -// @Override -// public void run() { -// if (!player.isOnline()) return; -// -// double range = 96.0D; -// for (Entity entity : player.getNearbyEntities(range, range, range)) { -// if (entity.equals(player)) continue; -// -// player.hideEntity(OMCPlugin.getInstance(), entity); -// player.showEntity(OMCPlugin.getInstance(), entity); -// } -// } -// }.runTaskLater(OMCPlugin.getInstance(), 2L); -// } - - public static void sendRespawnPackets(ServerPlayer nmsPlayer, CommonPlayerSpawnInfo targetSpawnInfo) { + + /** + * Envoie le packet RESPAWN au joueur ciblé avec les informations de spawn, + * plus un pivot qui permet d'afficher un changement de dimension + * @param nmsPlayer le joueur ciblé + * @param targetSpawnInfo les informations de spawn + * @param pivotDimension la dimension de pivot + * Note : Assurer vous que le pivot ne pointe pas vers une dimension ou le joueur est déja + * {@code nmsPlayer.createCommonSpawnInfo(nmsPlayer.level()).dimension().equals(Level.OVERWORLD) ? Level.END : Level.OVERWORLD;} + */ + public static void sendPacket(ServerPlayer nmsPlayer, CommonPlayerSpawnInfo targetSpawnInfo, ResourceKey pivotDimension) { CommonPlayerSpawnInfo currentSpawnInfo = nmsPlayer.createCommonSpawnInfo(nmsPlayer.level()); - ResourceKey pivotDimension = getPivotDimension(currentSpawnInfo.dimension()); // changement de dimension car sinon l'ambience de la dimension n'est pas affiché - sendRespawnPacket(nmsPlayer, getDimensionPlayerSpawnInfo(currentSpawnInfo, pivotDimension)); - sendRespawnPacket(nmsPlayer, targetSpawnInfo); + sendPacket(nmsPlayer, createPlayerSpawnInfoWithDimension(currentSpawnInfo, pivotDimension)); + sendPacket(nmsPlayer, targetSpawnInfo); + } + + /** + * Reaffiche les entités autour du joueur + * @param player le joueur ciblé + */ + private static void resyncEntities(Player player) { + new BukkitRunnable() { + @Override + public void run() { + if (!player.isOnline()) return; + + double range = 96.0D; + for (Entity entity : player.getNearbyEntities(range, range, range)) { + if (entity.equals(player)) continue; + + player.hideEntity(OMCPlugin.getInstance(), entity); + player.showEntity(OMCPlugin.getInstance(), entity); + } + } + }.runTaskLater(OMCPlugin.getInstance(), 2L); } + /** * Procédure basée sur {@link ServerPlayer#teleport} afin de corriger que le packet RESPAWN invalide * @param nmsPlayer le joueur (NMS) @@ -66,11 +89,12 @@ private static void sendPostRespawnPackets(ServerPlayer nmsPlayer) { ServerLevel nmsWorld = nmsPlayer.level(); LevelData levelData = nmsWorld.getLevelData(); - PlayerList playerList = ((CraftServer) Bukkit.getServer()).getServer().getPlayerList(); - + // ** Lancement des différentes procédure nécessaire apres un Repsawn Packet nmsPlayer.connection.send(new ClientboundChangeDifficultyPacket( levelData.getDifficulty(), levelData.isDifficultyLocked() )); + + PlayerList playerList = ((CraftServer) Bukkit.getServer()).getServer().getPlayerList(); playerList.sendPlayerPermissionLevel(nmsPlayer); nmsPlayer.connection.send(new ClientboundPlayerAbilitiesPacket(nmsPlayer.getAbilities())); playerList.sendLevelInfo(nmsPlayer, nmsWorld); @@ -98,7 +122,13 @@ private static void sendPostRespawnPackets(ServerPlayer nmsPlayer) { } } - private static CommonPlayerSpawnInfo getDimensionPlayerSpawnInfo(CommonPlayerSpawnInfo base, ResourceKey dimensionKey) { + /** + * Créer les Informations de Spawn avec la dimension ciblé, en gardant les autres informations de base + * @param base les informations de spawn de base + * @param dimensionKey la dimension type key + * @return Information de Spawn modifié + */ + private static CommonPlayerSpawnInfo createPlayerSpawnInfoWithDimension(CommonPlayerSpawnInfo base, ResourceKey dimensionKey) { return new CommonPlayerSpawnInfo( base.dimensionType(), dimensionKey, @@ -112,10 +142,4 @@ private static CommonPlayerSpawnInfo getDimensionPlayerSpawnInfo(CommonPlayerSpa base.seaLevel() ); } - - private static ResourceKey getPivotDimension(ResourceKey currentDimension) { - return currentDimension.equals(Level.OVERWORLD) ? Level.END : Level.OVERWORLD; - } - - } From 48a4a90a15115537cc90328bfbc64a74a879c4f0 Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Sat, 30 May 2026 10:38:20 +0200 Subject: [PATCH 05/10] speedy application dimension type --- .../core/utils/nms/PlayerRespawnNMS.java | 34 ++++++++++++++----- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/src/main/java/fr/openmc/core/utils/nms/PlayerRespawnNMS.java b/src/main/java/fr/openmc/core/utils/nms/PlayerRespawnNMS.java index b942fb460..481427745 100644 --- a/src/main/java/fr/openmc/core/utils/nms/PlayerRespawnNMS.java +++ b/src/main/java/fr/openmc/core/utils/nms/PlayerRespawnNMS.java @@ -24,18 +24,28 @@ * @see CustomAmbient utilisation trés spécifique, on affiche une dimension_type sur le joueur, ds la dimension actuelle */ public class PlayerRespawnNMS { + /** - * Envoie le packet RESPAWN au joueur ciblé, avec des informations données - * En utilisant des procédures qui assurent le tout + * Envoie juste le packet respawn. * @param nmsPlayer le joueur en NMS * @param spawnInfo Les informations de la dimension ou il est envoyé */ - public static void sendPacket(ServerPlayer nmsPlayer, CommonPlayerSpawnInfo spawnInfo) { + private static void sendSimplePacket(ServerPlayer nmsPlayer, CommonPlayerSpawnInfo spawnInfo) { nmsPlayer.connection.send(new ClientboundRespawnPacket( spawnInfo, ClientboundRespawnPacket.KEEP_ALL_DATA )); + } + /** + * Envoie le packet RESPAWN au joueur ciblé, avec des informations données + * En utilisant des procédures qui assurent le tout + * @param nmsPlayer le joueur en NMS + * @param spawnInfo Les informations de la dimension ou il est envoyé + */ + public static void sendPacket(ServerPlayer nmsPlayer, CommonPlayerSpawnInfo spawnInfo) { + // ** Envoie de l'entete du packet respawn + sendSimplePacket(nmsPlayer, spawnInfo); // ** Procédure afin que le packet respawn soit valide sendPostRespawnPackets(nmsPlayer); @@ -53,10 +63,9 @@ public static void sendPacket(ServerPlayer nmsPlayer, CommonPlayerSpawnInfo spaw * {@code nmsPlayer.createCommonSpawnInfo(nmsPlayer.level()).dimension().equals(Level.OVERWORLD) ? Level.END : Level.OVERWORLD;} */ public static void sendPacket(ServerPlayer nmsPlayer, CommonPlayerSpawnInfo targetSpawnInfo, ResourceKey pivotDimension) { - CommonPlayerSpawnInfo currentSpawnInfo = nmsPlayer.createCommonSpawnInfo(nmsPlayer.level()); - // changement de dimension car sinon l'ambience de la dimension n'est pas affiché - sendPacket(nmsPlayer, createPlayerSpawnInfoWithDimension(currentSpawnInfo, pivotDimension)); + // l'unique packet de repsawn pour simuler un changement de dimension + envoie du dimension type = plus rapide + sendSimplePacket(nmsPlayer, createPlayerSpawnInfoWithDimension(nmsPlayer, pivotDimension)); sendPacket(nmsPlayer, targetSpawnInfo); } @@ -97,6 +106,7 @@ private static void sendPostRespawnPackets(ServerPlayer nmsPlayer) { PlayerList playerList = ((CraftServer) Bukkit.getServer()).getServer().getPlayerList(); playerList.sendPlayerPermissionLevel(nmsPlayer); nmsPlayer.connection.send(new ClientboundPlayerAbilitiesPacket(nmsPlayer.getAbilities())); + playerList.sendLevelInfo(nmsPlayer, nmsWorld); playerList.sendAllPlayerInfo(nmsPlayer); playerList.sendActivePlayerEffects(nmsPlayer); @@ -108,6 +118,12 @@ private static void sendPostRespawnPackets(ServerPlayer nmsPlayer) { nmsPlayer.chunkPosition().z() )); + // ** Synchronise le cycle jour-nuit avec le monde actuel + nmsPlayer.connection.send(new ClientboundSetTimePacket( + nmsWorld.getGameTime(), + nmsWorld.clockManager().createFullSyncPacket().clockUpdates() + )); + int viewDistance = nmsWorld.getServer().getPlayerList().getViewDistance(); ChunkPos center = nmsPlayer.chunkPosition(); for (int cx = center.x() - viewDistance; cx <= center.x() + viewDistance; cx++) { @@ -124,11 +140,13 @@ private static void sendPostRespawnPackets(ServerPlayer nmsPlayer) { /** * Créer les Informations de Spawn avec la dimension ciblé, en gardant les autres informations de base - * @param base les informations de spawn de base + * @param nmsPlayer le joueur ciblé * @param dimensionKey la dimension type key * @return Information de Spawn modifié */ - private static CommonPlayerSpawnInfo createPlayerSpawnInfoWithDimension(CommonPlayerSpawnInfo base, ResourceKey dimensionKey) { + private static CommonPlayerSpawnInfo createPlayerSpawnInfoWithDimension(ServerPlayer nmsPlayer, ResourceKey dimensionKey) { + CommonPlayerSpawnInfo base = nmsPlayer.createCommonSpawnInfo(nmsPlayer.level()); + return new CommonPlayerSpawnInfo( base.dimensionType(), dimensionKey, From 3960777ca2e3d28769a3ce7dbebe3d7fc68d0635 Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Sat, 30 May 2026 13:19:40 +0200 Subject: [PATCH 06/10] remove static on reset + add transition dimension + add tracking of ambient --- .../injectors/DimensionTypesInjector.java | 65 ++++++++++++++++++- .../java/fr/openmc/core/ListenersManager.java | 4 +- .../core/registry/ambient/CustomAmbient.java | 43 +++++++++--- .../ambient/CustomAmbientRegistry.java | 4 +- .../commands/CustomAmbientCommands.java | 9 ++- .../ambient/contents/DarkAmbient.java | 20 ++++-- .../ambient/contents/HellAmbient.java | 44 +++++++++++++ .../listeners/CustomAmbientListener.java | 20 ++++++ .../core/utils/nms/PlayerRespawnNMS.java | 6 -- .../translations/default/commands.properties | 1 + 10 files changed, 193 insertions(+), 23 deletions(-) create mode 100644 src/main/java/fr/openmc/core/registry/ambient/contents/HellAmbient.java create mode 100644 src/main/java/fr/openmc/core/registry/ambient/listeners/CustomAmbientListener.java diff --git a/src/main/java/fr/openmc/api/datapacks/injectors/DimensionTypesInjector.java b/src/main/java/fr/openmc/api/datapacks/injectors/DimensionTypesInjector.java index e5f3aa88d..39a768ae5 100644 --- a/src/main/java/fr/openmc/api/datapacks/injectors/DimensionTypesInjector.java +++ b/src/main/java/fr/openmc/api/datapacks/injectors/DimensionTypesInjector.java @@ -1,9 +1,12 @@ package fr.openmc.api.datapacks.injectors; +import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; import fr.openmc.api.datapacks.DatapackInjector; +import net.minecraft.world.level.dimension.DimensionType; +import org.bukkit.Particle; import java.io.File; import java.io.IOException; @@ -64,6 +67,9 @@ public void inject(File rootFile) { * "has_ceiling": false, * "has_ender_dragon_fight": false, * "has_skylight": true, + * "has_fixed_time": true, + * "skybox": "overworld", + * "cardinal_light": "default", * "height": 384, * "infiniburn": "#minecraft:infiniburn_overworld", * "logical_height": 384, @@ -85,13 +91,16 @@ public static final class DimensionTypeBuilder { private Boolean hasCeiling = false; private Boolean hasEnderDragonFlight = false; private Boolean hasSkylight = true; + private Boolean hasFixedTime = false; + private String skybox = "overworld"; + private String cardinalLight = "default"; private Integer height = 384; private String infiniburn = "#infiniburn_overworld"; private Integer logicalHeight = 384; private Integer minY = -64; private Integer monsterSpawnBlockLightLimit = 0; private JsonElement monsterSpawnLightLevel = new JsonPrimitive(0); - private String timelines; + private String timelines = "#minecraft:in_overworld"; public DimensionTypeBuilder attributes(Consumer builder) { JsonObject obj = new JsonObject(); @@ -105,6 +114,38 @@ public DimensionTypeBuilder attributes(JsonObject attributes) { return this; } + /** + * Ajoute un attribut "minecraft:visual/ambient_particles" simple. + * Exemple : + * "minecraft:visual/ambient_particles": [ { "particle": { "type": "minecraft:crimson_spore" }, "probability": 0.025 } ] + */ + public DimensionTypeBuilder ambientParticles(String particleType, double probability) { + if (this.attributes == null) this.attributes = new JsonObject(); + JsonObject entry = new JsonObject(); + JsonObject particle = new JsonObject(); + particle.addProperty("type", particleType); + entry.add("particle", particle); + entry.addProperty("probability", probability); + + if (this.attributes.has("minecraft:visual/ambient_particles") && this.attributes.get("minecraft:visual/ambient_particles").isJsonArray()) { + this.attributes.getAsJsonArray("minecraft:visual/ambient_particles").add(entry); + } else { + JsonArray arr = new JsonArray(); + arr.add(entry); + this.attributes.add("minecraft:visual/ambient_particles", arr); + } + return this; + } + + /** + * Ajoute un attribut "minecraft:visual/ambient_particles" simple. + * Exemple : + * "minecraft:visual/ambient_particles": [ { "particle": { "type": "minecraft:crimson_spore" }, "probability": 0.025 } ] + */ + public DimensionTypeBuilder ambientParticles(Particle particle, double probability) { + return ambientParticles(particle.getKey().toString(), probability); + } + public DimensionTypeBuilder ambientLight(double ambientLight) { this.ambientLight = ambientLight; return this; @@ -135,6 +176,25 @@ public DimensionTypeBuilder hasSkylight(boolean hasSkylight) { return this; } + public DimensionTypeBuilder hasFixedTime(boolean hasFixedTime) { + this.hasFixedTime = hasFixedTime; + return this; + } + + public DimensionTypeBuilder skybox(String skybox) { + this.skybox = skybox; + return this; + } + + public DimensionTypeBuilder skybox(DimensionType.Skybox skybox) { + return skybox(skybox.getSerializedName()); + } + + public DimensionTypeBuilder cardinalLight(String cardinalLight) { + this.cardinalLight = cardinalLight; + return this; + } + public DimensionTypeBuilder height(int height) { this.height = height; return this; @@ -193,6 +253,9 @@ private JsonObject toJson() { if (hasCeiling != null) json.addProperty("has_ceiling", hasCeiling); if (hasEnderDragonFlight != null) json.addProperty("has_ender_dragon_fight", hasEnderDragonFlight); if (hasSkylight != null) json.addProperty("has_skylight", hasSkylight); + if (hasFixedTime != null) json.addProperty("has_fixed_time", hasFixedTime); + if (skybox != null) json.addProperty("skybox", skybox); + if (cardinalLight != null) json.addProperty("cardinal_light", cardinalLight); if (height != null) json.addProperty("height", height); if (infiniburn != null) json.addProperty("infiniburn", infiniburn); if (logicalHeight != null) json.addProperty("logical_height", logicalHeight); diff --git a/src/main/java/fr/openmc/core/ListenersManager.java b/src/main/java/fr/openmc/core/ListenersManager.java index 85fbe0d62..5f71dc22c 100644 --- a/src/main/java/fr/openmc/core/ListenersManager.java +++ b/src/main/java/fr/openmc/core/ListenersManager.java @@ -5,6 +5,7 @@ import fr.openmc.core.features.itemsadder.SpawnerExtractorListener; import fr.openmc.core.hooks.itemsadder.ItemsAdderHook; import fr.openmc.core.listeners.*; +import fr.openmc.core.registry.ambient.listeners.CustomAmbientListener; import org.bukkit.Bukkit; import org.bukkit.Server; import org.bukkit.event.Listener; @@ -33,7 +34,8 @@ public static void init() { new EquipableItemListener(), new NoMoreRabbit(), new ArmorListener(), - new BlockBreakListener() + new BlockBreakListener(), + new CustomAmbientListener() ); if (!OMCPlugin.isUnitTestVersion()) { diff --git a/src/main/java/fr/openmc/core/registry/ambient/CustomAmbient.java b/src/main/java/fr/openmc/core/registry/ambient/CustomAmbient.java index 0e86b756e..4ebb68fda 100644 --- a/src/main/java/fr/openmc/core/registry/ambient/CustomAmbient.java +++ b/src/main/java/fr/openmc/core/registry/ambient/CustomAmbient.java @@ -16,10 +16,28 @@ import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.entity.Player; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + public abstract class CustomAmbient { + // ** UUID playerUUID -> String idAmbient + public static final Map ACTIVE_AMBIENTS = new HashMap<>(); + public abstract String getId(); public abstract DimensionTypesInjector.DimensionTypeBuilder getDimensionType(); + /** + * Choix de la transition de dimension lorsque le joueur change d'ambience + * @return La key de la dimension + */ + public abstract ResourceKey getTransitionDimension(); + + /** + * Converti notre DimensionTypeBuild en un injecteur de datapack + * et qui mettera les dimension_type sous le namepsace omc_ambient + * @return Un datapack injector + */ public DatapackInjector toDimensionTypeInjector() { return new DimensionTypesInjector("omc_ambient").add(getId(), getDimensionType()); } @@ -35,25 +53,39 @@ public void apply(Player player) { PlayerRespawnNMS.sendPacket( nmsPlayer, getPlayerAmbientSpawnInfo(nmsPlayer), - getPivotDimension(nmsPlayer) + nmsPlayer.createCommonSpawnInfo(nmsPlayer.level()).dimension().equals(Level.OVERWORLD) + ? this.getTransitionDimension() + : Level.OVERWORLD ); + + ACTIVE_AMBIENTS.put(player.getUniqueId(), this.getId()); } /** * Retire l'ambience du Joueur * @param player le joueur ciblé */ - public static void reset(Player player) { + public void reset(Player player) { ServerPlayer nmsPlayer = ((CraftPlayer) player).getHandle(); // * On envoie le packet respawn qui remets tout a la normale PlayerRespawnNMS.sendPacket( nmsPlayer, nmsPlayer.createCommonSpawnInfo(nmsPlayer.level()), - getPivotDimension(nmsPlayer) + nmsPlayer.createCommonSpawnInfo(nmsPlayer.level()).dimension().equals(Level.OVERWORLD) + ? this.getTransitionDimension() + : Level.OVERWORLD ); + + ACTIVE_AMBIENTS.remove(player.getUniqueId()); } + /** + * Crée les informations de spawn du joueur en fonction de l'ambience ciblé + * En gros on cherche le dimension_type enregistré dans le registre, et on le mets dans les infos de spawn du joueur + * @param nmsPlayer le joueur ciblé + * @return les informations de spawn + */ private CommonPlayerSpawnInfo getPlayerAmbientSpawnInfo(ServerPlayer nmsPlayer) { ServerLevel nmsWorld = nmsPlayer.level(); CommonPlayerSpawnInfo spawnInfo = nmsPlayer.createCommonSpawnInfo(nmsPlayer.level()); @@ -83,9 +115,4 @@ private CommonPlayerSpawnInfo getPlayerAmbientSpawnInfo(ServerPlayer nmsPlayer) spawnInfo.seaLevel() ); } - - private static ResourceKey getPivotDimension(ServerPlayer nmsPlayer) { - return nmsPlayer.createCommonSpawnInfo(nmsPlayer.level()).dimension() - .equals(Level.OVERWORLD) ? Level.END : Level.NETHER; - } } diff --git a/src/main/java/fr/openmc/core/registry/ambient/CustomAmbientRegistry.java b/src/main/java/fr/openmc/core/registry/ambient/CustomAmbientRegistry.java index 748a38773..dd29def36 100644 --- a/src/main/java/fr/openmc/core/registry/ambient/CustomAmbientRegistry.java +++ b/src/main/java/fr/openmc/core/registry/ambient/CustomAmbientRegistry.java @@ -4,6 +4,7 @@ import fr.openmc.core.bootstrap.registries.KeyedRegistry; import fr.openmc.core.bootstrap.registries.Registry; import fr.openmc.core.registry.ambient.contents.DarkAmbient; +import fr.openmc.core.registry.ambient.contents.HellAmbient; import io.papermc.paper.plugin.bootstrap.BootstrapContext; import java.io.IOException; @@ -20,7 +21,8 @@ public String key(CustomAmbient registryObject) { @Override public void bootstrap(BootstrapContext context) throws IOException { register( - new DarkAmbient() + new DarkAmbient(), + new HellAmbient() ); for (CustomAmbient ambient : values()) { diff --git a/src/main/java/fr/openmc/core/registry/ambient/commands/CustomAmbientCommands.java b/src/main/java/fr/openmc/core/registry/ambient/commands/CustomAmbientCommands.java index 8ee843dae..71c919445 100644 --- a/src/main/java/fr/openmc/core/registry/ambient/commands/CustomAmbientCommands.java +++ b/src/main/java/fr/openmc/core/registry/ambient/commands/CustomAmbientCommands.java @@ -43,7 +43,14 @@ public void resetAmbient( Player player, Player toPlayer ) { - CustomAmbient.reset(toPlayer); + if (!CustomAmbient.ACTIVE_AMBIENTS.containsKey(toPlayer.getUniqueId())) { + MessagesManager.sendMessage(player, TranslationManager.translation("command.registry.custom_ambient.reset.player_havnt_ambient"), Prefix.STAFF, MessageType.ERROR, true); + return; + } + + String idAmbient = CustomAmbient.ACTIVE_AMBIENTS.get(toPlayer.getUniqueId()); + + OMCRegistry.CUSTOM_AMBIENTS.get(idAmbient).reset(toPlayer); MessagesManager.sendMessage(player, TranslationManager.translation("command.registry.custom_ambient.reset.success", Component.text(toPlayer.getName()).color(NamedTextColor.YELLOW) ), Prefix.STAFF, MessageType.ERROR, true); diff --git a/src/main/java/fr/openmc/core/registry/ambient/contents/DarkAmbient.java b/src/main/java/fr/openmc/core/registry/ambient/contents/DarkAmbient.java index 61ff0038e..296d9feef 100644 --- a/src/main/java/fr/openmc/core/registry/ambient/contents/DarkAmbient.java +++ b/src/main/java/fr/openmc/core/registry/ambient/contents/DarkAmbient.java @@ -2,6 +2,9 @@ import fr.openmc.api.datapacks.injectors.DimensionTypesInjector; import fr.openmc.core.registry.ambient.CustomAmbient; +import net.minecraft.resources.ResourceKey; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.dimension.DimensionType; public class DarkAmbient extends CustomAmbient { @Override @@ -14,13 +17,20 @@ public DimensionTypesInjector.DimensionTypeBuilder getDimensionType() { return new DimensionTypesInjector.DimensionTypeBuilder() .attributes(obj -> { obj.addProperty("visual/ambient_light_color", "#DD37E6"); - obj.addProperty("visual/sky_color", "#684873"); + obj.addProperty("visual/sky_color", "#DD37E6"); obj.addProperty("visual/sky_light_color", "#3B205E"); - obj.addProperty("visual/fog_start_distance", 78); - obj.addProperty("visual/fog_end_distance", 98); - obj.addProperty("visual/sunrise_sunset_color", "#F7BE27C4"); + obj.addProperty("visual/fog_start_distance", 40); + obj.addProperty("visual/fog_end_distance", 70); + obj.addProperty("visual/sunrise_sunset_color", "#FFBB00FA"); }) - .hasCeiling(true) + .defaultClock(null) + .timelines(null) + .skybox(DimensionType.Skybox.END) .hasSkylight(true); } + + @Override + public ResourceKey getTransitionDimension() { + return Level.END; + } } diff --git a/src/main/java/fr/openmc/core/registry/ambient/contents/HellAmbient.java b/src/main/java/fr/openmc/core/registry/ambient/contents/HellAmbient.java new file mode 100644 index 000000000..97c157c61 --- /dev/null +++ b/src/main/java/fr/openmc/core/registry/ambient/contents/HellAmbient.java @@ -0,0 +1,44 @@ +package fr.openmc.core.registry.ambient.contents; + +import fr.openmc.api.datapacks.injectors.DimensionTypesInjector; +import fr.openmc.core.registry.ambient.CustomAmbient; +import net.minecraft.resources.ResourceKey; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.dimension.DimensionType; +import org.bukkit.Particle; + +public class HellAmbient extends CustomAmbient { + @Override + public String getId() { + return "hell_ambient"; + } + + @Override + public DimensionTypesInjector.DimensionTypeBuilder getDimensionType() { + return new DimensionTypesInjector.DimensionTypeBuilder() + .attributes(obj -> { + obj.addProperty("visual/ambient_light_color", "#A3170B"); + obj.addProperty("visual/block_light_tint", "#F53200"); + obj.addProperty("visual/fog_start_distance", 10); + obj.addProperty("visual/fog_end_distance", 96); + obj.addProperty("minecraft:visual/sky_light_color", "#7a7aff"); + obj.addProperty("minecraft:visual/sky_light_factor", 0); + obj.addProperty("visual/fog_color","#5E1414"); + }) + .ambientParticles(Particle.CRIMSON_SPORE, 0.25f) + .defaultClock(null) + .ambientLight(0.1f) + .cardinalLight("nether") + .timelines("#minecraft:in_nether") + .skybox(DimensionType.Skybox.NONE) + .infiniburn("#minecraft:infiniburn_nether") + .hasSkylight(false) + .hasCeiling(true) + .hasFixedTime(true); + } + + @Override + public ResourceKey getTransitionDimension() { + return Level.NETHER; + } +} diff --git a/src/main/java/fr/openmc/core/registry/ambient/listeners/CustomAmbientListener.java b/src/main/java/fr/openmc/core/registry/ambient/listeners/CustomAmbientListener.java new file mode 100644 index 000000000..1a9a9c2f3 --- /dev/null +++ b/src/main/java/fr/openmc/core/registry/ambient/listeners/CustomAmbientListener.java @@ -0,0 +1,20 @@ +package fr.openmc.core.registry.ambient.listeners; + +import fr.openmc.core.registry.ambient.CustomAmbient; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerChangedWorldEvent; +import org.bukkit.event.player.PlayerQuitEvent; + +public class CustomAmbientListener implements Listener { + @EventHandler + public void onPlayerQuit(PlayerQuitEvent event) { + CustomAmbient.ACTIVE_AMBIENTS.remove(event.getPlayer().getUniqueId()); + } + + @EventHandler + public void onPlayerChangeWorld(PlayerChangedWorldEvent event) { + CustomAmbient.ACTIVE_AMBIENTS.remove(event.getPlayer().getUniqueId()); + } +} + diff --git a/src/main/java/fr/openmc/core/utils/nms/PlayerRespawnNMS.java b/src/main/java/fr/openmc/core/utils/nms/PlayerRespawnNMS.java index 481427745..0cec2d3e0 100644 --- a/src/main/java/fr/openmc/core/utils/nms/PlayerRespawnNMS.java +++ b/src/main/java/fr/openmc/core/utils/nms/PlayerRespawnNMS.java @@ -118,12 +118,6 @@ private static void sendPostRespawnPackets(ServerPlayer nmsPlayer) { nmsPlayer.chunkPosition().z() )); - // ** Synchronise le cycle jour-nuit avec le monde actuel - nmsPlayer.connection.send(new ClientboundSetTimePacket( - nmsWorld.getGameTime(), - nmsWorld.clockManager().createFullSyncPacket().clockUpdates() - )); - int viewDistance = nmsWorld.getServer().getPlayerList().getViewDistance(); ChunkPos center = nmsPlayer.chunkPosition(); for (int cx = center.x() - viewDistance; cx <= center.x() + viewDistance; cx++) { diff --git a/src/main/resources/translations/default/commands.properties b/src/main/resources/translations/default/commands.properties index 3f86e4b64..09b447603 100644 --- a/src/main/resources/translations/default/commands.properties +++ b/src/main/resources/translations/default/commands.properties @@ -21,6 +21,7 @@ command.debug.cooldown.error=Erreur, vous pouvez refaire la commande command.registry.custom_ambient.apply.null=Erreur, l'id renseigné est nul command.registry.custom_ambient.apply.success=L'ambiance %1$s a été correctement appliqué sur %2$s ! +command.registry.custom_ambient.reset.player_havnt_ambient=Erreur, le joueur n'a pas d'ambiance appliquée command.registry.custom_ambient.reset.success=L'ambiance a été correctement enlevé sur %1$s ! command.utils.cooldowns.no_cooldown=Vous n'avez aucun cooldown actif. From d2f677637b2a54bade465b0d341d0cae55182e22 Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Sat, 30 May 2026 13:57:52 +0200 Subject: [PATCH 07/10] readd getTransitionDimensionForPlayer --- .../core/registry/ambient/CustomAmbient.java | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/main/java/fr/openmc/core/registry/ambient/CustomAmbient.java b/src/main/java/fr/openmc/core/registry/ambient/CustomAmbient.java index 4ebb68fda..0261597d6 100644 --- a/src/main/java/fr/openmc/core/registry/ambient/CustomAmbient.java +++ b/src/main/java/fr/openmc/core/registry/ambient/CustomAmbient.java @@ -53,9 +53,7 @@ public void apply(Player player) { PlayerRespawnNMS.sendPacket( nmsPlayer, getPlayerAmbientSpawnInfo(nmsPlayer), - nmsPlayer.createCommonSpawnInfo(nmsPlayer.level()).dimension().equals(Level.OVERWORLD) - ? this.getTransitionDimension() - : Level.OVERWORLD + getTransitionDimensionForPlayer(nmsPlayer) ); ACTIVE_AMBIENTS.put(player.getUniqueId(), this.getId()); @@ -72,14 +70,25 @@ public void reset(Player player) { PlayerRespawnNMS.sendPacket( nmsPlayer, nmsPlayer.createCommonSpawnInfo(nmsPlayer.level()), - nmsPlayer.createCommonSpawnInfo(nmsPlayer.level()).dimension().equals(Level.OVERWORLD) - ? this.getTransitionDimension() - : Level.OVERWORLD + getTransitionDimensionForPlayer(nmsPlayer) ); ACTIVE_AMBIENTS.remove(player.getUniqueId()); } + /** + * Calcule la dimension de transition appropriée pour le joueur + * Si le joueur est en OVERWORLD, on transitionne vers l'ambience + * Sinon on revient à l'OVERWORLD + * @param nmsPlayer le joueur ciblé + * @return la key de dimension + */ + private ResourceKey getTransitionDimensionForPlayer(ServerPlayer nmsPlayer) { + return nmsPlayer.createCommonSpawnInfo(nmsPlayer.level()).dimension().equals(Level.OVERWORLD) + ? this.getTransitionDimension() + : Level.OVERWORLD; + } + /** * Crée les informations de spawn du joueur en fonction de l'ambience ciblé * En gros on cherche le dimension_type enregistré dans le registre, et on le mets dans les infos de spawn du joueur From 0c4a1ed463bd4c8f6147fdb6e82d737e1c33497d Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Sat, 30 May 2026 14:17:26 +0200 Subject: [PATCH 08/10] add cache for dimension type (next optimize PlayerRespawnNMS (Chunk and light)) --- .../core/registry/ambient/CustomAmbient.java | 40 +++++++++++-------- .../ambient/contents/DarkAmbient.java | 2 +- .../ambient/contents/HellAmbient.java | 2 +- 3 files changed, 25 insertions(+), 19 deletions(-) diff --git a/src/main/java/fr/openmc/core/registry/ambient/CustomAmbient.java b/src/main/java/fr/openmc/core/registry/ambient/CustomAmbient.java index 0261597d6..19e475510 100644 --- a/src/main/java/fr/openmc/core/registry/ambient/CustomAmbient.java +++ b/src/main/java/fr/openmc/core/registry/ambient/CustomAmbient.java @@ -9,7 +9,7 @@ import net.minecraft.network.protocol.game.CommonPlayerSpawnInfo; import net.minecraft.resources.Identifier; import net.minecraft.resources.ResourceKey; -import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.level.Level; import net.minecraft.world.level.dimension.DimensionType; @@ -23,9 +23,10 @@ public abstract class CustomAmbient { // ** UUID playerUUID -> String idAmbient public static final Map ACTIVE_AMBIENTS = new HashMap<>(); + private Holder CACHED_DIMENSION_TYPE = null; public abstract String getId(); - public abstract DimensionTypesInjector.DimensionTypeBuilder getDimensionType(); + public abstract DimensionTypesInjector.DimensionTypeBuilder getDimensionTypeBuilder(); /** * Choix de la transition de dimension lorsque le joueur change d'ambience @@ -39,7 +40,7 @@ public abstract class CustomAmbient { * @return Un datapack injector */ public DatapackInjector toDimensionTypeInjector() { - return new DimensionTypesInjector("omc_ambient").add(getId(), getDimensionType()); + return new DimensionTypesInjector("omc_ambient").add(getId(), getDimensionTypeBuilder()); } /** @@ -96,23 +97,10 @@ private ResourceKey getTransitionDimensionForPlayer(ServerPlayer nmsPlaye * @return les informations de spawn */ private CommonPlayerSpawnInfo getPlayerAmbientSpawnInfo(ServerPlayer nmsPlayer) { - ServerLevel nmsWorld = nmsPlayer.level(); CommonPlayerSpawnInfo spawnInfo = nmsPlayer.createCommonSpawnInfo(nmsPlayer.level()); - ResourceKey key = ResourceKey.create( - Registries.DIMENSION_TYPE, - Identifier.fromNamespaceAndPath("omc_ambient", this.getId()) - ); - - Registry dimRegistry = - nmsWorld.registryAccess().lookupOrThrow(Registries.DIMENSION_TYPE); - - Holder dimensionTypeHolder = dimRegistry.get(key).orElseThrow(() -> - new IllegalStateException("DimensionType omc_ambient:"+ this.getId() +" introuvable") - ); - return new CommonPlayerSpawnInfo( - dimensionTypeHolder, + getDimensionType(), spawnInfo.dimension(), spawnInfo.seed(), spawnInfo.gameType(), @@ -124,4 +112,22 @@ private CommonPlayerSpawnInfo getPlayerAmbientSpawnInfo(ServerPlayer nmsPlayer) spawnInfo.seaLevel() ); } + + private Holder getDimensionType() { + if (CACHED_DIMENSION_TYPE != null) + return CACHED_DIMENSION_TYPE; + + ResourceKey key = ResourceKey.create( + Registries.DIMENSION_TYPE, + Identifier.fromNamespaceAndPath("omc_ambient", this.getId()) + ); + + Registry dimRegistry = + MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.DIMENSION_TYPE); + + CACHED_DIMENSION_TYPE = dimRegistry.get(key).orElseThrow(() -> + new IllegalStateException("DimensionType omc_ambient:"+ this.getId() +" introuvable") + ); + return CACHED_DIMENSION_TYPE; + } } diff --git a/src/main/java/fr/openmc/core/registry/ambient/contents/DarkAmbient.java b/src/main/java/fr/openmc/core/registry/ambient/contents/DarkAmbient.java index 296d9feef..4e84828fe 100644 --- a/src/main/java/fr/openmc/core/registry/ambient/contents/DarkAmbient.java +++ b/src/main/java/fr/openmc/core/registry/ambient/contents/DarkAmbient.java @@ -13,7 +13,7 @@ public String getId() { } @Override - public DimensionTypesInjector.DimensionTypeBuilder getDimensionType() { + public DimensionTypesInjector.DimensionTypeBuilder getDimensionTypeBuilder() { return new DimensionTypesInjector.DimensionTypeBuilder() .attributes(obj -> { obj.addProperty("visual/ambient_light_color", "#DD37E6"); diff --git a/src/main/java/fr/openmc/core/registry/ambient/contents/HellAmbient.java b/src/main/java/fr/openmc/core/registry/ambient/contents/HellAmbient.java index 97c157c61..98aba1cf3 100644 --- a/src/main/java/fr/openmc/core/registry/ambient/contents/HellAmbient.java +++ b/src/main/java/fr/openmc/core/registry/ambient/contents/HellAmbient.java @@ -14,7 +14,7 @@ public String getId() { } @Override - public DimensionTypesInjector.DimensionTypeBuilder getDimensionType() { + public DimensionTypesInjector.DimensionTypeBuilder getDimensionTypeBuilder() { return new DimensionTypesInjector.DimensionTypeBuilder() .attributes(obj -> { obj.addProperty("visual/ambient_light_color", "#A3170B"); From 417984489b084a6d72654d9839633af8b05efedc Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Fri, 5 Jun 2026 18:01:11 +0200 Subject: [PATCH 09/10] Update src/main/java/fr/openmc/api/datapacks/OMCDatapack.java MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Timéo B. --- src/main/java/fr/openmc/api/datapacks/OMCDatapack.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/fr/openmc/api/datapacks/OMCDatapack.java b/src/main/java/fr/openmc/api/datapacks/OMCDatapack.java index 996da0ee8..e2af508b8 100644 --- a/src/main/java/fr/openmc/api/datapacks/OMCDatapack.java +++ b/src/main/java/fr/openmc/api/datapacks/OMCDatapack.java @@ -21,7 +21,7 @@ public class OMCDatapack { public OMCDatapack(String packName, String namespace) { this.packName=packName; - this.namespace=namespace; + this.namespace = namespace; } public void build(BootstrapContext context) throws IOException { From 1a639415814c1dca67b83bbfc6b1e13cfd0649cc Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Fri, 5 Jun 2026 18:16:24 +0200 Subject: [PATCH 10/10] Update src/main/java/fr/openmc/api/datapacks/OMCDatapack.java MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Timéo B. --- src/main/java/fr/openmc/api/datapacks/OMCDatapack.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/fr/openmc/api/datapacks/OMCDatapack.java b/src/main/java/fr/openmc/api/datapacks/OMCDatapack.java index e2af508b8..2352a1b9b 100644 --- a/src/main/java/fr/openmc/api/datapacks/OMCDatapack.java +++ b/src/main/java/fr/openmc/api/datapacks/OMCDatapack.java @@ -20,7 +20,7 @@ public class OMCDatapack { private final Set injectors = new HashSet<>(); public OMCDatapack(String packName, String namespace) { - this.packName=packName; + this.packName = packName; this.namespace = namespace; }