diff --git a/bukkit/build.gradle.kts b/bukkit/build.gradle.kts index 92915efaf..607fff3b3 100644 --- a/bukkit/build.gradle.kts +++ b/bukkit/build.gradle.kts @@ -91,10 +91,10 @@ tasks { relocate("org.apache.commons.io", "net.momirealms.craftengine.libraries.commons.io") relocate("org.bstats", "net.momirealms.craftengine.libraries.bstats") relocate("com.github.benmanes.caffeine", "net.momirealms.craftengine.libraries.caffeine") - relocate("net.objecthunter.exp4j", "net.momirealms.craftengine.libraries.exp4j") relocate("net.bytebuddy", "net.momirealms.craftengine.libraries.bytebuddy") relocate("org.yaml.snakeyaml", "net.momirealms.craftengine.libraries.snakeyaml") relocate("org.ahocorasick", "net.momirealms.craftengine.libraries.ahocorasick") + relocate("com.ezylang.evalex", "net.momirealms.craftengine.libraries.evalex") } } diff --git a/bukkit/compatibility/build.gradle.kts b/bukkit/compatibility/build.gradle.kts index b0cd5fa25..db481a7c5 100644 --- a/bukkit/compatibility/build.gradle.kts +++ b/bukkit/compatibility/build.gradle.kts @@ -26,9 +26,6 @@ dependencies { compileOnly("pers.neige.neigeitems:NeigeItems:1.21.42") // Placeholder compileOnly("me.clip:placeholderapi:${rootProject.properties["placeholder_api_version"]}") - // WorldEdit - compileOnly("com.sk89q.worldedit:worldedit-core:7.2.19") - compileOnly("com.sk89q.worldedit:worldedit-bukkit:7.2.19") // SlimeWorld compileOnly("com.infernalsuite.asp:api:4.0.0-SNAPSHOT") // ModelEngine @@ -44,6 +41,10 @@ dependencies { compileOnly("com.viaversion:viaversion-api:5.3.2") // Skript compileOnly("com.github.SkriptLang:Skript:2.11.0") + // FAWE + compileOnly(platform("com.intellectualsites.bom:bom-newest:1.52")) + compileOnly("com.fastasyncworldedit:FastAsyncWorldEdit-Core") + compileOnly("com.fastasyncworldedit:FastAsyncWorldEdit-Bukkit") { isTransitive = false } } java { diff --git a/bukkit/compatibility/legacy/src/main/java/net/momirealms/craftengine/bukkit/compatibility/legacy/slimeworld/LegacySlimeFormatStorageAdaptor.java b/bukkit/compatibility/legacy/src/main/java/net/momirealms/craftengine/bukkit/compatibility/legacy/slimeworld/LegacySlimeFormatStorageAdaptor.java index 872e50bf8..982f91c5e 100644 --- a/bukkit/compatibility/legacy/src/main/java/net/momirealms/craftengine/bukkit/compatibility/legacy/slimeworld/LegacySlimeFormatStorageAdaptor.java +++ b/bukkit/compatibility/legacy/src/main/java/net/momirealms/craftengine/bukkit/compatibility/legacy/slimeworld/LegacySlimeFormatStorageAdaptor.java @@ -2,8 +2,10 @@ package net.momirealms.craftengine.bukkit.compatibility.legacy.slimeworld; import com.infernalsuite.aswm.api.events.LoadSlimeWorldEvent; import com.infernalsuite.aswm.api.world.SlimeWorld; +import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.world.World; import net.momirealms.craftengine.core.world.WorldManager; +import net.momirealms.craftengine.core.world.chunk.storage.CachedStorage; import net.momirealms.craftengine.core.world.chunk.storage.DefaultStorageAdaptor; import net.momirealms.craftengine.core.world.chunk.storage.WorldDataStorage; import org.bukkit.Bukkit; @@ -22,7 +24,8 @@ public class LegacySlimeFormatStorageAdaptor extends DefaultStorageAdaptor imple @EventHandler public void onWorldLoad(LoadSlimeWorldEvent event) { org.bukkit.World world = Bukkit.getWorld(event.getSlimeWorld().getName()); - this.worldManager.loadWorld(this.worldManager.createWorld(this.worldManager.wrap(world), new LegacySlimeWorldDataStorage(event.getSlimeWorld()))); + this.worldManager.loadWorld(this.worldManager.createWorld(this.worldManager.wrap(world), + Config.enableChunkCache() ? new CachedStorage<>(new LegacySlimeWorldDataStorage(event.getSlimeWorld())) : new LegacySlimeWorldDataStorage(event.getSlimeWorld()))); } public LegacySlimeFormatStorageAdaptor(WorldManager worldManager, int version) { diff --git a/bukkit/compatibility/legacy/src/main/java/net/momirealms/craftengine/bukkit/compatibility/legacy/slimeworld/LegacySlimeWorldDataStorage.java b/bukkit/compatibility/legacy/src/main/java/net/momirealms/craftengine/bukkit/compatibility/legacy/slimeworld/LegacySlimeWorldDataStorage.java index b4550330f..4feff8a93 100644 --- a/bukkit/compatibility/legacy/src/main/java/net/momirealms/craftengine/bukkit/compatibility/legacy/slimeworld/LegacySlimeWorldDataStorage.java +++ b/bukkit/compatibility/legacy/src/main/java/net/momirealms/craftengine/bukkit/compatibility/legacy/slimeworld/LegacySlimeWorldDataStorage.java @@ -1,7 +1,6 @@ package net.momirealms.craftengine.bukkit.compatibility.legacy.slimeworld; import com.flowpowered.nbt.ByteArrayTag; -import com.flowpowered.nbt.CompoundMap; import com.infernalsuite.aswm.api.world.SlimeChunk; import com.infernalsuite.aswm.api.world.SlimeWorld; import net.momirealms.craftengine.core.world.CEWorld; @@ -42,20 +41,8 @@ public class LegacySlimeWorldDataStorage implements WorldDataStorage { } } - private CompoundMap createOrGetDataMap(SlimeWorld world) { - Optional optionalCompoundTag = world.getExtraData().getAsCompoundTag("craftengine"); - CompoundMap ccDataMap; - if (optionalCompoundTag.isEmpty()) { - ccDataMap = new CompoundMap(); - world.getExtraData().getValue().put(new com.flowpowered.nbt.CompoundTag("customcrops", ccDataMap)); - } else { - ccDataMap = optionalCompoundTag.get().getValue(); - } - return ccDataMap; - } - @Override - public void writeChunkAt(@NotNull ChunkPos pos, @NotNull CEChunk chunk, boolean immediately) { + public void writeChunkAt(@NotNull ChunkPos pos, @NotNull CEChunk chunk) { SlimeChunk slimeChunk = getWorld().getChunk(pos.x, pos.z); if (slimeChunk == null) return; CompoundTag nbt = DefaultChunkSerializer.serialize(chunk); diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/slimeworld/SlimeFormatStorageAdaptor.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/slimeworld/SlimeFormatStorageAdaptor.java index b01a6e1c1..2c02934a8 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/slimeworld/SlimeFormatStorageAdaptor.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/slimeworld/SlimeFormatStorageAdaptor.java @@ -3,9 +3,11 @@ package net.momirealms.craftengine.bukkit.compatibility.slimeworld; import com.infernalsuite.asp.api.AdvancedSlimePaperAPI; import com.infernalsuite.asp.api.events.LoadSlimeWorldEvent; import com.infernalsuite.asp.api.world.SlimeWorld; +import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.util.ReflectionUtils; import net.momirealms.craftengine.core.world.World; import net.momirealms.craftengine.core.world.WorldManager; +import net.momirealms.craftengine.core.world.chunk.storage.CachedStorage; import net.momirealms.craftengine.core.world.chunk.storage.DefaultStorageAdaptor; import net.momirealms.craftengine.core.world.chunk.storage.WorldDataStorage; import org.bukkit.Bukkit; @@ -24,7 +26,8 @@ public class SlimeFormatStorageAdaptor extends DefaultStorageAdaptor implements @EventHandler public void onWorldLoad(LoadSlimeWorldEvent event) { org.bukkit.World world = Bukkit.getWorld(event.getSlimeWorld().getName()); - this.worldManager.loadWorld(this.worldManager.createWorld(this.worldManager.wrap(world), new SlimeWorldDataStorage(event.getSlimeWorld(), this))); + this.worldManager.loadWorld(this.worldManager.createWorld(this.worldManager.wrap(world), + Config.enableChunkCache() ? new CachedStorage<>(new SlimeWorldDataStorage(event.getSlimeWorld(), this)) : new SlimeWorldDataStorage(event.getSlimeWorld(), this))); } public SlimeFormatStorageAdaptor(WorldManager worldManager) { diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/slimeworld/SlimeWorldDataStorage.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/slimeworld/SlimeWorldDataStorage.java index ae6703087..663689520 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/slimeworld/SlimeWorldDataStorage.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/slimeworld/SlimeWorldDataStorage.java @@ -44,7 +44,7 @@ public class SlimeWorldDataStorage implements WorldDataStorage { @SuppressWarnings("unchecked") @Override - public void writeChunkAt(@NotNull ChunkPos pos, @NotNull CEChunk chunk, boolean immediately) { + public void writeChunkAt(@NotNull ChunkPos pos, @NotNull CEChunk chunk) { SlimeChunk slimeChunk = getWorld().getChunk(pos.x, pos.z); if (slimeChunk == null) return; CompoundTag nbt = DefaultChunkSerializer.serialize(chunk); diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/worldedit/FastAsyncWorldEditDelegate.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/worldedit/FastAsyncWorldEditDelegate.java new file mode 100644 index 000000000..fc51538cf --- /dev/null +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/worldedit/FastAsyncWorldEditDelegate.java @@ -0,0 +1,208 @@ +package net.momirealms.craftengine.bukkit.compatibility.worldedit; + +import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter; +import com.fastasyncworldedit.bukkit.adapter.FaweAdapter; +import com.fastasyncworldedit.core.configuration.Settings; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.bukkit.WorldEditPlugin; +import com.sk89q.worldedit.event.extent.EditSessionEvent; +import com.sk89q.worldedit.extent.AbstractDelegateExtent; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.eventbus.Subscribe; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; +import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.plugin.injector.BukkitInjector; +import net.momirealms.craftengine.bukkit.util.BlockStateUtils; +import net.momirealms.craftengine.core.block.EmptyBlock; +import net.momirealms.craftengine.core.block.ImmutableBlockState; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.util.ReflectionUtils; +import net.momirealms.craftengine.core.world.CEWorld; +import net.momirealms.craftengine.core.world.ChunkPos; +import net.momirealms.craftengine.core.world.SectionPos; +import net.momirealms.craftengine.core.world.chunk.CEChunk; +import net.momirealms.craftengine.core.world.chunk.CESection; +import org.bukkit.Bukkit; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.lang.reflect.Method; +import java.util.*; + +import static java.util.Objects.requireNonNull; + +public class FastAsyncWorldEditDelegate extends AbstractDelegateExtent { + private static int[] ordinalToIbdID; + private final Set chunksToSave; + private final CEWorld ceWorld; + private final Set brokenChunks = Collections.synchronizedSet(new HashSet<>()); + + protected FastAsyncWorldEditDelegate(EditSessionEvent event) { + super(event.getExtent()); + this.chunksToSave = new HashSet<>(); + World weWorld = event.getWorld(); + org.bukkit.World world = Bukkit.getWorld(requireNonNull(weWorld).getName()); + CEWorld ceWorld = CraftEngine.instance().worldManager().getWorld(requireNonNull(world).getUID()); + this.ceWorld = requireNonNull(ceWorld); + } + + public static void init() { + Settings.settings().EXTENT.ALLOWED_PLUGINS.add(FastAsyncWorldEditDelegate.class.getCanonicalName()); + FaweAdapter adapter = (FaweAdapter) WorldEditPlugin.getInstance().getBukkitImplAdapter(); + Method ordinalToIbdIDMethod = ReflectionUtils.getDeclaredMethod(CachedBukkitAdapter.class, int.class.arrayType(), new String[]{"getOrdinalToIbdID"}); + try { + assert ordinalToIbdIDMethod != null; + ordinalToIbdID = (int[]) ordinalToIbdIDMethod.invoke(adapter); + } catch (ReflectiveOperationException e) { + throw new RuntimeException("Failed to init FastAsyncWorldEdit compatibility", e); + } + WorldEdit.getInstance().getEventBus().register(new Object() { + @Subscribe + @SuppressWarnings("unused") + public void onEditSessionEvent(EditSessionEvent event) { + World weWorld = event.getWorld(); + if (weWorld == null) return; + if (event.getStage() == EditSession.Stage.BEFORE_CHANGE) { + event.setExtent(new FastAsyncWorldEditDelegate(event)); + } + } + }); + } + + private static void injectLevelChunk(Object chunkSource, CEChunk ceChunk) { + ChunkPos pos = ceChunk.chunkPos(); + Object levelChunk = FastNMS.INSTANCE.method$ServerChunkCache$getChunk(chunkSource, pos.x, pos.z, false); + if (levelChunk != null) { + Object[] sections = FastNMS.INSTANCE.method$ChunkAccess$getSections(levelChunk); + CESection[] ceSections = ceChunk.sections(); + for (int i = 0; i < ceSections.length; i++) { + CESection ceSection = ceSections[i]; + Object section = sections[i]; + int finalI = i; + BukkitInjector.injectLevelChunkSection(section, ceSection, ceChunk, new SectionPos(pos.x, ceChunk.sectionY(i), pos.z), + (injected) -> sections[finalI] = injected); + } + } + } + + @Override + public int setBlocks(final Set vset, final Pattern pattern) { + this.processBlocks(vset, pattern); + return super.setBlocks(vset, pattern); + } + + @Override + public int setBlocks(final Region region, final Pattern pattern) { + this.processBlocks(region, pattern); + return super.setBlocks(region, pattern); + } + + @Override + public > int setBlocks(final Region region, final B block) { + this.processBlocks(region, block); + return super.setBlocks(region, block); + } + + @Override + public int replaceBlocks(Region region, Mask mask, Pattern pattern) { + this.processBlocks(region, pattern); + return super.replaceBlocks(region, mask, pattern); + } + + @Override + public > int replaceBlocks(final Region region, final Set filter, final B replacement) { + this.processBlocks(region, replacement); + return super.replaceBlocks(region, filter, replacement); + } + + @Override + public int replaceBlocks(final Region region, final Set filter, final Pattern pattern) { + this.processBlocks(region, pattern); + return super.replaceBlocks(region, filter, pattern); + } + + @Override + public > boolean setBlock(int x, int y, int z, T block) { + BaseBlock oldBlockState = getBlock(x, y, z).toBaseBlock(); + this.processBlock(x, y, z, block.toBaseBlock(), oldBlockState); + return super.setBlock(x, y, z, block); + } + + @Override + public > boolean setBlock(BlockVector3 position, T block) { + BaseBlock oldBlockState = getBlock(position).toBaseBlock(); + this.processBlock(position.x(), position.y(), position.z(), block.toBaseBlock(), oldBlockState); + return super.setBlock(position, block); + } + + @Override + public @Nullable Operation commit() { + Operation operation = super.commit(); + saveAllChunks(); + List chunks = new ArrayList<>(this.brokenChunks); + this.brokenChunks.clear(); + Object worldServer = this.ceWorld.world().serverWorld(); + Object chunkSource = FastNMS.INSTANCE.method$ServerLevel$getChunkSource(worldServer); + for (ChunkPos chunk : chunks) { + CEChunk loaded = this.ceWorld.getChunkAtIfLoaded(chunk.longKey()); + // only inject loaded chunks + if (loaded == null) continue; + injectLevelChunk(chunkSource, loaded); + } + return operation; + } + + private void processBlocks(Iterable region, Pattern pattern) { + for (BlockVector3 position : region) { + BaseBlock blockState = pattern.applyBlock(position); + BaseBlock oldBlockState = getBlock(position).toBaseBlock(); + int blockX = position.x(); + int blockY = position.y(); + int blockZ = position.z(); + this.processBlock(blockX, blockY, blockZ, blockState, oldBlockState); + } + } + + private void processBlock(int blockX, int blockY, int blockZ, BaseBlock newBlock, BaseBlock oldBlock) { + int chunkX = blockX >> 4; + int chunkZ = blockZ >> 4; + int newStateId = ordinalToIbdID[newBlock.getOrdinal()]; + int oldStateId = ordinalToIbdID[oldBlock.getOrdinal()]; + this.brokenChunks.add(ChunkPos.of(chunkX, chunkZ)); + //CraftEngine.instance().debug(() -> "Processing block at " + blockX + ", " + blockY + ", " + blockZ + ": " + oldStateId + " -> " + newStateId); + if (BlockStateUtils.isVanillaBlock(newStateId) && BlockStateUtils.isVanillaBlock(oldStateId)) return; + try { + CEChunk ceChunk = Optional.ofNullable(this.ceWorld.getChunkAtIfLoaded(chunkX, chunkZ)) + .orElse(this.ceWorld.worldDataStorage().readChunkAt(this.ceWorld, new ChunkPos(chunkX, chunkZ))); + ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(newStateId); + if (immutableBlockState == null) { + ceChunk.setBlockState(blockX, blockY, blockZ, EmptyBlock.STATE); + } else { + ceChunk.setBlockState(blockX, blockY, blockZ, immutableBlockState); + } + this.chunksToSave.add(ceChunk); + } catch (IOException e) { + CraftEngine.instance().logger().warn("Error when recording FastAsyncWorldEdit operation blocks", e); + } + } + + private void saveAllChunks() { + try { + for (CEChunk ceChunk : this.chunksToSave) { + CraftEngine.instance().debug(() -> "Saving chunk " + ceChunk.chunkPos()); + this.ceWorld.worldDataStorage().writeChunkAt(ceChunk.chunkPos(), ceChunk); + } + this.chunksToSave.clear(); + } catch (IOException e) { + CraftEngine.instance().logger().warn("Error when recording FastAsyncWorldEdit operation chunks", e); + } + } +} diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/worldedit/WorldEditBlockRegister.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/worldedit/WorldEditBlockRegister.java index 2066c2bc1..dd0951843 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/worldedit/WorldEditBlockRegister.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/worldedit/WorldEditBlockRegister.java @@ -30,8 +30,12 @@ public class WorldEditBlockRegister { this.isFAWE = isFAWE; CEBlockParser blockParser = new CEBlockParser(WorldEdit.getInstance()); WorldEdit.getInstance().getBlockFactory().register(blockParser); + if (isFAWE) { + FastAsyncWorldEditDelegate.init(); + } } + @SuppressWarnings("deprecation") public void register(Key id) throws ReflectiveOperationException { BlockType blockType = new BlockType(id.toString(), blockState -> blockState); this.field$BlockType$blockMaterial.set(blockType, LazyReference.from(() -> new BukkitBlockRegistry.BukkitBlockMaterial(null, Material.STONE))); @@ -45,6 +49,7 @@ public class WorldEditBlockRegister { } @Override + @SuppressWarnings("deprecation") public Stream getSuggestions(String input) { Set namespacesInUse = manager.namespacesInUse(); diff --git a/bukkit/legacy/src/main/java/net/momirealms/craftengine/bukkit/util/LegacyAttributeUtils.java b/bukkit/legacy/src/main/java/net/momirealms/craftengine/bukkit/util/LegacyAttributeUtils.java index 46552b43f..639c83553 100644 --- a/bukkit/legacy/src/main/java/net/momirealms/craftengine/bukkit/util/LegacyAttributeUtils.java +++ b/bukkit/legacy/src/main/java/net/momirealms/craftengine/bukkit/util/LegacyAttributeUtils.java @@ -1,13 +1,20 @@ package net.momirealms.craftengine.bukkit.util; import org.bukkit.attribute.Attribute; +import org.bukkit.attribute.AttributeInstance; import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.Player; import java.util.Objects; +import java.util.Optional; public class LegacyAttributeUtils { public static void setMaxHealth(ArmorStand entity) { Objects.requireNonNull(entity.getAttribute(Attribute.GENERIC_MAX_HEALTH)).setBaseValue(0.01); } + + public static double getLuck(Player player) { + return Optional.ofNullable(player.getAttribute(Attribute.GENERIC_LUCK)).map(AttributeInstance::getValue).orElse(1d); + } } diff --git a/bukkit/loader/build.gradle.kts b/bukkit/loader/build.gradle.kts index a373bbeff..dae694cd2 100644 --- a/bukkit/loader/build.gradle.kts +++ b/bukkit/loader/build.gradle.kts @@ -71,7 +71,7 @@ tasks { relocate("org.apache.commons.io", "net.momirealms.craftengine.libraries.commons.io") relocate("org.bstats", "net.momirealms.craftengine.libraries.bstats") relocate("com.github.benmanes.caffeine", "net.momirealms.craftengine.libraries.caffeine") - relocate("net.objecthunter.exp4j", "net.momirealms.craftengine.libraries.exp4j") + relocate("com.ezylang.evalex", "net.momirealms.craftengine.libraries.evalex") relocate("net.bytebuddy", "net.momirealms.craftengine.libraries.bytebuddy") relocate("org.yaml.snakeyaml", "net.momirealms.craftengine.libraries.snakeyaml") relocate("org.ahocorasick", "net.momirealms.craftengine.libraries.ahocorasick") diff --git a/bukkit/loader/src/main/resources/commands.yml b/bukkit/loader/src/main/resources/commands.yml index be61cd3c6..fdf4e1613 100644 --- a/bukkit/loader/src/main/resources/commands.yml +++ b/bukkit/loader/src/main/resources/commands.yml @@ -168,6 +168,13 @@ debug_target_block: - /craftengine debug target-block - /ce debug target-block +debug_is_section_injected: + enable: true + permission: ce.command.debug.is_section_injected + usage: + - /craftengine debug is-section-injected + - /ce debug is-section-injected + debug_test: enable: true permission: ce.command.debug.test diff --git a/bukkit/loader/src/main/resources/config.yml b/bukkit/loader/src/main/resources/config.yml index da8cf0aa0..297be7fe4 100644 --- a/bukkit/loader/src/main/resources/config.yml +++ b/bukkit/loader/src/main/resources/config.yml @@ -78,6 +78,8 @@ resource-pack: ip: "localhost" port: 8163 protocol: "http" + # The optional URL must be complete and include a trailing slash / at the end. + #url: "http://localhost:8163/" deny-non-minecraft-request: true one-time-token: true rate-limit: @@ -343,16 +345,24 @@ light-system: force-update-light: false chunk-system: - # Unloaded chunks may be loaded soon. Delaying serialization can improve performance, especially for those double-dimension mob farms. - delay-serialization: 20 # seconds -1 = disable + # With cache system, those frequently load/unload chunks would consume fewer resources on serialization + # Enabling this option will increase memory consumption to a certain extent + cache-system: true # 1 = NONE | Compression Speed | Decompress Speed | Compression Ratio | Memory Usage | # 2 = DEFLATE | Medium-Slow Medium Moderate Low | # 3 = GZIP | Medium-Slow Medium Moderate Low | # 4 = LZ4 | Blazing-Fast Blazing-Fast Low Low | # 5 = ZSTD | Medium-Fast Fast High Medium | compression-method: 4 - # This might not work for some server forks that modify how Minecraft saves chunks. - fast-palette-injection: false + # Settings for injection + injection: + # Requires a restart to apply + # SECTION: Inject the LevelChunkSection (Faster & Experimental) since 0.0.53 + # PALETTE: Inject the PalettedContainer + target: PALETTE + # Enables faster injection method + # Note: May not work with certain server forks that alter chunk class structure (In most cases it won't conflict) + use-fast-method: false # Auto-convert custom blocks -> vanilla blocks when unloading chunks # # - When ENABLED (true): diff --git a/bukkit/loader/src/main/resources/craft-engine.properties b/bukkit/loader/src/main/resources/craft-engine.properties index 5901f43dd..c94d83fa0 100644 --- a/bukkit/loader/src/main/resources/craft-engine.properties +++ b/bukkit/loader/src/main/resources/craft-engine.properties @@ -32,4 +32,5 @@ lz4=${lz4_version} netty-codec-http2=${netty_version} reactive-streams=${reactive_streams_version} amazon-sdk-s3=${amazon_awssdk_version} -amazon-sdk-eventstream=${amazon_awssdk_eventstream_version} \ No newline at end of file +amazon-sdk-eventstream=${amazon_awssdk_eventstream_version} +evalex=${evalex_version} \ No newline at end of file diff --git a/bukkit/loader/src/main/resources/todo.yml b/bukkit/loader/src/main/resources/todo.yml deleted file mode 100644 index e487968bc..000000000 --- a/bukkit/loader/src/main/resources/todo.yml +++ /dev/null @@ -1,72 +0,0 @@ -# Stores something that has not been implemented yet - -######################################################################################################################################################################################################################## -# If you want to create more doors, you can use doors of other materials, such as birch. You can only create one custom door from each vanilla door. -# Oak Door -minecraft:oak_door[facing=north,half=lower,hinge=right,open=false,powered=true]: minecraft:oak_door[facing=north,half=lower,hinge=right,open=false,powered=false] -minecraft:oak_door[facing=south,half=lower,hinge=right,open=false,powered=true]: minecraft:oak_door[facing=south,half=lower,hinge=right,open=false,powered=false] -minecraft:oak_door[facing=east,half=lower,hinge=right,open=false,powered=true]: minecraft:oak_door[facing=east,half=lower,hinge=right,open=false,powered=false] -minecraft:oak_door[facing=west,half=lower,hinge=right,open=false,powered=true]: minecraft:oak_door[facing=west,half=lower,hinge=right,open=false,powered=false] -minecraft:oak_door[facing=north,half=lower,hinge=right,open=true,powered=true]: minecraft:oak_door[facing=north,half=lower,hinge=right,open=true,powered=false] -minecraft:oak_door[facing=south,half=lower,hinge=right,open=true,powered=true]: minecraft:oak_door[facing=south,half=lower,hinge=right,open=true,powered=false] -minecraft:oak_door[facing=east,half=lower,hinge=right,open=true,powered=true]: minecraft:oak_door[facing=east,half=lower,hinge=right,open=true,powered=false] -minecraft:oak_door[facing=west,half=lower,hinge=right,open=true,powered=true]: minecraft:oak_door[facing=west,half=lower,hinge=right,open=true,powered=false] -minecraft:oak_door[facing=north,half=lower,hinge=left,open=false,powered=true]: minecraft:oak_door[facing=north,half=lower,hinge=left,open=false,powered=false] -minecraft:oak_door[facing=south,half=lower,hinge=left,open=false,powered=true]: minecraft:oak_door[facing=south,half=lower,hinge=left,open=false,powered=false] -minecraft:oak_door[facing=east,half=lower,hinge=left,open=false,powered=true]: minecraft:oak_door[facing=east,half=lower,hinge=left,open=false,powered=false] -minecraft:oak_door[facing=west,half=lower,hinge=left,open=false,powered=true]: minecraft:oak_door[facing=west,half=lower,hinge=left,open=false,powered=false] -minecraft:oak_door[facing=north,half=lower,hinge=left,open=true,powered=true]: minecraft:oak_door[facing=north,half=lower,hinge=left,open=true,powered=false] -minecraft:oak_door[facing=south,half=lower,hinge=left,open=true,powered=true]: minecraft:oak_door[facing=south,half=lower,hinge=left,open=true,powered=false] -minecraft:oak_door[facing=east,half=lower,hinge=left,open=true,powered=true]: minecraft:oak_door[facing=east,half=lower,hinge=left,open=true,powered=false] -minecraft:oak_door[facing=west,half=lower,hinge=left,open=true,powered=true]: minecraft:oak_door[facing=west,half=lower,hinge=left,open=true,powered=false] -minecraft:oak_door[facing=north,half=upper,hinge=right,open=false,powered=true]: minecraft:oak_door[facing=north,half=upper,hinge=right,open=false,powered=false] -minecraft:oak_door[facing=south,half=upper,hinge=right,open=false,powered=true]: minecraft:oak_door[facing=south,half=upper,hinge=right,open=false,powered=false] -minecraft:oak_door[facing=east,half=upper,hinge=right,open=false,powered=true]: minecraft:oak_door[facing=east,half=upper,hinge=right,open=false,powered=false] -minecraft:oak_door[facing=west,half=upper,hinge=right,open=false,powered=true]: minecraft:oak_door[facing=west,half=upper,hinge=right,open=false,powered=false] -minecraft:oak_door[facing=north,half=upper,hinge=right,open=true,powered=true]: minecraft:oak_door[facing=north,half=upper,hinge=right,open=true,powered=false] -minecraft:oak_door[facing=south,half=upper,hinge=right,open=true,powered=true]: minecraft:oak_door[facing=south,half=upper,hinge=right,open=true,powered=false] -minecraft:oak_door[facing=east,half=upper,hinge=right,open=true,powered=true]: minecraft:oak_door[facing=east,half=upper,hinge=right,open=true,powered=false] -minecraft:oak_door[facing=west,half=upper,hinge=right,open=true,powered=true]: minecraft:oak_door[facing=west,half=upper,hinge=right,open=true,powered=false] -minecraft:oak_door[facing=north,half=upper,hinge=left,open=false,powered=true]: minecraft:oak_door[facing=north,half=upper,hinge=left,open=false,powered=false] -minecraft:oak_door[facing=south,half=upper,hinge=left,open=false,powered=true]: minecraft:oak_door[facing=south,half=upper,hinge=left,open=false,powered=false] -minecraft:oak_door[facing=east,half=upper,hinge=left,open=false,powered=true]: minecraft:oak_door[facing=east,half=upper,hinge=left,open=false,powered=false] -minecraft:oak_door[facing=west,half=upper,hinge=left,open=false,powered=true]: minecraft:oak_door[facing=west,half=upper,hinge=left,open=false,powered=false] -minecraft:oak_door[facing=north,half=upper,hinge=left,open=true,powered=true]: minecraft:oak_door[facing=north,half=upper,hinge=left,open=true,powered=false] -minecraft:oak_door[facing=south,half=upper,hinge=left,open=true,powered=true]: minecraft:oak_door[facing=south,half=upper,hinge=left,open=true,powered=false] -minecraft:oak_door[facing=east,half=upper,hinge=left,open=true,powered=true]: minecraft:oak_door[facing=east,half=upper,hinge=left,open=true,powered=false] -minecraft:oak_door[facing=west,half=upper,hinge=left,open=true,powered=true]: minecraft:oak_door[facing=west,half=upper,hinge=left,open=true,powered=false] -# You can create more trapdoor if you don't care the facing. -# Oak Trapdoor -minecraft:oak_trapdoor[facing=north,open=false,powered=true,waterlogged=false]: minecraft:oak_trapdoor[facing=north,open=false,powered=false,waterlogged=false] -minecraft:oak_trapdoor[facing=north,open=false,powered=true,waterlogged=true]: minecraft:oak_trapdoor[facing=north,open=false,powered=false,waterlogged=true] -minecraft:oak_trapdoor[facing=north,open=true,powered=true,waterlogged=false]: minecraft:oak_trapdoor[facing=north,open=true,powered=false,waterlogged=false] -minecraft:oak_trapdoor[facing=north,open=true,powered=true,waterlogged=true]: minecraft:oak_trapdoor[facing=north,open=true,powered=false,waterlogged=true] -minecraft:oak_trapdoor[facing=south,open=false,powered=true,waterlogged=false]: minecraft:oak_trapdoor[facing=south,open=false,powered=false,waterlogged=false] -minecraft:oak_trapdoor[facing=south,open=false,powered=true,waterlogged=true]: minecraft:oak_trapdoor[facing=south,open=false,powered=false,waterlogged=true] -minecraft:oak_trapdoor[facing=south,open=true,powered=true,waterlogged=false]: minecraft:oak_trapdoor[facing=south,open=true,powered=false,waterlogged=false] -minecraft:oak_trapdoor[facing=south,open=true,powered=true,waterlogged=true]: minecraft:oak_trapdoor[facing=south,open=true,powered=false,waterlogged=true] -minecraft:oak_trapdoor[facing=east,open=false,powered=true,waterlogged=false]: minecraft:oak_trapdoor[facing=east,open=false,powered=false,waterlogged=false] -minecraft:oak_trapdoor[facing=east,open=false,powered=true,waterlogged=true]: minecraft:oak_trapdoor[facing=east,open=false,powered=false,waterlogged=true] -minecraft:oak_trapdoor[facing=east,open=true,powered=true,waterlogged=false]: minecraft:oak_trapdoor[facing=east,open=true,powered=false,waterlogged=false] -minecraft:oak_trapdoor[facing=east,open=true,powered=true,waterlogged=true]: minecraft:oak_trapdoor[facing=east,open=true,powered=false,waterlogged=true] -minecraft:oak_trapdoor[facing=west,open=false,powered=true,waterlogged=false]: minecraft:oak_trapdoor[facing=west,open=false,powered=false,waterlogged=false] -minecraft:oak_trapdoor[facing=west,open=false,powered=true,waterlogged=true]: minecraft:oak_trapdoor[facing=west,open=false,powered=false,waterlogged=true] -minecraft:oak_trapdoor[facing=west,open=true,powered=true,waterlogged=false]: minecraft:oak_trapdoor[facing=west,open=true,powered=false,waterlogged=false] -minecraft:oak_trapdoor[facing=west,open=true,powered=true,waterlogged=true]: minecraft:oak_trapdoor[facing=west,open=true,powered=false,waterlogged=true] -# fence_gate -minecraft:oak_fence_gate[facing=north,open=false,powered=true,in_wall=false]: minecraft:oak_fence_gate[facing=north,open=false,powered=false,in_wall=false] -minecraft:oak_fence_gate[facing=north,open=false,powered=true,in_wall=true]: minecraft:oak_fence_gate[facing=north,open=false,powered=false,in_wall=true] -minecraft:oak_fence_gate[facing=north,open=true,powered=true,in_wall=false]: minecraft:oak_fence_gate[facing=north,open=true,powered=false,in_wall=false] -minecraft:oak_fence_gate[facing=north,open=true,powered=true,in_wall=true]: minecraft:oak_fence_gate[facing=north,open=true,powered=false,in_wall=true] -minecraft:oak_fence_gate[facing=south,open=false,powered=true,in_wall=false]: minecraft:oak_fence_gate[facing=south,open=false,powered=false,in_wall=false] -minecraft:oak_fence_gate[facing=south,open=false,powered=true,in_wall=true]: minecraft:oak_fence_gate[facing=south,open=false,powered=false,in_wall=true] -minecraft:oak_fence_gate[facing=south,open=true,powered=true,in_wall=false]: minecraft:oak_fence_gate[facing=south,open=true,powered=false,in_wall=false] -minecraft:oak_fence_gate[facing=south,open=true,powered=true,in_wall=true]: minecraft:oak_fence_gate[facing=south,open=true,powered=false,in_wall=true] -minecraft:oak_fence_gate[facing=east,open=false,powered=true,in_wall=false]: minecraft:oak_fence_gate[facing=east,open=false,powered=false,in_wall=false] -minecraft:oak_fence_gate[facing=east,open=false,powered=true,in_wall=true]: minecraft:oak_fence_gate[facing=east,open=false,powered=false,in_wall=true] -minecraft:oak_fence_gate[facing=east,open=true,powered=true,in_wall=false]: minecraft:oak_fence_gate[facing=east,open=true,powered=false,in_wall=false] -minecraft:oak_fence_gate[facing=east,open=true,powered=true,in_wall=true]: minecraft:oak_fence_gate[facing=east,open=true,powered=false,in_wall=true] -minecraft:oak_fence_gate[facing=west,open=false,powered=true,in_wall=false]: minecraft:oak_fence_gate[facing=west,open=false,powered=false,in_wall=false] -minecraft:oak_fence_gate[facing=west,open=false,powered=true,in_wall=true]: minecraft:oak_fence_gate[facing=west,open=false,powered=false,in_wall=true] -minecraft:oak_fence_gate[facing=west,open=true,powered=true,in_wall=false]: minecraft:oak_fence_gate[facing=west,open=true,powered=false,in_wall=false] -minecraft:oak_fence_gate[facing=west,open=true,powered=true,in_wall=true]: minecraft:oak_fence_gate[facing=west,open=true,powered=false,in_wall=true] diff --git a/bukkit/loader/src/main/resources/translations/en.yml b/bukkit/loader/src/main/resources/translations/en.yml index 7b9afee86..ff18b0826 100644 --- a/bukkit/loader/src/main/resources/translations/en.yml +++ b/bukkit/loader/src/main/resources/translations/en.yml @@ -1,7 +1,6 @@ # Don't change this lang-version: "${lang_version}" -# Commands exception.invalid_syntax: "Invalid syntax. Correct syntax: " exception.invalid_argument: "Invalid argument. Reason: " exception.invalid_sender: " is not allowed to execute that command. Must be of type " @@ -70,6 +69,27 @@ warning.config.type.float: "Issue found in file - Failed to load warning.config.type.double: "Issue found in file - Failed to load '': Cannot cast '' to double type for option ''." warning.config.type.quaternionf: "Issue found in file - Failed to load '': Cannot cast '' to Quaternionf type for option ''." warning.config.type.vector3f: "Issue found in file - Failed to load '': Cannot cast '' to Vector3f type for option ''." +warning.config.number.missing_type: "Issue found in file - The config '' is missing the required 'type' argument for number argument." +warning.config.number.invalid_type: "Issue found in file - The config '' is using an invalid number argument type ''." +warning.config.number.missing_argument: "Issue found in file - The config '' is missing the argument for 'number'." +warning.config.number.invalid_format: "Issue found in file - The config '' is using an invalid number format ''." +warning.config.number.fixed.missing_value: "Issue found in file - The config '' is missing the required 'value' argument for 'constant' number." +warning.config.number.fixed.invalid_value: "Issue found in file - The config '' is using the invalid 'value' argument '' for 'constant' number." +warning.config.number.expression.missing_expression: "Issue found in file - The config '' is missing the required 'expression' argument for 'expression' number." +warning.config.number.uniform.missing_min: "Issue found in file - The config '' is missing the required 'min' argument for 'uniform' number." +warning.config.number.uniform.missing_max: "Issue found in file - The config '' is missing the required 'max' argument for 'uniform' number." +warning.config.condition.all_of.missing_terms: "Issue found in file - The config '' is missing the required 'terms' argument for 'all_of' condition." +warning.config.condition.all_of.invalid_terms_type: "Issue found in file - The config '' has a misconfigured 'all_of' condition, 'terms' should be a map list, current type: ''." +warning.config.condition.any_of.missing_terms: "Issue found in file - The config '' is missing the required 'terms' argument for 'any_of' condition." +warning.config.condition.any_of.invalid_terms_type: "Issue found in file - The config '' has a misconfigured 'any_of' condition, 'terms' should be a map list, current type: ''." +warning.config.condition.inverted.missing_term: "Issue found in file - The config '' is missing the required 'term' argument for 'inverted' condition." +warning.config.condition.inverted.invalid_term_type: "Issue found in file - The config '' has a misconfigured 'inverted' condition, 'term' should be a config section, current type: ''." +warning.config.condition.enchantment.missing_predicate: "Issue found in file - The config '' is missing the required 'predicate' argument for 'enchantment' condition." +warning.config.condition.enchantment.invalid_predicate: "Issue found in file - The config '' is using an invalid enchantment 'predicate' argument ''." +warning.config.condition.match_block_property.missing_properties: "Issue found in file - The config '' is missing the required 'properties' argument for 'match_block_property' condition." +warning.config.condition.match_item.missing_id: "Issue found in file - The config '' is missing the required 'id' argument for 'match_item' condition." +warning.config.condition.table_bonus.missing_enchantment: "Issue found in file - The config '' is missing the required 'enchantment' argument for 'table_bonus' condition." +warning.config.condition.table_bonus.missing_chances: "Issue found in file - The config '' is missing the required 'chances' argument for 'table_bonus' condition." warning.config.structure.not_section: "Issue found in file - The config '' is expected to be a config section while it's actually a(n) ''." warning.config.image.duplicate: "Issue found in file - Duplicated image ''. Please check if there is the same configuration in other files." warning.config.image.missing_height: "Issue found in file - The image '' is missing the required 'height' argument." @@ -80,6 +100,7 @@ warning.config.image.invalid_font_chars: "Issue found in file - warning.config.image.missing_char: "Issue found in file - The image '' is missing the required 'char' argument." warning.config.image.codepoint_conflict: "Issue found in file - The image '' is using a character '()' in font that has been used by another image ''." warning.config.image.invalid_codepoint_grid: "Issue found in file - Image '' has an invalid 'chars' codepoint grid." +warning.config.image.invalid_char: "Issue found in file - Image '' has a char parameter containing combining characters, which may result in image splitting." warning.config.image.file_not_found: "Issue found in file - PNG file '' not found for image ''." warning.config.image.invalid_hex_value: "Issue found in file - The image '' is using a unicode character '' that is not a valid hexadecimal (radix 16) value." warning.config.recipe.duplicate: "Issue found in file - Duplicated recipe ''. Please check if there is the same configuration in other files." @@ -202,6 +223,8 @@ warning.config.block.behavior.leaves.missing_distance: "Issue found in f warning.config.block.behavior.sapling.missing_stage: "Issue found in file - The block '' is missing the required 'stage' property for 'sapling_block' behavior." warning.config.block.behavior.sapling.missing_feature: "Issue found in file - The block '' is missing the required 'feature' argument for 'sapling_block' behavior." warning.config.block.behavior.strippable.missing_stripped: "Issue found in file - The block '' is missing the required 'stripped' argument for 'strippable_block' behavior." +warning.config.block.event.condition.missing_type: "Issue found in file - The block '' is missing the required 'type' argument for event condition." +warning.config.block.event.condition.invalid_type: "Issue found in file - The block '' is using an invalid 'type' argument '' for event condition." warning.config.model.generation.missing_parent: "Issue found in file - The config '' is missing the required 'parent' argument in 'generation' section." warning.config.model.generation.conflict: "Issue found in file - Failed to generate model for '' as two or more configurations attempt to generate different json models with the same path: ''." warning.config.model.generation.texture.invalid: "Issue found in file - The config '' has a texture '' with path '' that contains illegal characters. Please read https://minecraft.wiki/w/Resource_location#Legal_characters." @@ -227,10 +250,6 @@ warning.config.loot_table.entry.exp.missing_count: "Issue found in file warning.config.loot_table.entry.item.missing_item: "Issue found in file - '' has a misconfigured loot table, entry 'item' is missing the required 'item' argument." warning.config.loot_table.condition.missing_type: "Issue found in file - '' has a misconfigured loot table, one of the conditions is missing the required 'type' argument." warning.config.loot_table.condition.invalid_type: "Issue found in file - '' has a misconfigured loot table, one of the conditions is using an invalid condition type ''." -warning.config.loot_table.condition.table_bonus.missing_enchantment: "Issue found in file - '' has a misconfigured loot table, 'table_bonus' condition is missing the required 'enchantment' argument." -warning.config.loot_table.condition.table_bonus.missing_chances: "Issue found in file - '' has a misconfigured loot table, 'table_bonus' condition is missing the required 'chances' argument." -warning.config.loot_table.number.missing_type: "Issue found in file - '' has a misconfigured loot table, one of the numbers is missing the required 'type' argument." -warning.config.loot_table.number.invalid_type: "Issue found in file - '' has a misconfigured loot table, one of the numbers is using an invalid number type ''." warning.config.host.missing_type: "Issue found in config.yml at 'resource-pack.delivery.hosting' - Missing required 'type' argument for host." warning.config.host.invalid_type: "Issue found in config.yml at 'resource-pack.delivery.hosting' - Host type '' is invalid. Please read https://mo-mi.gitbook.io/xiaomomi-plugins/craftengine/plugin-wiki/craftengine/resource-pack/host." warning.config.host.external.missing_url: "Issue found in config.yml at 'resource-pack.delivery.hosting' - Missing required 'url' argument for external host." @@ -254,6 +273,7 @@ warning.config.host.s3.missing_secret: "Issue found in config.yml at 're warning.config.host.s3.missing_upload_path: "Issue found in config.yml at 'resource-pack.delivery.hosting' - Missing required 'upload-path' argument for s3 host." warning.config.host.self.missing_ip: "Issue found in config.yml at 'resource-pack.delivery.hosting' - Missing required 'ip' argument for self host." warning.config.host.self.invalid_port: "Issue found in config.yml at 'resource-pack.delivery.hosting' - Invalid port '' for self host." +warning.config.host.self.invalid_url: "Issue found in config.yml at 'resource-pack.delivery.hosting' - Invalid url '' for self host." warning.config.host.gitlab.missing_url: "Issue found in config.yml at 'resource-pack.delivery.hosting' - Missing required 'gitlab-url' argument for gitlab host." warning.config.host.gitlab.missing_token: "Issue found in config.yml at 'resource-pack.delivery.hosting' - Missing required 'access-token' argument for gitlab host." warning.config.host.gitlab.missing_project: "Issue found in config.yml at 'resource-pack.delivery.hosting' - Missing required 'project-id' argument for gitlab host." @@ -273,4 +293,5 @@ warning.config.conflict_matcher.inverted.missing_term: "Issue found in c warning.config.conflict_matcher.all_of.missing_terms: "Issue found in config.yml at 'resource-pack.duplicated-files-handler' - Missing required 'terms' argument for 'all_of' matcher." warning.config.conflict_matcher.any_of.missing_terms: "Issue found in config.yml at 'resource-pack.duplicated-files-handler' - Missing required 'terms' argument for 'any_of' matcher." warning.config.conflict_resolution.missing_type: "Issue found in config.yml at 'resource-pack.duplicated-files-handler' - Missing required 'type' argument for one of the resolutions." -warning.config.conflict_resolution.invalid_type: "Issue found in config.yml at 'resource-pack.duplicated-files-handler' - One of the resolutions is using the invalid type ''." \ No newline at end of file +warning.config.conflict_resolution.invalid_type: "Issue found in config.yml at 'resource-pack.duplicated-files-handler' - One of the resolutions is using the invalid type ''." +warning.config.function.command.missing_command: "Issue found in file - The config '' is missing the required 'command' argument for 'command' function." \ No newline at end of file diff --git a/bukkit/loader/src/main/resources/translations/tr.yml b/bukkit/loader/src/main/resources/translations/tr.yml index 7eadf3d06..def783519 100644 --- a/bukkit/loader/src/main/resources/translations/tr.yml +++ b/bukkit/loader/src/main/resources/translations/tr.yml @@ -1,6 +1,6 @@ # Don't change this lang-version: "${lang_version}" -# Commands + exception.invalid_syntax: "Geçersiz sözdizimi. Doğru kullanım: " exception.invalid_argument: "Geçersiz argüman. Neden: " exception.invalid_sender: " bu komutu çalıştırmaya yetkili değil. türünde olmalı" @@ -226,10 +226,6 @@ warning.config.loot_table.entry.exp.missing_count: " dosyasında warning.config.loot_table.entry.item.missing_item: " dosyasında sorun bulundu - '', yanlış yapılandırılmış bir ganimet tablosuna sahip, 'item' girişi için gerekli 'item' argümanı eksik." warning.config.loot_table.condition.missing_type: " dosyasında sorun bulundu - '', yanlış yapılandırılmış bir ganimet tablosuna sahip, koşullardan biri için gerekli 'type' argümanı eksik." warning.config.loot_table.condition.invalid_type: " dosyasında sorun bulundu - '', yanlış yapılandırılmış bir ganimet tablosuna sahip, koşullardan biri geçersiz bir koşul türü '' kullanıyor." -warning.config.loot_table.condition.table_bonus.missing_enchantment: " dosyasında sorun bulundu - '', yanlış yapılandırılmış bir ganimet tablosuna sahip, 'table_bonus' koşulu için gerekli 'enchantment' argümanı eksik." -warning.config.loot_table.condition.table_bonus.missing_chances: " dosyasında sorun bulundu - '', yanlış yapılandırılmış bir ganimet tablosuna sahip, 'table_bonus' koşulu için gerekli 'chances' argümanı eksik." -warning.config.loot_table.number.missing_type: " dosyasında sorun bulundu - '', yanlış yapılandırılmış bir ganimet tablosuna sahip, sayılardan biri için gerekli 'type' argümanı eksik." -warning.config.loot_table.number.invalid_type: " dosyasında sorun bulundu - '', yanlış yapılandırılmış bir ganimet tablosuna sahip, sayılardan biri geçersiz bir sayı türü '' kullanıyor." warning.config.host.missing_type: "config.yml dosyasında 'resource-pack.delivery.hosting' bölümünde sorun bulundu - Host için gerekli 'type' argümanı eksik." warning.config.host.invalid_type: "config.yml dosyasında 'resource-pack.delivery.hosting' bölümünde sorun bulundu - Host türü '' geçersiz. Lütfen https://mo-mi.gitbook.io/xiaomomi-plugins/craftengine/plugin-wiki/craftengine/resource-pack/host sayfasını okuyun." warning.config.host.external.missing_url: "config.yml dosyasında 'resource-pack.delivery.hosting' bölümünde sorun bulundu - Harici host için gerekli 'url' argümanı eksik." @@ -272,4 +268,4 @@ warning.config.conflict_matcher.inverted.missing_term: "config.yml dosya warning.config.conflict_matcher.all_of.missing_terms: "config.yml dosyasında 'resource-pack.duplicated-files-handler' bölümünde sorun bulundu - 'all_of' eşleştiricisi için gerekli 'terms' argümanı eksik." warning.config.conflict_matcher.any_of.missing_terms: "config.yml dosyasında 'resource-pack.duplicated-files-handler' bölümünde sorun bulundu - 'any_of' eşleştiricisi için gerekli 'terms' argümanı eksik." warning.config.conflict_resolution.missing_type: "config.yml dosyasında 'resource-pack.duplicated-files-handler' bölümünde sorun bulundu - Çözümlerden biri için gerekli 'type' argümanı eksik." -warning.config.conflict_resolution.invalid_type: "config.yml dosyasında 'resource-pack.duplicated-files-handler' bölümünde sorun bulundu - Çözümlerden biri geçersiz bir tür '' kullanıyor." +warning.config.conflict_resolution.invalid_type: "config.yml dosyasında 'resource-pack.duplicated-files-handler' bölümünde sorun bulundu - Çözümlerden biri geçersiz bir tür '' kullanıyor." \ No newline at end of file diff --git a/bukkit/loader/src/main/resources/translations/zh_cn.yml b/bukkit/loader/src/main/resources/translations/zh_cn.yml index 860a110af..d2e6ed5f9 100644 --- a/bukkit/loader/src/main/resources/translations/zh_cn.yml +++ b/bukkit/loader/src/main/resources/translations/zh_cn.yml @@ -1,7 +1,6 @@ # 别动这个 lang-version: "${lang_version}" -# 命令 exception.invalid_syntax: "无效语法. 正确语法: " exception.invalid_argument: "无效参数. 原因: " exception.invalid_sender: " 不允许执行该命令. 执行者必须是 " @@ -40,11 +39,11 @@ argument.parse.failure.aggregate.failure: "无效的组件 '': 无法从 '' 解析 " argument.parse.failure.namedtextcolor: "'' 不是颜色代码" command.reload.config.success: "重新加载配置完成. 耗时 毫秒 (异步: ms | 同步: ms)" -command.reload.config.failure: "重新加载配置失败,请检查控制台日志" +command.reload.config.failure: "重新加载配置失败, 请检查控制台日志" command.reload.pack.success: "资源包重新加载完成. 耗时 毫秒" -command.reload.pack.failure: "重新加载资源包失败,请检查控制台日志" +command.reload.pack.failure: "重新加载资源包失败, 请检查控制台日志" command.reload.all.success: "全部重新加载完成. 耗时 毫秒 (异步: ms | 同步: ms | 资源包: ms)" -command.reload.all.failure: "重新加载失败,请检查控制台日志" +command.reload.all.failure: "重新加载失败, 请检查控制台日志" command.item.get.success: "获得" command.item.get.failure.not_exist: "'>" command.item.give.success.single: "':'':''>" @@ -70,6 +69,27 @@ warning.config.type.float: "在文件 发现问题 - 无法加 warning.config.type.double: "在文件 发现问题 - 无法加载 '': 无法将 '' 转换为双精度类型 (选项 '')" warning.config.type.quaternionf: "在文件 发现问题 - 无法加载 '': 无法将 '' 转换为四元数类型 (选项 '')" warning.config.type.vector3f: "在文件 发现问题 - 无法加载 '': 无法将 '' 转换为三维向量类型 (选项 '')" +warning.config.number.missing_type: "在文件 发现问题 - 配置项 '' 缺少数字类型所需的 'type' 参数" +warning.config.number.invalid_type: "在文件 发现问题 - 配置项 '' 使用了无效的数字类型 ''" +warning.config.number.missing_argument: "在文件 发现问题 - 配置项 '' 缺少数字参数" +warning.config.number.invalid_format: "在文件 发现问题 - 配置项 '' 使用了无效的数字格式 ''" +warning.config.number.fixed.missing_value: "在文件 发现问题 - 配置项 '' 缺少 'constant' 数字类型所需的 'value' 参数" +warning.config.number.fixed.invalid_value: "在文件 发现问题 - 配置项 '' 使用了无效的常量值参数 ''" +warning.config.number.expression.missing_expression: "在文件 发现问题 - 配置项 '' 缺少 'expression' 数字类型所需的 'expression' 参数" +warning.config.number.uniform.missing_min: "在文件 发现问题 - 配置项 '' 缺少 'uniform' 数字类型所需的 'min' 参数" +warning.config.number.uniform.missing_max: "在文件 发现问题 - 配置项 '' 缺少 'uniform' 数字类型所需的 'max' 参数" +warning.config.condition.all_of.missing_terms: "在文件 发现问题 - 配置项 '' 缺少 'all_of' 条件所需的 'terms' 参数" +warning.config.condition.all_of.invalid_terms_type: "在文件 发现问题 - 配置项 '' 的 'all_of' 条件配置错误, 'terms' 应为映射列表, 当前类型: ''" +warning.config.condition.any_of.missing_terms: "在文件 发现问题 - 配置项 '' 缺少 'any_of' 条件所需的 'terms' 参数" +warning.config.condition.any_of.invalid_terms_type: "在文件 发现问题 - 配置项 '' 的 'any_of' 条件配置错误, 'terms' 应为映射列表, 当前类型: ''" +warning.config.condition.inverted.missing_term: "在文件 发现问题 - 配置项 '' 缺少 'inverted' 条件所需的 'term' 参数" +warning.config.condition.inverted.invalid_term_type: "在文件 发现问题 - 配置项 '' 的 'inverted' 条件配置错误, 'term' 应为配置节点, 当前类型: ''" +warning.config.condition.enchantment.missing_predicate: "在文件 发现问题 - 配置项 '' 缺少 'enchantment' 条件所需的 'predicate' 参数" +warning.config.condition.enchantment.invalid_predicate: "在文件 发现问题 - 配置项 '' 使用了无效的附魔 'predicate' 参数 ''" +warning.config.condition.match_block_property.missing_properties: "在文件 发现问题 - 配置项 '' 缺少 'match_block_property' 条件所需的 'properties' 参数" +warning.config.condition.match_item.missing_id: "在文件 发现问题 - 配置项 '' 缺少 'match_item' 条件所需的 'id' 参数" +warning.config.condition.table_bonus.missing_enchantment: "在文件 发现问题 - 配置项 '' 缺少 'table_bonus' 条件所需的 'enchantment' 参数" +warning.config.condition.table_bonus.missing_chances: "在文件 发现问题 - 配置项 '' 缺少 'table_bonus' 条件所需的 'chances' 参数" warning.config.structure.not_section: "在文件 发现问题 - 配置项 '' 应为配置段落 但实际类型为 ''" warning.config.image.duplicate: "在文件 发现问题 - 重复的图片配置 '' 请检查其他文件中是否存在相同配置" warning.config.image.missing_height: "在文件 发现问题 - 图片 '' 缺少必需的 'height' 参数" @@ -80,6 +100,7 @@ warning.config.image.invalid_font_chars: "在文件 发现问题 warning.config.image.missing_char: "在文件 发现问题 - 图片 '' 缺少必需的 'char' 参数" warning.config.image.codepoint_conflict: "在文件 发现问题 - 图片 '' 在字体 中使用的字符 '()' 已被其他图片 '' 占用" warning.config.image.invalid_codepoint_grid: "在文件 发现问题 - 图片 '' 的 'chars' 码位网格无效" +warning.config.image.invalid_char: "在文件 发现问题 - 图片 '' 的 'char' 参数包含组合字符可能导致图片分裂" warning.config.image.file_not_found: "在文件 发现问题 - 图片 '' 的 PNG 文件 '' 未找到" warning.config.image.invalid_hex_value: "在文件 发现问题 - 图片 '' 使用的 Unicode 字符 '' 不是有效的十六进制值" warning.config.recipe.duplicate: "在文件 发现问题 - 重复的配方 '' 请检查其他文件中是否存在相同配置" @@ -202,6 +223,8 @@ warning.config.block.behavior.leaves.missing_distance: "在文件 在文件 发现问题 - 方块 '' 的 'sapling_block' 行为缺少必需的 'stage' 属性" warning.config.block.behavior.sapling.missing_feature: "在文件 发现问题 - 方块 '' 的 'sapling_block' 行为缺少必需的 'feature' 参数" warning.config.block.behavior.strippable.missing_stripped: "在文件 发现问题 - 方块 '' 的 'strippable_block' 行为缺少必需的 'stripped' 参数" +warning.config.block.event.condition.missing_type: "在文件 - 方块 '' 的事件条件缺少 'type' 参数" +warning.config.block.event.condition.invalid_type: "在文件 - 方块 '' 使用了无效的事件条件类型 ''" warning.config.model.generation.missing_parent: "在文件 发现问题 - 配置项 '' 的 'generation' 段落缺少必需的 'parent' 参数" warning.config.model.generation.conflict: "在文件 发现问题 - 无法为 '' 生成模型 存在多个配置尝试使用相同路径 '' 生成不同的 JSON 模型" warning.config.model.generation.texture.invalid: "在文件 发现问题 - 配置项 '' 的纹理 '' 路径 '' 包含非法字符 请参考 https://zh.minecraft.wiki/w/%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4ID#%E5%90%88%E6%B3%95%E5%AD%97%E7%AC%A6" @@ -227,10 +250,6 @@ warning.config.loot_table.entry.exp.missing_count: "在文件 warning.config.loot_table.entry.item.missing_item: "在文件 发现问题 - '' 的战利品表配置错误 'item' 条目缺少必需的 'item' 参数" warning.config.loot_table.condition.missing_type: "在文件 发现问题 - '' 的战利品表配置错误 某个条件缺少必需的 'type' 参数" warning.config.loot_table.condition.invalid_type: "在文件 发现问题 - '' 的战利品表配置错误 某个条件使用了无效的条件类型 ''" -warning.config.loot_table.condition.table_bonus.missing_enchantment: "在文件 发现问题 - '' 的战利品表配置错误 'table_bonus' 条件缺少必需的 'enchantment' 参数" -warning.config.loot_table.condition.table_bonus.missing_chances: "在文件 发现问题 - '' 的战利品表配置错误 'table_bonus' 条件缺少必需的 'chances' 参数" -warning.config.loot_table.number.missing_type: "在文件 发现问题 - '' 的战利品表配置错误 某个数值缺少必需的 'type' 参数" -warning.config.loot_table.number.invalid_type: "在文件 发现问题 - '' 的战利品表配置错误 某个数值使用了无效的数值类型 ''" warning.config.host.missing_type: "在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - 缺少必需的 'type' 参数" warning.config.host.invalid_type: "在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - 无效的托管类型 '' 请参考 https://mo-mi.gitbook.io/xiaomomi-plugins/craftengine/plugin-wiki/craftengine/resource-pack/host" warning.config.host.external.missing_url: "在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - 外部托管缺少必需的 'url' 参数" @@ -254,6 +273,7 @@ warning.config.host.s3.missing_secret: "在 config.yml 的 'resource-pac warning.config.host.s3.missing_upload_path: "在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - S3 托管缺少必需的 'upload-path' 参数" warning.config.host.self.missing_ip: "在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - 自托管托管缺少必需的 'ip' 参数" warning.config.host.self.invalid_port: "在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - 自托管托管的端口 '' 无效" +warning.config.host.self.invalid_url: "在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - 自托管托管的 URL '' 无效" warning.config.host.gitlab.missing_url: "在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - GitLab 托管缺少必需的 'gitlab-url' 参数" warning.config.host.gitlab.missing_token: "在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - GitLab 托管缺少必需的 'access-token' 参数" warning.config.host.gitlab.missing_project: "在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - GitLab 托管缺少必需的 'project-id' 参数" diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/BukkitAdaptors.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/BukkitAdaptors.java index d49ca44c8..f11ae4be3 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/BukkitAdaptors.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/BukkitAdaptors.java @@ -3,8 +3,8 @@ package net.momirealms.craftengine.bukkit.api; import net.momirealms.craftengine.bukkit.entity.BukkitEntity; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; +import net.momirealms.craftengine.bukkit.world.BukkitBlockInWorld; import net.momirealms.craftengine.bukkit.world.BukkitWorld; -import net.momirealms.craftengine.bukkit.world.BukkitWorldBlock; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.entity.Entity; @@ -26,7 +26,7 @@ public final class BukkitAdaptors { return new BukkitEntity(entity); } - public static BukkitWorldBlock adapt(final Block block) { - return new BukkitWorldBlock(block); + public static BukkitBlockInWorld adapt(final Block block) { + return new BukkitBlockInWorld(block); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java index 7b8467ea5..17a8d21b4 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java @@ -10,11 +10,10 @@ import net.momirealms.craftengine.bukkit.world.BukkitWorld; import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.UpdateOption; -import net.momirealms.craftengine.core.entity.player.InteractionHand; import net.momirealms.craftengine.core.item.Item; -import net.momirealms.craftengine.core.loot.parameter.LootParameters; +import net.momirealms.craftengine.core.plugin.context.ContextHolder; +import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.context.ContextHolder; import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.core.world.World; import net.momirealms.craftengine.core.world.WorldEvents; @@ -172,13 +171,13 @@ public final class CraftEngineBlocks { Location location = block.getLocation(); Vec3d vec3d = new Vec3d(location.getBlockX() + 0.5, location.getBlockY() + 0.5, location.getBlockZ() + 0.5); if (dropLoot) { - ContextHolder.Builder builder = new ContextHolder.Builder().withParameter(LootParameters.WORLD, world).withParameter(LootParameters.LOCATION, vec3d); + ContextHolder.Builder builder = new ContextHolder.Builder().withParameter(CommonParameters.WORLD, world).withParameter(CommonParameters.LOCATION, vec3d); BukkitServerPlayer serverPlayer = BukkitCraftEngine.instance().adapt(player); if (player != null) { - builder.withParameter(LootParameters.PLAYER, serverPlayer); - builder.withOptionalParameter(LootParameters.TOOL, serverPlayer.getItemInHand(InteractionHand.MAIN_HAND)); + builder.withParameter(CommonParameters.PLAYER, serverPlayer); + //mark item builder.withOptionalParameter(CommonParameters.MAIN_HAND_ITEM, serverPlayer.getItemInHand(InteractionHand.MAIN_HAND)); } - for (Item item : state.getDrops(builder, world)) { + for (Item item : state.getDrops(builder, world, serverPlayer)) { world.dropItemNaturally(vec3d, item); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineFurniture.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineFurniture.java index 4abf9bbab..134fda9a6 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineFurniture.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineFurniture.java @@ -9,12 +9,11 @@ import net.momirealms.craftengine.bukkit.util.LocationUtils; import net.momirealms.craftengine.bukkit.world.BukkitWorld; import net.momirealms.craftengine.core.entity.furniture.AnchorType; import net.momirealms.craftengine.core.entity.furniture.CustomFurniture; -import net.momirealms.craftengine.core.entity.player.InteractionHand; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.loot.LootTable; -import net.momirealms.craftengine.core.loot.parameter.LootParameters; +import net.momirealms.craftengine.core.plugin.context.ContextHolder; +import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.context.ContextHolder; import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.core.world.World; import org.bukkit.Location; @@ -271,13 +270,13 @@ public final class CraftEngineFurniture { World world = new BukkitWorld(location.getWorld()); if (dropLoot && lootTable != null) { ContextHolder.Builder builder = ContextHolder.builder(); - builder.withParameter(LootParameters.LOCATION, vec3d); - builder.withParameter(LootParameters.WORLD, world); + builder.withParameter(CommonParameters.LOCATION, vec3d); + builder.withParameter(CommonParameters.WORLD, world); if (player != null) { - builder.withParameter(LootParameters.PLAYER, player); - builder.withOptionalParameter(LootParameters.TOOL, player.getItemInHand(InteractionHand.MAIN_HAND)); + builder.withParameter(CommonParameters.PLAYER, player); + //mark item builder.withOptionalParameter(CommonParameters.MAIN_HAND_ITEM, player.getItemInHand(InteractionHand.MAIN_HAND)); } - List> items = lootTable.getRandomItems(builder.build(), world); + List> items = lootTable.getRandomItems(builder.build(), world, player); for (Item item : items) { world.dropItemNaturally(vec3d, item); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java index 6b4dcd633..a31e0023a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java @@ -12,10 +12,10 @@ import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.entity.player.InteractionHand; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.loot.LootTable; -import net.momirealms.craftengine.core.loot.parameter.LootParameters; import net.momirealms.craftengine.core.plugin.config.Config; +import net.momirealms.craftengine.core.plugin.context.ContextHolder; +import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; import net.momirealms.craftengine.core.util.VersionHelper; -import net.momirealms.craftengine.core.util.context.ContextHolder; import net.momirealms.craftengine.core.world.BlockPos; import net.momirealms.craftengine.core.world.Vec3d; import org.bukkit.*; @@ -150,12 +150,12 @@ public class BlockEventListener implements Listener { } // drop items - ContextHolder.Builder builder = ContextHolder.builder(); - builder.withParameter(LootParameters.WORLD, world); - builder.withParameter(LootParameters.LOCATION, vec3d); - builder.withParameter(LootParameters.PLAYER, serverPlayer); - builder.withOptionalParameter(LootParameters.TOOL, itemInHand); - for (Item item : state.getDrops(builder, world)) { + ContextHolder.Builder builder = ContextHolder.builder() + .withParameter(CommonParameters.WORLD, world) + .withParameter(CommonParameters.LOCATION, vec3d) + .withParameter(CommonParameters.PLAYER, serverPlayer); + //mark item .withOptionalParameter(CommonParameters.MAIN_HAND_ITEM, itemInHand); + for (Item item : state.getDrops(builder, world, serverPlayer)) { world.dropItemNaturally(vec3d, item); } } @@ -171,14 +171,14 @@ public class BlockEventListener implements Listener { BukkitServerPlayer serverPlayer = this.plugin.adapt(player); net.momirealms.craftengine.core.world.World world = new BukkitWorld(player.getWorld()); Vec3d vec3d = new Vec3d(location.getBlockX() + 0.5, location.getBlockY() + 0.5, location.getBlockZ() + 0.5); - ContextHolder.Builder builder = ContextHolder.builder(); - builder.withParameter(LootParameters.WORLD, world); - builder.withParameter(LootParameters.LOCATION, vec3d); - builder.withParameter(LootParameters.PLAYER, serverPlayer); - builder.withOptionalParameter(LootParameters.TOOL, serverPlayer.getItemInHand(InteractionHand.MAIN_HAND)); + ContextHolder.Builder builder = ContextHolder.builder() + .withParameter(CommonParameters.WORLD, world) + .withParameter(CommonParameters.LOCATION, vec3d) + .withParameter(CommonParameters.PLAYER, serverPlayer); + //mark item .withOptionalParameter(CommonParameters.MAIN_HAND_ITEM, serverPlayer.getItemInHand(InteractionHand.MAIN_HAND)); ContextHolder contextHolder = builder.build(); for (LootTable lootTable : it.lootTables()) { - for (Item item : lootTable.getRandomItems(contextHolder, world)) { + for (Item item : lootTable.getRandomItems(contextHolder, world, serverPlayer)) { world.dropItemNaturally(vec3d, item); } } @@ -213,10 +213,10 @@ public class BlockEventListener implements Listener { Location location = block.getLocation(); net.momirealms.craftengine.core.world.World world = new BukkitWorld(block.getWorld()); Vec3d vec3d = new Vec3d(location.getBlockX() + 0.5, location.getBlockY() + 0.5, location.getBlockZ() + 0.5); - ContextHolder.Builder builder = ContextHolder.builder(); - builder.withParameter(LootParameters.WORLD, world); - builder.withParameter(LootParameters.LOCATION, vec3d); - for (Item item : immutableBlockState.getDrops(builder, world)) { + ContextHolder.Builder builder = ContextHolder.builder() + .withParameter(CommonParameters.WORLD, world) + .withParameter(CommonParameters.LOCATION, vec3d); + for (Item item : immutableBlockState.getDrops(builder, world, null)) { world.dropItemNaturally(vec3d, item); } } @@ -232,11 +232,11 @@ public class BlockEventListener implements Listener { Vec3d vec3d = new Vec3d(location.getBlockX() + 0.5, location.getBlockY() + 0.5, location.getBlockZ() + 0.5); net.momirealms.craftengine.core.world.World world = new BukkitWorld(location.getWorld()); ContextHolder.Builder builder = ContextHolder.builder(); - builder.withParameter(LootParameters.WORLD, world); - builder.withParameter(LootParameters.LOCATION, vec3d); + builder.withParameter(CommonParameters.WORLD, world); + builder.withParameter(CommonParameters.LOCATION, vec3d); ContextHolder contextHolder = builder.build(); for (LootTable lootTable : it.lootTables()) { - for (Item item : lootTable.getRandomItems(contextHolder, world)) { + for (Item item : lootTable.getRandomItems(contextHolder, world, null)) { world.dropItemNaturally(vec3d, item); } } @@ -329,12 +329,12 @@ public class BlockEventListener implements Listener { if (state != null && !state.isEmpty()) { ContextHolder.Builder builder = ContextHolder.builder(); Vec3d vec3d = Vec3d.atCenterOf(blockPos); - builder.withParameter(LootParameters.LOCATION, vec3d); - builder.withParameter(LootParameters.WORLD, world); + builder.withParameter(CommonParameters.LOCATION, vec3d); + builder.withParameter(CommonParameters.WORLD, world); if (yield < 1f) { - builder.withParameter(LootParameters.EXPLOSION_RADIUS, 1.0f / yield); + builder.withParameter(CommonParameters.EXPLOSION_RADIUS, 1.0f / yield); } - for (Item item : state.getDrops(builder, world)) { + for (Item item : state.getDrops(builder, world, null)) { world.dropItemNaturally(vec3d, item); } world.playBlockSound(vec3d, state.sounds().breakSound()); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java index 74e9e5019..6142cbed6 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java @@ -359,7 +359,7 @@ public class BukkitBlockManager extends AbstractBlockManager { appearances = Map.of("default", pair.right()); String internalBlock = pair.left().value() + "_" + internalId; - Key internalBlockId = Key.of(CraftEngine.NAMESPACE, internalBlock); + Key internalBlockId = Key.of(Key.DEFAULT_NAMESPACE, internalBlock); int internalBlockRegistryId = Optional.ofNullable(internalId2StateId.get(internalBlockId)).orElse(-1); if (internalBlockRegistryId == -1) { throw new LocalizedResourceConfigException("warning.config.block.state.invalid_real_id", @@ -408,7 +408,7 @@ public class BukkitBlockManager extends AbstractBlockManager { } int internalId = ResourceConfigUtils.getAsInt(variantSection.getOrDefault("id", -1), "id"); Key baseBlock = tempTypeMap.get(appearance); - Key internalBlockId = Key.of(CraftEngine.NAMESPACE, baseBlock.value() + "_" + internalId); + Key internalBlockId = Key.of(Key.DEFAULT_NAMESPACE, baseBlock.value() + "_" + internalId); int internalBlockRegistryId = Optional.ofNullable(internalId2StateId.get(internalBlockId)).orElse(-1); if (internalBlockRegistryId == -1) { throw new LocalizedResourceConfigException("warning.config.block.state.invalid_real_id", @@ -782,7 +782,7 @@ public class BukkitBlockManager extends AbstractBlockManager { } private Key createRealBlockKey(Key replacedBlock, int index) { - return Key.of(CraftEngine.NAMESPACE, replacedBlock.value() + "_" + index); + return Key.of(Key.DEFAULT_NAMESPACE, replacedBlock.value() + "_" + index); } private Object createBlockProperties(Key realBlockKey) throws Exception { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/FallingBlockRemoveListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/FallingBlockRemoveListener.java index f40a43172..20e17db9d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/FallingBlockRemoveListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/FallingBlockRemoveListener.java @@ -5,9 +5,9 @@ import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.bukkit.world.BukkitWorld; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.item.Item; -import net.momirealms.craftengine.core.loot.parameter.LootParameters; import net.momirealms.craftengine.core.plugin.CraftEngine; -import net.momirealms.craftengine.core.util.context.ContextHolder; +import net.momirealms.craftengine.core.plugin.context.ContextHolder; +import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; import net.momirealms.craftengine.core.world.Vec3d; import org.bukkit.entity.FallingBlock; import org.bukkit.event.EventHandler; @@ -32,15 +32,15 @@ public class FallingBlockRemoveListener implements Listener { ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(stateId); if (immutableBlockState == null || immutableBlockState.isEmpty()) return; ContextHolder.Builder builder = ContextHolder.builder(); - builder.withParameter(LootParameters.FALLING_BLOCK, true); + builder.withParameter(CommonParameters.FALLING_BLOCK, true); double x = Reflections.field$Entity$xo.getDouble(fallingBlockEntity); double y = Reflections.field$Entity$yo.getDouble(fallingBlockEntity); double z = Reflections.field$Entity$zo.getDouble(fallingBlockEntity); Vec3d vec3d = new Vec3d(x, y, z); net.momirealms.craftengine.core.world.World world = new BukkitWorld(fallingBlock.getWorld()); - builder.withParameter(LootParameters.LOCATION, vec3d); - builder.withParameter(LootParameters.WORLD, world); - for (Item item : immutableBlockState.getDrops(builder, world)) { + builder.withParameter(CommonParameters.LOCATION, vec3d); + builder.withParameter(CommonParameters.WORLD, world); + for (Item item : immutableBlockState.getDrops(builder, world, null)) { world.dropItemNaturally(vec3d, item); } Object entityData = Reflections.field$Entity$entityData.get(fallingBlockEntity); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java index b19b7bdbf..06b6bac69 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java @@ -11,12 +11,12 @@ import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; import net.momirealms.craftengine.core.item.Item; -import net.momirealms.craftengine.core.loot.parameter.LootParameters; +import net.momirealms.craftengine.core.plugin.context.ContextHolder; +import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.Tuple; import net.momirealms.craftengine.core.util.VersionHelper; -import net.momirealms.craftengine.core.util.context.ContextHolder; import net.momirealms.craftengine.core.world.BlockPos; import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.core.world.WorldEvents; @@ -71,9 +71,9 @@ public class BushBlockBehavior extends BukkitBlockBehavior { BlockPos pos = LocationUtils.fromBlockPos(blockPos); Vec3d vec3d = Vec3d.atCenterOf(pos); net.momirealms.craftengine.core.world.World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level)); - builder.withParameter(LootParameters.LOCATION, vec3d); - builder.withParameter(LootParameters.WORLD, world); - for (Item item : previousState.getDrops(builder, world)) { + builder.withParameter(CommonParameters.LOCATION, vec3d); + builder.withParameter(CommonParameters.WORLD, world); + for (Item item : previousState.getDrops(builder, world, null)) { world.dropItemNaturally(vec3d, item); } world.playBlockSound(vec3d, previousState.sounds().breakSound()); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java index 6e18976af..e5681c5fb 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java @@ -12,14 +12,14 @@ import net.momirealms.craftengine.core.block.UpdateOption; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; import net.momirealms.craftengine.core.block.properties.IntegerProperty; import net.momirealms.craftengine.core.block.properties.Property; -import net.momirealms.craftengine.core.loot.LootContext; -import net.momirealms.craftengine.core.loot.number.NumberProvider; -import net.momirealms.craftengine.core.loot.number.NumberProviders; -import net.momirealms.craftengine.core.loot.parameter.LootParameters; +import net.momirealms.craftengine.core.plugin.context.ContextHolder; +import net.momirealms.craftengine.core.plugin.context.SimpleContext; +import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; +import net.momirealms.craftengine.core.plugin.context.number.NumberProviders; +import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; import net.momirealms.craftengine.core.util.RandomUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.util.Tuple; -import net.momirealms.craftengine.core.util.context.ContextHolder; import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.core.world.Vec3i; import net.momirealms.craftengine.shared.block.BlockBehavior; @@ -30,7 +30,6 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.Callable; -import java.util.concurrent.ThreadLocalRandom; public class CropBlockBehavior extends BushBlockBehavior { public static final Factory FACTORY = new Factory(); @@ -146,17 +145,19 @@ public class CropBlockBehavior extends BushBlockBehavior { int x = FastNMS.INSTANCE.field$Vec3i$x(pos); int y = FastNMS.INSTANCE.field$Vec3i$y(pos); int z = FastNMS.INSTANCE.field$Vec3i$z(pos); - - net.momirealms.craftengine.core.world.World wrappedWorld = new BukkitWorld(world); - int i = this.getAge(immutableBlockState) + this.boneMealBonus.getInt(new LootContext(wrappedWorld, ContextHolder.builder() - .withParameter(LootParameters.WORLD, wrappedWorld) - .withParameter(LootParameters.LOCATION, Vec3d.atCenterOf(new Vec3i(x, y, z))) - .build(), ThreadLocalRandom.current(), 1)); + int i = this.getAge(immutableBlockState) + this.boneMealBonus.getInt( + SimpleContext.of( + ContextHolder.builder() + .withParameter(CommonParameters.WORLD, new BukkitWorld(world)) + .withParameter(CommonParameters.LOCATION, Vec3d.atCenterOf(new Vec3i(x, y, z))) + .build() + ) + ); int maxAge = this.ageProperty.max; if (i > maxAge) { i = maxAge; } - FastNMS.INSTANCE.method$LevelWriter$setBlock(level, pos, immutableBlockState.with(this.ageProperty, i).customBlockState().handle(), UpdateOption.UPDATE_NONE.flags()); + FastNMS.INSTANCE.method$LevelWriter$setBlock(level, pos, immutableBlockState.with(this.ageProperty, i).customBlockState().handle(), UpdateOption.UPDATE_ALL.flags()); if (sendParticles) { world.spawnParticle(ParticleUtils.getParticle("HAPPY_VILLAGER"), x + 0.5, y + 0.5, z + 0.5, 15, 0.25, 0.25, 0.25); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FallingBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FallingBlockBehavior.java index 54b2d436a..f90956c5f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FallingBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FallingBlockBehavior.java @@ -10,10 +10,10 @@ import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; import net.momirealms.craftengine.core.item.Item; -import net.momirealms.craftengine.core.loot.parameter.LootParameters; +import net.momirealms.craftengine.core.plugin.context.ContextHolder; +import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.util.VersionHelper; -import net.momirealms.craftengine.core.util.context.ContextHolder; import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.shared.block.BlockBehavior; @@ -91,15 +91,15 @@ public class FallingBlockBehavior extends BukkitBlockBehavior { ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(stateId); if (immutableBlockState == null || immutableBlockState.isEmpty()) return; ContextHolder.Builder builder = ContextHolder.builder(); - builder.withParameter(LootParameters.FALLING_BLOCK, true); + builder.withParameter(CommonParameters.FALLING_BLOCK, true); double x = Reflections.field$Entity$xo.getDouble(fallingBlockEntity); double y = Reflections.field$Entity$yo.getDouble(fallingBlockEntity); double z = Reflections.field$Entity$zo.getDouble(fallingBlockEntity); Vec3d vec3d = new Vec3d(x, y, z); net.momirealms.craftengine.core.world.World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level)); - builder.withParameter(LootParameters.LOCATION, vec3d); - builder.withParameter(LootParameters.WORLD, world); - for (Item item : immutableBlockState.getDrops(builder, world)) { + builder.withParameter(CommonParameters.LOCATION, vec3d); + builder.withParameter(CommonParameters.WORLD, world); + for (Item item : immutableBlockState.getDrops(builder, world, null)) { world.dropItemNaturally(vec3d, item); } Object entityData = Reflections.field$Entity$entityData.get(fallingBlockEntity); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/LeavesBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/LeavesBlockBehavior.java index 4686b022c..cf88d726f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/LeavesBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/LeavesBlockBehavior.java @@ -13,12 +13,12 @@ import net.momirealms.craftengine.core.block.UpdateOption; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.item.Item; -import net.momirealms.craftengine.core.loot.parameter.LootParameters; +import net.momirealms.craftengine.core.plugin.context.ContextHolder; +import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; import net.momirealms.craftengine.core.util.Direction; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.util.VersionHelper; -import net.momirealms.craftengine.core.util.context.ContextHolder; import net.momirealms.craftengine.core.world.BlockPos; import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.shared.block.BlockBehavior; @@ -125,9 +125,9 @@ public class LeavesBlockBehavior extends WaterLoggedBlockBehavior { Vec3d vec3d = Vec3d.atCenterOf(pos); net.momirealms.craftengine.core.world.World world = new BukkitWorld(bukkitWorld); ContextHolder.Builder builder = ContextHolder.builder() - .withParameter(LootParameters.LOCATION, vec3d) - .withParameter(LootParameters.WORLD, world); - for (Item item : immutableBlockState.getDrops(builder, world)) { + .withParameter(CommonParameters.LOCATION, vec3d) + .withParameter(CommonParameters.WORLD, world); + for (Item item : immutableBlockState.getDrops(builder, world, null)) { world.dropItemNaturally(vec3d, item); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SugarCaneBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SugarCaneBlockBehavior.java index cf1b77194..1deb5712f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SugarCaneBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SugarCaneBlockBehavior.java @@ -13,9 +13,9 @@ import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; import net.momirealms.craftengine.core.block.properties.IntegerProperty; import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.item.Item; -import net.momirealms.craftengine.core.loot.parameter.LootParameters; +import net.momirealms.craftengine.core.plugin.context.ContextHolder; +import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; import net.momirealms.craftengine.core.util.*; -import net.momirealms.craftengine.core.util.context.ContextHolder; import net.momirealms.craftengine.core.world.BlockPos; import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.core.world.WorldEvents; @@ -61,9 +61,9 @@ public class SugarCaneBlockBehavior extends BushBlockBehavior { Vec3d vec3d = Vec3d.atCenterOf(LocationUtils.fromBlockPos(blockPos)); net.momirealms.craftengine.core.world.World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level)); ContextHolder.Builder builder = ContextHolder.builder() - .withParameter(LootParameters.LOCATION, vec3d) - .withParameter(LootParameters.WORLD, world); - for (Item item : currentState.getDrops(builder, world)) { + .withParameter(CommonParameters.LOCATION, vec3d) + .withParameter(CommonParameters.WORLD, world); + for (Item item : currentState.getDrops(builder, world, null)) { world.dropItemNaturally(vec3d, item); } world.playBlockSound(vec3d, currentState.sounds().breakSound()); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/BukkitEntity.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/BukkitEntity.java index d61bfce98..d8bc859de 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/BukkitEntity.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/BukkitEntity.java @@ -1,8 +1,10 @@ package net.momirealms.craftengine.bukkit.entity; +import net.momirealms.craftengine.bukkit.util.KeyUtils; import net.momirealms.craftengine.bukkit.world.BukkitWorld; import net.momirealms.craftengine.core.entity.Entity; import net.momirealms.craftengine.core.util.Direction; +import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.world.World; import java.lang.ref.WeakReference; @@ -49,7 +51,7 @@ public class BukkitEntity extends Entity { } @Override - public World level() { + public World world() { return new BukkitWorld(literalObject().getWorld()); } @@ -62,4 +64,9 @@ public class BukkitEntity extends Entity { public org.bukkit.entity.Entity literalObject() { return this.entity.get(); } + + @Override + public Key type() { + return KeyUtils.namespacedKey2Key(literalObject().getType().getKey()); + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java index 6dc5566af..9296dd4c5 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java @@ -28,12 +28,12 @@ import net.momirealms.craftengine.core.pack.model.select.ChargeTypeSelectPropert import net.momirealms.craftengine.core.pack.model.select.TrimMaterialSelectProperty; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; +import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.registry.WritableRegistry; import net.momirealms.craftengine.core.util.*; -import net.momirealms.craftengine.core.util.context.ContextHolder; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.NamespacedKey; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ItemEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ItemEventListener.java index a23cf371a..bc5e9772f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ItemEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ItemEventListener.java @@ -100,7 +100,7 @@ public class ItemEventListener implements Listener { if (optionalItemBehaviors.isPresent()) { for (ItemBehavior itemBehavior : optionalItemBehaviors.get()) { - InteractionResult result = itemBehavior.use(player.level(), player, hand); + InteractionResult result = itemBehavior.use(player.world(), player, hand); if (result == InteractionResult.SUCCESS_AND_CANCEL) { event.setCancelled(true); return; @@ -167,7 +167,7 @@ public class ItemEventListener implements Listener { event.setCancelled(true); return; } - int maxY = player.level().worldHeight().getMaxBuildHeight() - 1; + int maxY = player.world().worldHeight().getMaxBuildHeight() - 1; if (direction == Direction.UP && result != InteractionResult.SUCCESS && pos.y() >= maxY diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/AxeItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/AxeItemBehavior.java index 47b466610..732978b30 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/AxeItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/AxeItemBehavior.java @@ -4,7 +4,7 @@ import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks; import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.block.behavior.StrippableBlockBehavior; import net.momirealms.craftengine.bukkit.util.*; -import net.momirealms.craftengine.bukkit.world.BukkitWorldBlock; +import net.momirealms.craftengine.bukkit.world.BukkitBlockInWorld; import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.UpdateOption; @@ -43,7 +43,7 @@ public class AxeItemBehavior extends ItemBehavior { @SuppressWarnings("unchecked") @Override public InteractionResult useOnBlock(UseOnContext context) { - BukkitWorldBlock clicked = (BukkitWorldBlock) context.getLevel().getBlockAt(context.getClickedPos()); + BukkitBlockInWorld clicked = (BukkitBlockInWorld) context.getLevel().getBlockAt(context.getClickedPos()); Block block = clicked.block(); ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockDataToId(block.getBlockData())); if (state == null || state.isEmpty()) return InteractionResult.PASS; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BoneMealItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BoneMealItemBehavior.java index 6d60e9e44..2996694ed 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BoneMealItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BoneMealItemBehavior.java @@ -8,7 +8,7 @@ import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; import net.momirealms.craftengine.bukkit.util.LocationUtils; import net.momirealms.craftengine.bukkit.util.Reflections; -import net.momirealms.craftengine.bukkit.world.BukkitWorldBlock; +import net.momirealms.craftengine.bukkit.world.BukkitBlockInWorld; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.entity.player.InteractionResult; import net.momirealms.craftengine.core.item.behavior.ItemBehavior; @@ -32,7 +32,7 @@ public class BoneMealItemBehavior extends ItemBehavior { return InteractionResult.PASS; } - BukkitWorldBlock clicked = (BukkitWorldBlock) context.getLevel().getBlockAt(context.getClickedPos()); + BukkitBlockInWorld clicked = (BukkitBlockInWorld) context.getLevel().getBlockAt(context.getClickedPos()); Block block = clicked.block(); ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockDataToId(block.getBlockData())); if (state == null || state.isEmpty()) return InteractionResult.PASS; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BucketItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BucketItemBehavior.java index e8f90596f..570786360 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BucketItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BucketItemBehavior.java @@ -4,7 +4,7 @@ import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks; import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; -import net.momirealms.craftengine.bukkit.world.BukkitWorldBlock; +import net.momirealms.craftengine.bukkit.world.BukkitBlockInWorld; import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.UpdateOption; @@ -35,7 +35,7 @@ public class BucketItemBehavior extends ItemBehavior { @Override public InteractionResult useOnBlock(UseOnContext context) { if (context.getPlayer().isAdventureMode()) return InteractionResult.PASS; - BukkitWorldBlock clicked = (BukkitWorldBlock) context.getLevel().getBlockAt(context.getClickedPos()); + BukkitBlockInWorld clicked = (BukkitBlockInWorld) context.getLevel().getBlockAt(context.getClickedPos()); Block block = clicked.block(); ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockDataToId(block.getBlockData())); if (state == null || state.isEmpty()) return InteractionResult.PASS; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FurnitureItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FurnitureItemBehavior.java index f61092a23..ff062ebec 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FurnitureItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FurnitureItemBehavior.java @@ -120,10 +120,6 @@ public class FurnitureItemBehavior extends ItemBehavior { return InteractionResult.FAIL; } - if (!BukkitCraftEngine.instance().antiGrief().canPlace(bukkitPlayer, furnitureLocation)) { - return InteractionResult.FAIL; - } - FurnitureAttemptPlaceEvent attemptPlaceEvent = new FurnitureAttemptPlaceEvent(bukkitPlayer, customFurniture, anchorType, furnitureLocation.clone(), DirectionUtils.toBlockFace(clickedFace), context.getHand(), world.getBlockAt(context.getClickedPos().x(), context.getClickedPos().y(), context.getClickedPos().z())); if (EventUtils.fireAndCheckCancel(attemptPlaceEvent)) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/WaterBucketItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/WaterBucketItemBehavior.java index 1ec481214..af31edd9d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/WaterBucketItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/WaterBucketItemBehavior.java @@ -4,7 +4,7 @@ import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks; import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; -import net.momirealms.craftengine.bukkit.world.BukkitWorldBlock; +import net.momirealms.craftengine.bukkit.world.BukkitBlockInWorld; import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.UpdateOption; @@ -33,7 +33,7 @@ public class WaterBucketItemBehavior extends ItemBehavior { public InteractionResult useOnBlock(UseOnContext context) { if (context.getPlayer().isAdventureMode()) return InteractionResult.PASS; BlockPos pos = context.getClickedPos(); - BukkitWorldBlock clicked = (BukkitWorldBlock) context.getLevel().getBlockAt(pos); + BukkitBlockInWorld clicked = (BukkitBlockInWorld) context.getLevel().getBlockAt(pos); Block block = clicked.block(); ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockDataToId(block.getBlockData())); if (state == null || state.isEmpty()) return InteractionResult.PASS; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java index 7bc3042f3..aaa910a99 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java @@ -19,13 +19,13 @@ import net.momirealms.craftengine.core.item.recipe.input.CraftingInput; import net.momirealms.craftengine.core.item.recipe.input.SingleItemInput; import net.momirealms.craftengine.core.item.recipe.input.SmithingInput; import net.momirealms.craftengine.core.plugin.config.Config; +import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.AdventureHelper; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.Pair; import net.momirealms.craftengine.core.util.VersionHelper; -import net.momirealms.craftengine.core.util.context.ContextHolder; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.Campfire; @@ -752,7 +752,7 @@ public class RecipeEventListener implements Listener { return; } - Item newItem = customItem.buildItem(ItemBuildContext.of(plugin.adapt(player), ContextHolder.EMPTY)); + Item newItem = customItem.buildItem(ItemBuildContext.of(plugin.adapt(player))); int remainingDurability = totalMaxDamage - totalDamage; int newItemDamage = Math.max(0, newItem.maxDamage().get() - remainingDurability); newItem.damage(newItemDamage); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/loot/BukkitVanillaLootManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/loot/BukkitVanillaLootManager.java index 1bfb8cd09..f994c121b 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/loot/BukkitVanillaLootManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/loot/BukkitVanillaLootManager.java @@ -6,18 +6,17 @@ import net.momirealms.craftengine.bukkit.util.BlockStateUtils; import net.momirealms.craftengine.bukkit.util.KeyUtils; import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.bukkit.world.BukkitWorld; -import net.momirealms.craftengine.core.entity.player.InteractionHand; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.loot.AbstractVanillaLootManager; import net.momirealms.craftengine.core.loot.LootTable; import net.momirealms.craftengine.core.loot.VanillaLoot; -import net.momirealms.craftengine.core.loot.parameter.LootParameters; import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; +import net.momirealms.craftengine.core.plugin.context.ContextHolder; +import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.*; -import net.momirealms.craftengine.core.util.context.ContextHolder; import net.momirealms.craftengine.core.world.Vec3d; import org.bukkit.Bukkit; import org.bukkit.Location; @@ -68,18 +67,19 @@ public class BukkitVanillaLootManager extends AbstractVanillaLootManager impleme net.momirealms.craftengine.core.world.World world = new BukkitWorld(entity.getWorld()); Vec3d vec3d = new Vec3d(location.getBlockX() + 0.5, location.getBlockY() + 0.5, location.getBlockZ() + 0.5); ContextHolder.Builder builder = ContextHolder.builder(); - builder.withParameter(LootParameters.WORLD, world); - builder.withParameter(LootParameters.LOCATION, vec3d); + builder.withParameter(CommonParameters.WORLD, world); + builder.withParameter(CommonParameters.LOCATION, vec3d); + BukkitServerPlayer optionalPlayer = null; if (VersionHelper.isOrAbove1_20_5()) { if (event.getDamageSource().getCausingEntity() instanceof Player player) { - BukkitServerPlayer serverPlayer = this.plugin.adapt(player); - builder.withParameter(LootParameters.PLAYER, serverPlayer); - builder.withOptionalParameter(LootParameters.TOOL, serverPlayer.getItemInHand(InteractionHand.MAIN_HAND)); + optionalPlayer = this.plugin.adapt(player); + builder.withParameter(CommonParameters.PLAYER, optionalPlayer); + //mark item builder.withOptionalParameter(CommonParameters.MAIN_HAND_ITEM, serverPlayer.getItemInHand(InteractionHand.MAIN_HAND)); } } ContextHolder contextHolder = builder.build(); for (LootTable lootTable : loot.lootTables()) { - for (Item item : lootTable.getRandomItems(contextHolder, world)) { + for (Item item : lootTable.getRandomItems(contextHolder, world, optionalPlayer)) { world.dropItemNaturally(vec3d, item); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java index d6741da96..fe7f48e8f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java @@ -75,6 +75,7 @@ public class BukkitCraftEngine extends CraftEngine { super.classPathAppender = new ReflectionClassPathAppender(this); super.scheduler = new BukkitSchedulerAdapter(this); super.logger = new JavaPluginLogger(bootstrap.getLogger()); + super.platform = new BukkitPlatform(); // find mod class if present Class modClass = ReflectionUtils.getClazz(MOD_CLASS); if (modClass != null) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitPlatform.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitPlatform.java new file mode 100644 index 000000000..2b3647fa1 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitPlatform.java @@ -0,0 +1,12 @@ +package net.momirealms.craftengine.bukkit.plugin; + +import net.momirealms.craftengine.core.plugin.Platform; +import org.bukkit.Bukkit; + +public class BukkitPlatform implements Platform { + + @Override + public void dispatchCommand(String command) { + Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), command); + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/BukkitCommandManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/BukkitCommandManager.java index 0b5d4030e..c1f1c3f39 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/BukkitCommandManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/BukkitCommandManager.java @@ -46,6 +46,7 @@ public class BukkitCommandManager extends AbstractCommandManager new DebugSetBlockCommand(this, plugin), new DebugSpawnFurnitureCommand(this, plugin), new DebugTargetBlockCommand(this, plugin), + new DebugIsSectionInjectedCommand(this, plugin), new TotemAnimationCommand(this, plugin), new EnableResourceCommand(this, plugin), new DisableResourceCommand(this, plugin), diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/BukkitSenderFactory.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/BukkitSenderFactory.java index df890ee5d..a9a2ba020 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/BukkitSenderFactory.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/BukkitSenderFactory.java @@ -3,7 +3,9 @@ package net.momirealms.craftengine.bukkit.plugin.command; import net.kyori.adventure.audience.Audience; import net.kyori.adventure.platform.bukkit.BukkitAudiences; import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; +import net.momirealms.craftengine.bukkit.util.ComponentUtils; import net.momirealms.craftengine.core.plugin.command.sender.Sender; import net.momirealms.craftengine.core.plugin.command.sender.SenderFactory; import net.momirealms.craftengine.core.util.Tristate; @@ -47,7 +49,9 @@ public class BukkitSenderFactory extends SenderFactory audience(sender).sendMessage(message)); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugIsSectionInjectedCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugIsSectionInjectedCommand.java new file mode 100644 index 000000000..b14e164e9 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugIsSectionInjectedCommand.java @@ -0,0 +1,50 @@ +package net.momirealms.craftengine.bukkit.plugin.command.feature; + +import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; +import net.momirealms.craftengine.bukkit.plugin.injector.BukkitInjector; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; +import net.momirealms.craftengine.core.plugin.command.sender.Sender; +import net.momirealms.craftengine.core.plugin.context.ContextHolder; +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; +import net.momirealms.craftengine.core.util.AdventureHelper; +import net.momirealms.craftengine.core.world.chunk.CESection; +import org.bukkit.Chunk; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.incendo.cloud.Command; +import org.incendo.cloud.parser.standard.StringParser; + +public class DebugIsSectionInjectedCommand extends BukkitCommandFeature { + + public DebugIsSectionInjectedCommand(CraftEngineCommandManager commandManager, CraftEngine plugin) { + super(commandManager, plugin); + } + + @Override + public Command.Builder assembleCommand(org.incendo.cloud.CommandManager manager, Command.Builder builder) { + return builder + .senderType(Player.class) + .handler(context -> { + Player player = context.sender(); + Chunk chunk = player.getChunk(); + Object worldServer = FastNMS.INSTANCE.field$CraftChunk$worldServer(chunk); + Object chunkSource = FastNMS.INSTANCE.method$ServerLevel$getChunkSource(worldServer); + Object levelChunk = FastNMS.INSTANCE.method$ServerChunkCache$getChunkAtIfLoadedMainThread(chunkSource, chunk.getX(), chunk.getZ()); + Object[] sections = FastNMS.INSTANCE.method$ChunkAccess$getSections(levelChunk); + int i = 0; + Sender sender = plugin().senderFactory().wrap(player); + for (Object section : sections) { + sender.sendMessage(Component.text("Section #" + i + ": " + BukkitInjector.isSectionInjected(section))); + i++; + } + }); + } + + @Override + public String getFeatureID() { + return "debug_is_section_injected"; + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/ReloadCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/ReloadCommand.java index 00056ba91..db8d277a1 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/ReloadCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/ReloadCommand.java @@ -68,7 +68,6 @@ public class ReloadCommand extends BukkitCommandFeature { long time2 = System.currentTimeMillis(); long packTime = time2 - time1; handleFeedback(context, MessageConstants.COMMAND_RELOAD_PACK_SUCCESS, Component.text(packTime)); - } catch (Exception e) { handleFeedback(context, MessageConstants.COMMAND_RELOAD_PACK_FAILURE); plugin().logger().warn("Failed to generate resource pack", e); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java index 5e1ae7447..116ac584a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java @@ -1,13 +1,15 @@ package net.momirealms.craftengine.bukkit.plugin.command.feature; -import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; -import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.plugin.context.ContextHolder; +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; +import net.momirealms.craftengine.core.util.AdventureHelper; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.incendo.cloud.Command; +import org.incendo.cloud.parser.standard.StringParser; public class TestCommand extends BukkitCommandFeature { @@ -19,9 +21,11 @@ public class TestCommand extends BukkitCommandFeature { public Command.Builder assembleCommand(org.incendo.cloud.CommandManager manager, Command.Builder builder) { return builder .senderType(Player.class) + .required("text", StringParser.greedyStringParser()) .handler(context -> { - Player player = context.sender(); - player.getInventory().addItem(BukkitItemManager.instance().createWrappedItem(Key.from("default:topaz"), null).getItem()); + String text = ""; + PlayerOptionalContext context1 = PlayerOptionalContext.of(plugin().adapt(context.sender()), ContextHolder.builder()); + plugin().senderFactory().wrap(context.sender()).sendMessage(AdventureHelper.customMiniMessage().deserialize(text, context1.tagResolvers())); }); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BukkitInjector.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BukkitInjector.java index b68ef4a2d..9a54e77a1 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BukkitInjector.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BukkitInjector.java @@ -17,6 +17,7 @@ import net.bytebuddy.implementation.bind.annotation.AllArguments; import net.bytebuddy.implementation.bind.annotation.RuntimeType; import net.bytebuddy.implementation.bind.annotation.SuperCall; import net.bytebuddy.implementation.bind.annotation.This; +import net.bytebuddy.implementation.bytecode.assign.Assigner; import net.bytebuddy.implementation.bytecode.assign.TypeCasting; import net.bytebuddy.implementation.bytecode.member.FieldAccess; import net.bytebuddy.implementation.bytecode.member.MethodReturn; @@ -51,7 +52,7 @@ import net.momirealms.craftengine.core.world.CEWorld; import net.momirealms.craftengine.core.world.SectionPos; import net.momirealms.craftengine.core.world.chunk.CEChunk; import net.momirealms.craftengine.core.world.chunk.CESection; -import net.momirealms.craftengine.core.world.chunk.InjectedPalettedContainerHolder; +import net.momirealms.craftengine.core.world.chunk.InjectedHolder; import net.momirealms.craftengine.shared.ObjectHolder; import net.momirealms.craftengine.shared.block.*; import org.bukkit.inventory.ItemStack; @@ -69,12 +70,15 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.concurrent.Callable; +import java.util.function.Consumer; public class BukkitInjector { private static final ByteBuddy byteBuddy = new ByteBuddy(ClassFileVersion.JAVA_V17); private static final BukkitBlockShape STONE_SHAPE = new BukkitBlockShape(Reflections.instance$Blocks$STONE$defaultState); private static Class clazz$InjectedPalettedContainer; + private static Class clazz$InjectedLevelChunkSection; + private static MethodHandle constructor$InjectedLevelChunkSection; private static VarHandle varHandle$InjectedPalettedContainer$target; @@ -100,36 +104,62 @@ public class BukkitInjector { clazz$InjectedPalettedContainer = byteBuddy .subclass(Reflections.clazz$PalettedContainer) .name("net.minecraft.world.level.chunk.InjectedPalettedContainer") - .implement(InjectedPalettedContainerHolder.class) - .defineField("target", Reflections.clazz$PalettedContainer, Visibility.PRIVATE) - .defineField("ceworld", CEWorld.class, Visibility.PRIVATE) + .implement(InjectedHolder.Palette.class) + .defineField("target", Reflections.clazz$PalettedContainer, Visibility.PUBLIC) + .defineField("active", boolean.class, Visibility.PUBLIC) .defineField("cesection", CESection.class, Visibility.PRIVATE) .defineField("cechunk", CEChunk.class, Visibility.PRIVATE) .defineField("cepos", SectionPos.class, Visibility.PRIVATE) .method(ElementMatchers.any() .and(ElementMatchers.not(ElementMatchers.is(Reflections.method$PalettedContainer$getAndSet))) .and(ElementMatchers.not(ElementMatchers.isDeclaredBy(Object.class))) - // TODO Requires Paper Patch - //.and(ElementMatchers.not(ElementMatchers.named("get").and(ElementMatchers.takesArguments(int.class)).and(ElementMatchers.returns(Object.class)))) ) .intercept(MethodDelegation.toField("target")) .method(ElementMatchers.is(Reflections.method$PalettedContainer$getAndSet)) .intercept(MethodDelegation.to(GetAndSetInterceptor.INSTANCE)) .method(ElementMatchers.named("target")) .intercept(FieldAccessor.ofField("target")) + .method(ElementMatchers.named("setTarget")) + .intercept(FieldAccessor.ofField("target").withAssigner(Assigner.DEFAULT, Assigner.Typing.DYNAMIC)) + .method(ElementMatchers.named("isActive").or(ElementMatchers.named("setActive"))) + .intercept(FieldAccessor.ofField("active")) .method(ElementMatchers.named("ceSection")) .intercept(FieldAccessor.ofField("cesection")) .method(ElementMatchers.named("ceChunk")) .intercept(FieldAccessor.ofField("cechunk")) - .method(ElementMatchers.named("ceWorld")) - .intercept(FieldAccessor.ofField("ceworld")) .method(ElementMatchers.named("cePos")) .intercept(FieldAccessor.ofField("cepos")) .make() .load(BukkitInjector.class.getClassLoader()) .getLoaded(); + //varHandle$InjectedPalettedContainer$target = Objects.requireNonNull(ReflectionUtils.findVarHandle(clazz$InjectedPalettedContainer, "target", Reflections.clazz$PalettedContainer)); - varHandle$InjectedPalettedContainer$target = Objects.requireNonNull(ReflectionUtils.findVarHandle(clazz$InjectedPalettedContainer, "target", Reflections.clazz$PalettedContainer)); + // Level Chunk Section + clazz$InjectedLevelChunkSection = byteBuddy + .subclass(Reflections.clazz$LevelChunkSection, ConstructorStrategy.Default.IMITATE_SUPER_CLASS_OPENING) + .name("net.minecraft.world.level.chunk.InjectedLevelChunkSection") + .implement(InjectedHolder.Section.class) + .defineField("active", boolean.class, Visibility.PUBLIC) + .defineField("cesection", CESection.class, Visibility.PRIVATE) + .defineField("cechunk", CEChunk.class, Visibility.PRIVATE) + .defineField("cepos", SectionPos.class, Visibility.PRIVATE) + .method(ElementMatchers.is(Reflections.method$LevelChunkSection$setBlockState)) + .intercept(MethodDelegation.to(SetBlockStateInterceptor.INSTANCE)) + .method(ElementMatchers.named("ceSection")) + .intercept(FieldAccessor.ofField("cesection")) + .method(ElementMatchers.named("ceChunk")) + .intercept(FieldAccessor.ofField("cechunk")) + .method(ElementMatchers.named("cePos")) + .intercept(FieldAccessor.ofField("cepos")) + .method(ElementMatchers.named("isActive").or(ElementMatchers.named("setActive"))) + .intercept(FieldAccessor.ofField("active")) + .make() + .load(BukkitInjector.class.getClassLoader()) + .getLoaded(); + + constructor$InjectedLevelChunkSection = MethodHandles.publicLookup().in(clazz$InjectedLevelChunkSection) + .findConstructor(clazz$InjectedLevelChunkSection, MethodType.methodType(void.class, Reflections.clazz$PalettedContainer, Reflections.clazz$PalettedContainer)) + .asType(MethodType.methodType(Reflections.clazz$LevelChunkSection, Reflections.clazz$PalettedContainer, Reflections.clazz$PalettedContainer)); // State Predicate DynamicType.Unloaded alwaysTrue = byteBuddy @@ -388,40 +418,86 @@ public class BukkitInjector { // } // } - public synchronized static void injectLevelChunkSection(Object targetSection, CESection ceSection, CEWorld ceWorld, CEChunk chunk, SectionPos pos) { + public synchronized static void injectLevelChunkSection(Object targetSection, CESection ceSection, CEChunk chunk, SectionPos pos, Consumer callback) { try { - Object container = FastNMS.INSTANCE.field$LevelChunkSection$states(targetSection); - if (!clazz$InjectedPalettedContainer.isInstance(container)) { - InjectedPalettedContainerHolder injectedObject; - if (Config.fastPaletteInjection()) { - injectedObject = FastNMS.INSTANCE.createInjectedPalettedContainerHolder(container); + if (Config.injectionTarget()) { + Object container = FastNMS.INSTANCE.field$LevelChunkSection$states(targetSection); + if (!(container instanceof InjectedHolder.Palette holder)) { + InjectedHolder.Palette injectedObject; + if (Config.fastInjection()) { + injectedObject = FastNMS.INSTANCE.createInjectedPalettedContainerHolder(container); + } else { + injectedObject = (InjectedHolder.Palette) Reflections.UNSAFE.allocateInstance(clazz$InjectedPalettedContainer); + injectedObject.setTarget(container); + //varHandle$InjectedPalettedContainer$target.set(injectedObject, container); + } + injectedObject.ceChunk(chunk); + injectedObject.ceSection(ceSection); + injectedObject.cePos(pos); + injectedObject.setActive(true); + Reflections.varHandle$PalettedContainer$data.setVolatile(injectedObject, Reflections.varHandle$PalettedContainer$data.get(container)); + Reflections.field$LevelChunkSection$states.set(targetSection, injectedObject); } else { - injectedObject = (InjectedPalettedContainerHolder) Reflections.UNSAFE.allocateInstance(clazz$InjectedPalettedContainer); - varHandle$InjectedPalettedContainer$target.set(injectedObject, container); + holder.ceChunk(chunk); + holder.ceSection(ceSection); + holder.cePos(pos); + holder.setActive(true); + } + } else { + if (!(targetSection instanceof InjectedHolder.Section holder)) { + InjectedHolder.Section injectedObject; + if (Config.fastInjection()) { + injectedObject = FastNMS.INSTANCE.createInjectedLevelChunkSectionHolder(targetSection); + } else { + injectedObject = (InjectedHolder.Section) constructor$InjectedLevelChunkSection.invoke( + FastNMS.INSTANCE.field$LevelChunkSection$states(targetSection), FastNMS.INSTANCE.field$LevelChunkSection$biomes(targetSection)); + } + injectedObject.ceChunk(chunk); + injectedObject.ceSection(ceSection); + injectedObject.cePos(pos); + injectedObject.setActive(true); + callback.accept(injectedObject); + } else { + holder.ceChunk(chunk); + holder.ceSection(ceSection); + holder.cePos(pos); + holder.setActive(true); } - injectedObject.ceWorld(ceWorld); - injectedObject.ceChunk(chunk); - injectedObject.ceSection(ceSection); - injectedObject.cePos(pos); - Reflections.varHandle$PalettedContainer$data.setVolatile(injectedObject, Reflections.varHandle$PalettedContainer$data.get(container)); - Reflections.field$LevelChunkSection$states.set(targetSection, injectedObject); } - } catch (Exception e) { - CraftEngine.instance().logger().severe("Failed to inject chunk section", e); + } catch (Throwable e) { + CraftEngine.instance().logger().severe("Failed to inject chunk section " + pos, e); } } - public synchronized static void uninjectLevelChunkSection(Object section) { - try { - Object states = FastNMS.INSTANCE.field$LevelChunkSection$states(section); - if (states instanceof InjectedPalettedContainerHolder holder) { - Reflections.field$LevelChunkSection$states.set(section, holder.target()); - } - } catch (Exception e) { - CraftEngine.instance().logger().severe("Failed to inject chunk section", e); + public static boolean isSectionInjected(Object section) { + if (Config.injectionTarget()) { + Object container = FastNMS.INSTANCE.field$LevelChunkSection$states(section); + return container instanceof InjectedHolder.Palette; + } else { + return section instanceof InjectedHolder.Section; } } + public synchronized static Object uninjectLevelChunkSection(Object section) { + if (Config.injectionTarget()) { + Object states = FastNMS.INSTANCE.field$LevelChunkSection$states(section); + if (states instanceof InjectedHolder.Palette holder) { + holder.setActive(false); +// try { +// Reflections.field$LevelChunkSection$states.set(section, holder.target()); +// } catch (ReflectiveOperationException e) { +// CraftEngine.instance().logger().severe("Failed to uninject palette", e); +// } + } + } else { + if (section instanceof InjectedHolder.Section holder) { + holder.setActive(false); + //return FastNMS.INSTANCE.constructor$LevelChunkSection(holder); + } + } + return section; + } + public static class GetRecipeForMethodInterceptor1_20 { public static final GetRecipeForMethodInterceptor1_20 INSTANCE = new GetRecipeForMethodInterceptor1_20(); @@ -677,58 +753,82 @@ public class BukkitInjector { } } + public static class SetBlockStateInterceptor { + public static final SetBlockStateInterceptor INSTANCE = new SetBlockStateInterceptor(); + + @RuntimeType + public Object intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable superMethod) throws Exception { + InjectedHolder.Section holder = (InjectedHolder.Section) thisObj; + int x = (int) args[0]; + int y = (int) args[1]; + int z = (int) args[2]; + Object newState = args[3]; + Object previousState = superMethod.call(); + if (holder.isActive()) { + compareAndUpdateBlockState(x, y, z, newState, previousState, holder); + } + return previousState; + } + } + public static class GetAndSetInterceptor { public static final GetAndSetInterceptor INSTANCE = new GetAndSetInterceptor(); @RuntimeType public Object intercept(@This Object thisObj, @AllArguments Object[] args) { - InjectedPalettedContainerHolder holder = (InjectedPalettedContainerHolder) thisObj; + InjectedHolder.Palette holder = (InjectedHolder.Palette) thisObj; Object targetStates = holder.target(); int x = (int) args[0]; int y = (int) args[1]; int z = (int) args[2]; - Object previousState = FastNMS.INSTANCE.method$PalettedContainer$getAndSet(targetStates, x, y, z, args[3]); - try { - Object newState = args[3]; - int stateId = BlockStateUtils.blockStateToId(newState); - CESection section = holder.ceSection(); - // 如果是原版方块 - if (BlockStateUtils.isVanillaBlock(stateId)) { - // 那么应该情况自定义块 - ImmutableBlockState previous = section.setBlockState(x, y, z, EmptyBlock.STATE); - // 如果先前不是空气则标记 - if (!previous.isEmpty()) { - holder.ceChunk().setDirty(true); - } - if (Config.enableLightSystem() && Config.forceUpdateLight()) { - updateLightIfChanged(holder, previousState, newState, null, y, z, x); - } - } else { - ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockStateUnsafe(stateId); - ImmutableBlockState previousImmutableBlockState = section.setBlockState(x, y, z, immutableBlockState); - // 如果之前的自定义块(空气)和当前自定义块不同 - if (previousImmutableBlockState != immutableBlockState) { - holder.ceChunk().setDirty(true); - if (Config.enableLightSystem() && !immutableBlockState.isEmpty()) { - updateLightIfChanged(holder, previousState, newState, immutableBlockState.vanillaBlockState().handle(), y, z, x); - } - } - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to intercept setBlockState", e); + Object newState = args[3]; + Object previousState = FastNMS.INSTANCE.method$PalettedContainer$getAndSet(targetStates, x, y, z, newState); + if (holder.isActive()) { + compareAndUpdateBlockState(x, y, z, newState, previousState, holder); } return previousState; } + } - private void updateLightIfChanged(@This InjectedPalettedContainerHolder thisObj, Object previousBlockState, Object newState, @Nullable Object clientSideNewState, int y, int z, int x) throws ReflectiveOperationException { - int previousLight = BlockStateUtils.getLightEmission(previousBlockState); - int newLight = BlockStateUtils.getLightEmission(newState); - if (previousLight != newLight || (clientSideNewState != null && (BlockStateUtils.isOcclude(newState) != BlockStateUtils.isOcclude(clientSideNewState)))) { - CEWorld world = thisObj.ceWorld(); - SectionPos sectionPos = thisObj.cePos(); - Set posSet = SectionPosUtils.calculateAffectedRegions((sectionPos.x() << 4) + x, (sectionPos.y() << 4) + y, (sectionPos.z() << 4) + z, Math.max(newLight, previousLight)); - world.sectionLightUpdated(posSet); + protected static void compareAndUpdateBlockState(int x, int y, int z, Object newState, Object previousState, InjectedHolder holder) { + try { + int stateId = BlockStateUtils.blockStateToId(newState); + CESection section = holder.ceSection(); + // 如果是原版方块 + if (BlockStateUtils.isVanillaBlock(stateId)) { + // 那么应该情况自定义块 + ImmutableBlockState previous = section.setBlockState(x, y, z, EmptyBlock.STATE); + // 如果先前不是空气则标记 + if (!previous.isEmpty()) { + holder.ceChunk().setDirty(true); + } + if (Config.enableLightSystem() && Config.forceUpdateLight()) { + updateLightIfChanged(holder, previousState, newState, null, y, z, x); + } + } else { + ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockStateUnsafe(stateId); + ImmutableBlockState previousImmutableBlockState = section.setBlockState(x, y, z, immutableBlockState); + // 如果之前的自定义块(空气)和当前自定义块不同 + if (previousImmutableBlockState != immutableBlockState) { + holder.ceChunk().setDirty(true); + if (Config.enableLightSystem() && !immutableBlockState.isEmpty()) { + updateLightIfChanged(holder, previousState, newState, immutableBlockState.vanillaBlockState().handle(), y, z, x); + } + } } + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to intercept setBlockState", e); + } + } + + protected static void updateLightIfChanged(@This InjectedHolder thisObj, Object previousBlockState, Object newState, @Nullable Object clientSideNewState, int y, int z, int x) throws ReflectiveOperationException { + int previousLight = BlockStateUtils.getLightEmission(previousBlockState); + int newLight = BlockStateUtils.getLightEmission(newState); + if (previousLight != newLight || (clientSideNewState != null && (BlockStateUtils.isOcclude(newState) != BlockStateUtils.isOcclude(clientSideNewState)))) { + CEWorld world = thisObj.ceChunk().world(); + SectionPos sectionPos = thisObj.cePos(); + Set posSet = SectionPosUtils.calculateAffectedRegions((sectionPos.x() << 4) + x, (sectionPos.y() << 4) + y, (sectionPos.z() << 4) + z, Math.max(newLight, previousLight)); + world.sectionLightUpdated(posSet); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java index 0b9b202fa..a5cb326fc 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java @@ -1,5 +1,6 @@ package net.momirealms.craftengine.bukkit.plugin.network; +import com.mojang.datafixers.util.Either; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import it.unimi.dsi.fastutil.ints.IntList; @@ -33,6 +34,7 @@ import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.network.ConnectionState; import net.momirealms.craftengine.core.plugin.network.NetWorkUser; import net.momirealms.craftengine.core.plugin.network.NetworkManager; +import net.momirealms.craftengine.core.plugin.network.ProtocolVersion; import net.momirealms.craftengine.core.util.*; import net.momirealms.craftengine.core.world.BlockHitResult; import net.momirealms.craftengine.core.world.BlockPos; @@ -52,6 +54,7 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; import org.bukkit.util.RayTraceResult; import org.bukkit.util.Vector; +import org.jetbrains.annotations.Nullable; import java.lang.reflect.InvocationTargetException; import java.nio.charset.StandardCharsets; @@ -198,7 +201,6 @@ public class PacketConsumers { buf.writeInt(chunkZ); if (VersionHelper.isOrAbove1_21_5()) { buf.writeVarInt(heightmapsCount); - assert heightmapsMap != null; for (Map.Entry entry : heightmapsMap.entrySet()) { buf.writeVarInt(entry.getKey()); buf.writeLongArray(entry.getValue()); @@ -331,8 +333,17 @@ public class PacketConsumers { Tag displayName = buf.readNbt(false); if (displayName == null) return; byte friendlyFlags = buf.readByte(); - String nameTagVisibility = buf.readUtf(40); - String collisionRule = buf.readUtf(40); + + Either eitherVisibility; + Either eitherCollisionRule; + + if (VersionHelper.isOrAbove1_21_5()) { + eitherVisibility = Either.right(buf.readVarInt()); + eitherCollisionRule = Either.right(buf.readVarInt()); + } else { + eitherVisibility = Either.left(buf.readUtf(40)); + eitherCollisionRule = Either.left(buf.readUtf(40)); + } int color = buf.readVarInt(); Tag prefix = buf.readNbt(false); if (prefix == null) return; @@ -368,8 +379,8 @@ public class PacketConsumers { } buf.writeByte(friendlyFlags); - buf.writeUtf(nameTagVisibility); - buf.writeUtf(collisionRule); + eitherVisibility.ifLeft(buf::writeUtf).ifRight(buf::writeVarInt); + eitherCollisionRule.ifLeft(buf::writeUtf).ifRight(buf::writeVarInt); buf.writeVarInt(color); if (!tokens2.isEmpty()) { @@ -1339,7 +1350,7 @@ public class PacketConsumers { // When the hotbar is full, the latest creative mode inventory can only be accessed when the player opens the inventory screen. Currently, it is not worth further handling this issue. public static final TriConsumer SET_CREATIVE_SLOT = (user, event, packet) -> { try { - if (VersionHelper.isOrAbove1_21_4()) return; + if (user.protocolVersion().isVersionNewerThan(ProtocolVersion.V1_21_4)) return; if (!user.isOnline()) return; BukkitServerPlayer player = (BukkitServerPlayer) user; if (VersionHelper.isFolia()) { @@ -1349,7 +1360,7 @@ public class PacketConsumers { } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to handle ServerboundSetCreativeModeSlotPacket", e); } - }, (World) player.level().platformWorld(), (MCUtils.fastFloor(player.x())) >> 4, (MCUtils.fastFloor(player.z())) >> 4); + }, (World) player.world().platformWorld(), (MCUtils.fastFloor(player.x())) >> 4, (MCUtils.fastFloor(player.z())) >> 4); } else { handleSetCreativeSlotPacketOnMainThread(player, packet); } @@ -1469,7 +1480,7 @@ public class PacketConsumers { if (state == null) return; Key itemId = state.settings().itemId(); if (itemId == null) return; - pickItem(player, itemId); + pickItem(player, itemId, pos, null); } // 1.21.4+ @@ -1508,18 +1519,24 @@ public class PacketConsumers { private static void handlePickItemFromEntityOnMainThread(Player player, LoadedFurniture furniture) throws Exception { Key itemId = furniture.config().settings().itemId(); if (itemId == null) return; - pickItem(player, itemId); + pickItem(player, itemId, null, FastNMS.INSTANCE.method$CraftEntity$getHandle(furniture.baseEntity())); } - private static void pickItem(Player player, Key itemId) throws IllegalAccessException, InvocationTargetException { + private static void pickItem(Player player, Key itemId, @Nullable Object blockPos, @Nullable Object entity) throws IllegalAccessException, InvocationTargetException { ItemStack itemStack = BukkitCraftEngine.instance().itemManager().buildCustomItemStack(itemId, BukkitCraftEngine.instance().adapt(player)); if (itemStack == null) { CraftEngine.instance().logger().warn("Item: " + itemId + " is not a valid item"); return; } assert Reflections.method$ServerGamePacketListenerImpl$tryPickItem != null; - Reflections.method$ServerGamePacketListenerImpl$tryPickItem.invoke( - Reflections.field$ServerPlayer$connection.get(FastNMS.INSTANCE.method$CraftPlayer$getHandle(player)), FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack)); + if (VersionHelper.isOrAbove1_21_5()) { + Reflections.method$ServerGamePacketListenerImpl$tryPickItem.invoke( + Reflections.field$ServerPlayer$connection.get(FastNMS.INSTANCE.method$CraftPlayer$getHandle(player)), + FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack), blockPos, entity, true); + } else { + Reflections.method$ServerGamePacketListenerImpl$tryPickItem.invoke( + Reflections.field$ServerPlayer$connection.get(FastNMS.INSTANCE.method$CraftPlayer$getHandle(player)), FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack)); + } } public static final BiConsumer ADD_ENTITY_BYTEBUFFER = (user, event) -> { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java index 13341b5b2..c3352106c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java @@ -26,6 +26,8 @@ import net.momirealms.craftengine.core.world.BlockPos; import net.momirealms.craftengine.core.world.World; import net.momirealms.craftengine.core.world.WorldEvents; import org.bukkit.*; +import org.bukkit.attribute.Attribute; +import org.bukkit.attribute.AttributeInstance; import org.bukkit.block.Block; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; @@ -427,8 +429,8 @@ public class BukkitServerPlayer extends Player { } else { if (VersionHelper.isOrAbove1_20_5()) { Object attributeModifier = VersionHelper.isOrAbove1_21() ? - Reflections.constructor$AttributeModifier.newInstance(KeyUtils.toResourceLocation("craftengine", "custom_hardness"), -9999d, Reflections.instance$AttributeModifier$Operation$ADD_VALUE) : - Reflections.constructor$AttributeModifier.newInstance(UUID.randomUUID(), "craftengine:custom_hardness", -9999d, Reflections.instance$AttributeModifier$Operation$ADD_VALUE); + Reflections.constructor$AttributeModifier.newInstance(KeyUtils.toResourceLocation(Key.DEFAULT_NAMESPACE, "custom_hardness"), -9999d, Reflections.instance$AttributeModifier$Operation$ADD_VALUE) : + Reflections.constructor$AttributeModifier.newInstance(UUID.randomUUID(), Key.DEFAULT_NAMESPACE + ":custom_hardness", -9999d, Reflections.instance$AttributeModifier$Operation$ADD_VALUE); Object attributeSnapshot = Reflections.constructor$ClientboundUpdateAttributesPacket$AttributeSnapshot.newInstance(Reflections.instance$Holder$Attribute$block_break_speed, 1d, Lists.newArrayList(attributeModifier)); Object newPacket = Reflections.constructor$ClientboundUpdateAttributesPacket1.newInstance(entityID(), Lists.newArrayList(attributeSnapshot)); sendPacket(newPacket, true); @@ -677,7 +679,7 @@ public class BukkitServerPlayer extends Player { } @Override - public World level() { + public World world() { return new BukkitWorld(platformPlayer().getWorld()); } @@ -800,4 +802,18 @@ public class BukkitServerPlayer extends Player { this.resourcePackUUID.clear(); } } + + @Override + public void performCommand(String command) { + platformPlayer().performCommand(command); + } + + @Override + public double luck() { + if (VersionHelper.isOrAbove1_21_3()) { + return Optional.ofNullable(platformPlayer().getAttribute(Attribute.LUCK)).map(AttributeInstance::getValue).orElse(1d); + } else { + return LegacyAttributeUtils.getLuck(platformPlayer()); + } + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ParticleUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ParticleUtils.java index 3b44594e6..6e847f6f9 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ParticleUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ParticleUtils.java @@ -11,7 +11,7 @@ public class ParticleUtils { } catch (IllegalArgumentException e) { return switch (particle) { case "REDSTONE" -> Particle.valueOf("DUST"); - case "VILLAGER_HAPPY" -> Particle.valueOf(VersionHelper.isOrAbove1_20_5() ? "HAPPY_VILLAGER" : "VILLAGER_HAPPY"); + case "VILLAGER_HAPPY", "HAPPY_VILLAGER" -> Particle.valueOf(VersionHelper.isOrAbove1_20_5() ? "HAPPY_VILLAGER" : "VILLAGER_HAPPY"); default -> Particle.valueOf(particle); }; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java index 85165e2e5..3ffed4d5b 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java @@ -1928,7 +1928,6 @@ public class Reflections { // field$ChunkAccess$blockEntities = targetField; // } - @Deprecated public static final Method method$LevelChunkSection$setBlockState = requireNonNull( ReflectionUtils.getMethod( clazz$LevelChunkSection, clazz$BlockState, int.class, int.class, int.class, clazz$BlockState, boolean.class @@ -4963,10 +4962,10 @@ public class Reflections { public static final Method method$BonemealableBlock$isValidBonemealTarget = requireNonNull( VersionHelper.isOrAbove1_20_2() ? - ReflectionUtils.getMethod( + ReflectionUtils.getInstanceMethod( clazz$BonemealableBlock, boolean.class, clazz$LevelReader, clazz$BlockPos, clazz$BlockState ) : - ReflectionUtils.getMethod( + ReflectionUtils.getInstanceMethod( clazz$BonemealableBlock, boolean.class, clazz$LevelReader, clazz$BlockPos, clazz$BlockState, boolean.class ) ); @@ -5030,6 +5029,10 @@ public class Reflections { ); public static final Method method$ServerGamePacketListenerImpl$tryPickItem = + VersionHelper.isOrAbove1_21_5() ? + ReflectionUtils.getDeclaredMethod( + clazz$ServerGamePacketListenerImpl, void.class, clazz$ItemStack, clazz$BlockPos, clazz$Entity, boolean.class + ) : ReflectionUtils.getDeclaredMethod( clazz$ServerGamePacketListenerImpl, void.class, clazz$ItemStack ); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldBlock.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitBlockInWorld.java similarity index 64% rename from bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldBlock.java rename to bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitBlockInWorld.java index 105ac4443..a7dc16a3d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldBlock.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitBlockInWorld.java @@ -1,10 +1,12 @@ package net.momirealms.craftengine.bukkit.world; +import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks; import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.item.behavior.BlockItemBehavior; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; +import net.momirealms.craftengine.bukkit.util.KeyUtils; import net.momirealms.craftengine.bukkit.util.LocationUtils; import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.block.ImmutableBlockState; @@ -13,24 +15,25 @@ import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.context.BlockPlaceContext; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.world.WorldBlock; +import net.momirealms.craftengine.core.world.BlockInWorld; +import net.momirealms.craftengine.core.world.World; import org.bukkit.Location; import org.bukkit.block.Block; import org.bukkit.inventory.ItemStack; import java.util.Optional; -public class BukkitWorldBlock implements WorldBlock { +public class BukkitBlockInWorld implements BlockInWorld { private final Block block; - public BukkitWorldBlock(Block block) { + public BukkitBlockInWorld(Block block) { this.block = block; } @SuppressWarnings("unchecked") @Override public boolean canBeReplaced(BlockPlaceContext context) { - ImmutableBlockState customState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockDataToId(block.getBlockData())); + ImmutableBlockState customState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockDataToId(this.block.getBlockData())); if (customState != null && !customState.isEmpty()) { Key clickedBlockId = customState.owner().value().id(); Item item = (Item) context.getPlayer().getItemInHand(context.getHand()); @@ -45,14 +48,14 @@ public class BukkitWorldBlock implements WorldBlock { } } } - return block.isReplaceable(); + return this.block.isReplaceable(); } @Override public boolean isWaterSource(BlockPlaceContext blockPlaceContext) { try { - Location location = block.getLocation(); - Object serverLevel = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(block.getWorld()); + Location location = this.block.getLocation(); + Object serverLevel = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(this.block.getWorld()); Object fluidData = Reflections.method$Level$getFluidState.invoke(serverLevel, LocationUtils.toBlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ())); if (fluidData == null) return false; return Reflections.method$FluidState$getType.invoke(fluidData) == Reflections.instance$Fluids$WATER; @@ -62,7 +65,45 @@ public class BukkitWorldBlock implements WorldBlock { } } + @Override + public int x() { + return this.block.getX(); + } + + @Override + public int y() { + return this.block.getY(); + } + + @Override + public int z() { + return this.block.getZ(); + } + + @Override + public World world() { + return new BukkitWorld(this.block.getWorld()); + } + + @Override + public String getAsString() { + ImmutableBlockState state = CraftEngineBlocks.getCustomBlockState(this.block); + if (state != null) { + return state.toString(); + } + return this.block.getBlockData().getAsString(); + } + + @Override + public Key owner() { + ImmutableBlockState state = CraftEngineBlocks.getCustomBlockState(this.block); + if (state != null) { + return state.owner().value().id(); + } + return KeyUtils.namespacedKey2Key(this.block.getType().getKey()); + } + public Block block() { - return block; + return this.block; } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java index b63a851ac..5223b9bd4 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java @@ -6,9 +6,9 @@ import net.momirealms.craftengine.bukkit.util.ItemUtils; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.VersionHelper; +import net.momirealms.craftengine.core.world.BlockInWorld; import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.core.world.World; -import net.momirealms.craftengine.core.world.WorldBlock; import net.momirealms.craftengine.core.world.WorldHeight; import org.bukkit.Location; import org.bukkit.SoundCategory; @@ -51,8 +51,8 @@ public class BukkitWorld implements World { } @Override - public WorldBlock getBlockAt(int x, int y, int z) { - return new BukkitWorldBlock(platformWorld().getBlockAt(x, y, z)); + public BlockInWorld getBlockAt(int x, int y, int z) { + return new BukkitBlockInWorld(platformWorld().getBlockAt(x, y, z)); } @Override diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java index c644076c8..d527a0ab7 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java @@ -266,23 +266,24 @@ public class BukkitWorldManager implements WorldManager, Listener { if (ceChunk != null) { if (ceChunk.dirty()) { try { - world.worldDataStorage().writeChunkAt(pos, ceChunk, false); + this.plugin.debug(() -> "[Dirty Chunk]" + pos + " unloaded"); + world.worldDataStorage().writeChunkAt(pos, ceChunk); ceChunk.setDirty(false); } catch (IOException e) { this.plugin.logger().warn("Failed to write chunk tag at " + chunk.getX() + " " + chunk.getZ(), e); } } - if (Config.restoreVanillaBlocks()) { - boolean unsaved = false; - CESection[] ceSections = ceChunk.sections(); - Object worldServer = FastNMS.INSTANCE.field$CraftChunk$worldServer(chunk); - Object chunkSource = FastNMS.INSTANCE.method$ServerLevel$getChunkSource(worldServer); - Object levelChunk = FastNMS.INSTANCE.method$ServerChunkCache$getChunkAtIfLoadedMainThread(chunkSource, chunk.getX(), chunk.getZ()); - Object[] sections = FastNMS.INSTANCE.method$ChunkAccess$getSections(levelChunk); - for (int i = 0; i < ceSections.length; i++) { - CESection ceSection = ceSections[i]; - Object section = sections[i]; - BukkitInjector.uninjectLevelChunkSection(section); + boolean unsaved = false; + CESection[] ceSections = ceChunk.sections(); + Object worldServer = FastNMS.INSTANCE.field$CraftChunk$worldServer(chunk); + Object chunkSource = FastNMS.INSTANCE.method$ServerLevel$getChunkSource(worldServer); + Object levelChunk = FastNMS.INSTANCE.method$ServerChunkCache$getChunkAtIfLoadedMainThread(chunkSource, chunk.getX(), chunk.getZ()); + Object[] sections = FastNMS.INSTANCE.method$ChunkAccess$getSections(levelChunk); + for (int i = 0; i < ceSections.length; i++) { + CESection ceSection = ceSections[i]; + Object section = sections[i]; + BukkitInjector.uninjectLevelChunkSection(section); + if (Config.restoreVanillaBlocks()) { if (!ceSection.statesContainer().isEmpty()) { for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { @@ -297,9 +298,9 @@ public class BukkitWorldManager implements WorldManager, Listener { } } } - if (unsaved && !FastNMS.INSTANCE.method$LevelChunk$isUnsaved(levelChunk)) { - FastNMS.INSTANCE.method$LevelChunk$markUnsaved(levelChunk); - } + } + if (unsaved && !FastNMS.INSTANCE.method$LevelChunk$isUnsaved(levelChunk)) { + FastNMS.INSTANCE.method$LevelChunk$markUnsaved(levelChunk); } ceChunk.unload(); } @@ -383,7 +384,9 @@ public class BukkitWorldManager implements WorldManager, Listener { } } } - BukkitInjector.injectLevelChunkSection(section, ceSection, ceWorld, ceChunk, new SectionPos(pos.x, ceChunk.sectionY(i), pos.z)); + int finalI = i; + BukkitInjector.injectLevelChunkSection(section, ceSection, ceChunk, new SectionPos(pos.x, ceChunk.sectionY(i), pos.z), + (injected) -> sections[finalI] = injected); } if (Config.enableRecipeSystem()) { @SuppressWarnings("unchecked") diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 0ba9d3b0a..83e995a17 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -52,8 +52,12 @@ dependencies { // Aho-Corasick java implementation compileOnly("org.ahocorasick:ahocorasick:${rootProject.properties["ahocorasick_version"]}") // Amazon S3 - compileOnly("software.amazon.awssdk:s3:${rootProject.properties["amazon_awssdk_version"]}") + compileOnly("software.amazon.awssdk:s3:${rootProject.properties["amazon_awssdk_version"]}") { + + } compileOnly("software.amazon.awssdk:netty-nio-client:${rootProject.properties["amazon_awssdk_version"]}") + // EvalEx + compileOnly("com.ezylang:EvalEx:${rootProject.properties["evalex_version"]}") } java { @@ -85,6 +89,7 @@ tasks { relocate("net.jpountz", "net.momirealms.craftengine.libraries.jpountz") // lz4 relocate("software.amazon.awssdk", "net.momirealms.craftengine.libraries.awssdk") // awssdk relocate("software.amazon.eventstream", "net.momirealms.craftengine.libraries.eventstream") // awssdk + relocate("com.ezylang.evalex", "net.momirealms.craftengine.libraries.evalex") } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/ImmutableBlockState.java b/core/src/main/java/net/momirealms/craftengine/core/block/ImmutableBlockState.java index 4f6ca3a96..7e53699aa 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/ImmutableBlockState.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/ImmutableBlockState.java @@ -2,16 +2,18 @@ package net.momirealms.craftengine.core.block; import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap; import net.momirealms.craftengine.core.block.properties.Property; +import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.loot.LootTable; -import net.momirealms.craftengine.core.loot.parameter.LootParameters; +import net.momirealms.craftengine.core.plugin.context.ContextHolder; +import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; import net.momirealms.craftengine.core.registry.Holder; -import net.momirealms.craftengine.core.util.context.ContextHolder; import net.momirealms.craftengine.core.world.World; import net.momirealms.craftengine.shared.block.BlockBehavior; import net.momirealms.sparrow.nbt.CompoundTag; import net.momirealms.sparrow.nbt.NBT; import net.momirealms.sparrow.nbt.Tag; +import org.jetbrains.annotations.NotNull; import javax.annotation.Nullable; import java.util.List; @@ -138,12 +140,16 @@ public class ImmutableBlockState extends BlockStateHolder { return state.with(property, (T) value); } + public List> getDrops(@NotNull ContextHolder.Builder builder, @NotNull World world) { + return this.getDrops(builder, world, null); + } + @SuppressWarnings("unchecked") - public List> getDrops(ContextHolder.Builder builder, World world) { + public List> getDrops(@NotNull ContextHolder.Builder builder, @NotNull World world, @Nullable Player player) { CustomBlock block = owner.value(); if (block == null) return List.of(); LootTable lootTable = (LootTable) block.lootTable(); if (lootTable == null) return List.of(); - return lootTable.getRandomItems(builder.withParameter(LootParameters.BLOCK_STATE, this).build(), world); + return lootTable.getRandomItems(builder.withParameter(CommonParameters.BLOCK_STATE, this).build(), world, player); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/UpdateOption.java b/core/src/main/java/net/momirealms/craftengine/core/block/UpdateOption.java index 98286d2ea..ae1c652ad 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/UpdateOption.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/UpdateOption.java @@ -14,6 +14,10 @@ public class UpdateOption { return flags; } + public static Builder builder() { + return new Builder(); + } + public static class Builder { private int flags; diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/behavior/BlockBehaviors.java b/core/src/main/java/net/momirealms/craftengine/core/block/behavior/BlockBehaviors.java index e67a96dc1..d75ffc494 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/behavior/BlockBehaviors.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/behavior/BlockBehaviors.java @@ -27,7 +27,7 @@ public class BlockBehaviors { public static BlockBehavior fromMap(CustomBlock block, @Nullable Map map) { if (map == null || map.isEmpty()) return EmptyBlockBehavior.INSTANCE; String type = ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("type"), "warning.config.block.behavior.missing_type"); - Key key = Key.withDefaultNamespace(type, "craftengine"); + Key key = Key.withDefaultNamespace(type, Key.DEFAULT_NAMESPACE); BlockBehaviorFactory factory = BuiltInRegistries.BLOCK_BEHAVIOR_FACTORY.getValue(key); if (factory == null) { throw new LocalizedResourceConfigException("warning.config.block.behavior.invalid_type", type.toString()); diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/properties/Properties.java b/core/src/main/java/net/momirealms/craftengine/core/block/properties/Properties.java index bf1b1c0a5..44194f07a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/properties/Properties.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/properties/Properties.java @@ -33,7 +33,7 @@ public class Properties { public static Property fromMap(String name, Map map) { String type = ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("type"), "warning.config.block.state.property.missing_type"); - Key key = Key.withDefaultNamespace(type, "craftengine"); + Key key = Key.withDefaultNamespace(type, Key.DEFAULT_NAMESPACE); PropertyFactory factory = BuiltInRegistries.PROPERTY_FACTORY.getValue(key); if (factory == null) { throw new LocalizedResourceConfigException("warning.config.block.state.property.invalid_type", key.toString(), name); diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/Entity.java b/core/src/main/java/net/momirealms/craftengine/core/entity/Entity.java index fd45a8f1c..24efd4208 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/Entity.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/Entity.java @@ -1,16 +1,24 @@ package net.momirealms.craftengine.core.entity; import net.momirealms.craftengine.core.util.Direction; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.core.world.World; public abstract class Entity { + public abstract Key type(); + public abstract double x(); public abstract double y(); public abstract double z(); + public Vec3d position() { + return new Vec3d(x(), y(), z()); + } + public abstract void tick(); public abstract int entityID(); @@ -19,7 +27,7 @@ public abstract class Entity { public abstract float getYRot(); - public abstract World level(); + public abstract World world(); public abstract Direction getDirection(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java b/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java index 0af8d0e34..48d6b6185 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java @@ -11,6 +11,7 @@ import org.jetbrains.annotations.Nullable; import java.util.List; public abstract class Player extends Entity implements NetWorkUser { + private static final Key TYPE = Key.of("minecraft:player"); public abstract boolean isSecondaryUseActive(); @@ -84,4 +85,13 @@ public abstract class Player extends Entity implements NetWorkUser { public abstract void clearView(); public abstract void unloadCurrentResourcePack(); + + public abstract void performCommand(String command); + + public abstract double luck(); + + @Override + public Key type() { + return TYPE; + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java b/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java index 3277303cf..aa7a7797e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java @@ -7,11 +7,11 @@ import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.pack.ResourceLocation; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; +import net.momirealms.craftengine.core.plugin.context.ContextHolder; +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.plugin.locale.TranslationManager; import net.momirealms.craftengine.core.util.*; -import net.momirealms.craftengine.core.util.context.ContextHolder; -import net.momirealms.craftengine.core.util.context.PlayerContext; import org.ahocorasick.trie.Token; import org.ahocorasick.trie.Trie; import org.jetbrains.annotations.NotNull; @@ -121,10 +121,10 @@ public abstract class AbstractFontManager implements FontManager { continue; Component content = AdventureHelper.miniMessage().deserialize( emoji.content(), - PlayerContext.of(player, ContextHolder.builder() + PlayerOptionalContext.of(player, ContextHolder.builder() .withOptionalParameter(EmojiParameters.EMOJI, emoji.emojiImage()) .withParameter(EmojiParameters.KEYWORD, emoji.keywords().get(0)) - .build()).tagResolvers() + ).tagResolvers() ); replacements.put(fragment, AdventureHelper.componentToMiniMessage(content)); } @@ -167,10 +167,10 @@ public abstract class AbstractFontManager implements FontManager { continue; emojis.put(fragment, AdventureHelper.miniMessage().deserialize( emoji.content(), - PlayerContext.of(player, ContextHolder.builder() + PlayerOptionalContext.of(player, ContextHolder.builder() .withOptionalParameter(EmojiParameters.EMOJI, emoji.emojiImage()) .withParameter(EmojiParameters.KEYWORD, emoji.keywords().get(0)) - .build()).tagResolvers()) + ).tagResolvers()) ); if (emojis.size() >= maxTimes) break; } @@ -199,11 +199,9 @@ public abstract class AbstractFontManager implements FontManager { continue; emojis.put(fragment, AdventureHelper.miniMessage().deserialize( emoji.content(), - PlayerContext.of(player, - ContextHolder.builder() - .withOptionalParameter(EmojiParameters.EMOJI, emoji.emojiImage()) - .withParameter(EmojiParameters.KEYWORD, emoji.keywords().get(0)) - .build() + PlayerOptionalContext.of(player, ContextHolder.builder() + .withOptionalParameter(EmojiParameters.EMOJI, emoji.emojiImage()) + .withParameter(EmojiParameters.KEYWORD, emoji.keywords().get(0)) ).tagResolvers() )); if (emojis.size() >= maxTimes) break; @@ -454,15 +452,32 @@ public abstract class AbstractFontManager implements FontManager { return it.toCharArray(); } }).toList(); + if (chars.isEmpty()) { + throw new LocalizedResourceConfigException("warning.config.image.missing_char", path, id); + } } else { if (charsObj instanceof Integer integer) { chars = List.of(new char[]{(char) integer.intValue()}); } else { String character = charsObj.toString(); + if (character.isEmpty()) { + throw new LocalizedResourceConfigException("warning.config.image.missing_char", path, id); + } if (character.length() == 1) { chars = List.of(character.toCharArray()); } else { - chars = List.of(CharacterUtils.decodeUnicodeToChars(character)); + if (character.startsWith("\\u")) { + chars = List.of(CharacterUtils.decodeUnicodeToChars(character)); + } else { + if (CharacterUtils.containsCombinedCharacter(character)) { + TranslationManager.instance().log("warning.config.image.invalid_char", path.toString(), id.toString()); + } + StringBuilder stringBuilder = new StringBuilder(); + for (char c : character.toCharArray()) { + stringBuilder.append(String.format("\\u%04x", (int) c)); + } + chars = List.of(CharacterUtils.decodeUnicodeToChars(stringBuilder.toString())); + } } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/font/EmojiParameters.java b/core/src/main/java/net/momirealms/craftengine/core/font/EmojiParameters.java index 83c91536d..5cf91415a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/font/EmojiParameters.java +++ b/core/src/main/java/net/momirealms/craftengine/core/font/EmojiParameters.java @@ -1,9 +1,10 @@ package net.momirealms.craftengine.core.font; -import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.context.ContextKey; +import net.momirealms.craftengine.core.plugin.context.ContextKey; -public class EmojiParameters { - public static final ContextKey KEYWORD = new ContextKey<>(Key.of("keyword")); - public static final ContextKey EMOJI = new ContextKey<>(Key.of("emoji")); +public final class EmojiParameters { + private EmojiParameters() {} + + public static final ContextKey KEYWORD = ContextKey.of("keyword"); + public static final ContextKey EMOJI = ContextKey.of("emoji"); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/BuildableItem.java b/core/src/main/java/net/momirealms/craftengine/core/item/BuildableItem.java index 3f755d6b1..ed2e23317 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/BuildableItem.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/BuildableItem.java @@ -1,8 +1,8 @@ package net.momirealms.craftengine.core.item; import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.context.ContextHolder; public interface BuildableItem { diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/CustomItem.java b/core/src/main/java/net/momirealms/craftengine/core/item/CustomItem.java index 6d72163f1..b4ff58f2a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/CustomItem.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/CustomItem.java @@ -4,7 +4,6 @@ import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.context.ContextHolder; import org.jetbrains.annotations.NotNull; import java.util.List; @@ -35,7 +34,7 @@ public interface CustomItem extends BuildableItem { } default Item buildItem(Player player) { - return buildItem(ItemBuildContext.of(player, ContextHolder.EMPTY)); + return buildItem(ItemBuildContext.of(player)); } Item buildItem(ItemBuildContext context); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemBuildContext.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemBuildContext.java index 5f7ccfd0a..521907dc3 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemBuildContext.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemBuildContext.java @@ -1,12 +1,15 @@ package net.momirealms.craftengine.core.item; import net.momirealms.craftengine.core.entity.player.Player; -import net.momirealms.craftengine.core.util.context.ContextHolder; -import net.momirealms.craftengine.core.util.context.PlayerContext; +import net.momirealms.craftengine.core.plugin.context.ContextHolder; +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; +import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class ItemBuildContext extends PlayerContext { +import java.util.Map; + +public class ItemBuildContext extends PlayerOptionalContext { public static final ItemBuildContext EMPTY = new ItemBuildContext(null, ContextHolder.EMPTY); public ItemBuildContext(@Nullable Player player, @NotNull ContextHolder contexts) { @@ -17,4 +20,16 @@ public class ItemBuildContext extends PlayerContext { public static ItemBuildContext of(@Nullable Player player, @NotNull ContextHolder contexts) { return new ItemBuildContext(player, contexts); } + + @NotNull + public static ItemBuildContext of(@Nullable Player player, @NotNull ContextHolder.Builder builder) { + if (player != null) builder.withParameter(CommonParameters.PLAYER, player); + return new ItemBuildContext(player, builder.build()); + } + + @NotNull + public static ItemBuildContext of(@Nullable Player player) { + if (player == null) return new ItemBuildContext(null, ContextHolder.EMPTY); + return new ItemBuildContext(player, new ContextHolder(Map.of(CommonParameters.PLAYER, () -> player))); + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/behavior/ItemBehaviors.java b/core/src/main/java/net/momirealms/craftengine/core/item/behavior/ItemBehaviors.java index c2217ec6a..af0524d2a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/behavior/ItemBehaviors.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/behavior/ItemBehaviors.java @@ -14,7 +14,7 @@ import java.nio.file.Path; import java.util.Map; public class ItemBehaviors { - public static final Key EMPTY = Key.from("craftengine:empty"); + public static final Key EMPTY = Key.withDefaultNamespace("empty", Key.DEFAULT_NAMESPACE); public static void register(Key key, ItemBehaviorFactory factory) { Holder.Reference holder = ((WritableRegistry) BuiltInRegistries.ITEM_BEHAVIOR_FACTORY) @@ -25,7 +25,7 @@ public class ItemBehaviors { public static ItemBehavior fromMap(Pack pack, Path path, Key id, Map map) { if (map == null || map.isEmpty()) return EmptyItemBehavior.INSTANCE; String type = ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("type"), "warning.config.item.behavior.missing_type"); - Key key = Key.withDefaultNamespace(type, "craftengine"); + Key key = Key.withDefaultNamespace(type, Key.DEFAULT_NAMESPACE); ItemBehaviorFactory factory = BuiltInRegistries.ITEM_BEHAVIOR_FACTORY.getValue(key); if (factory == null) { throw new LocalizedResourceConfigException("warning.config.item.behavior.invalid_type", type.toString()); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/context/UseOnContext.java b/core/src/main/java/net/momirealms/craftengine/core/item/context/UseOnContext.java index ff6a6514e..5e6280e02 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/context/UseOnContext.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/context/UseOnContext.java @@ -17,7 +17,7 @@ public class UseOnContext { private final Item itemStack; public UseOnContext(Player player, InteractionHand hand, BlockHitResult hit) { - this(player.level(), player, hand, player.getItemInHand(hand), hit); + this(player.world(), player, hand, player.getItemInHand(hand), hit); } public UseOnContext(World world, Player player, InteractionHand hand, Item stack, BlockHitResult hit) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTransformRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTransformRecipe.java index 1742fcc19..b4698e00b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTransformRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTransformRecipe.java @@ -184,16 +184,16 @@ public class CustomSmithingTransformRecipe implements Recipe { if (type == null) { throw new LocalizedResourceConfigException("warning.config.recipe.smithing_transform.post_processor.missing_type"); } - Key key = Key.withDefaultNamespace(type, "craftengine"); - ItemDataProcessor.Factory factory = BuiltInRegistries.SMITHING_RESULT_PROCESSOR_FACTORY.getValue(key); + Key key = Key.withDefaultNamespace(type, Key.DEFAULT_NAMESPACE); + ItemDataProcessor.ProcessorFactory factory = BuiltInRegistries.SMITHING_RESULT_PROCESSOR_FACTORY.getValue(key); if (factory == null) { throw new LocalizedResourceConfigException("warning.config.recipe.smithing_transform.post_processor.invalid_type", type); } return factory.create(map); } - public static void register(Key key, ItemDataProcessor.Factory factory) { - Holder.Reference holder = ((WritableRegistry) BuiltInRegistries.SMITHING_RESULT_PROCESSOR_FACTORY) + public static void register(Key key, ItemDataProcessor.ProcessorFactory factory) { + Holder.Reference holder = ((WritableRegistry) BuiltInRegistries.SMITHING_RESULT_PROCESSOR_FACTORY) .registerForHolder(new ResourceKey<>(Registries.SMITHING_RESULT_PROCESSOR_FACTORY.location(), key)); holder.bindValue(factory); } @@ -203,7 +203,7 @@ public class CustomSmithingTransformRecipe implements Recipe { Key type(); - interface Factory { + interface ProcessorFactory { ItemDataProcessor create(Map arguments); } } @@ -231,7 +231,7 @@ public class CustomSmithingTransformRecipe implements Recipe { return ItemDataProcessors.KEEP_COMPONENTS; } - public static class Factory implements ItemDataProcessor.Factory { + public static class Factory implements ProcessorFactory { @Override public ItemDataProcessor create(Map arguments) { @@ -268,7 +268,7 @@ public class CustomSmithingTransformRecipe implements Recipe { return ItemDataProcessors.KEEP_TAGS; } - public static class Factory implements ItemDataProcessor.Factory { + public static class Factory implements ProcessorFactory { @Override public ItemDataProcessor create(Map arguments) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/LootConditions.java b/core/src/main/java/net/momirealms/craftengine/core/loot/LootConditions.java new file mode 100644 index 000000000..0dc4c9a32 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/LootConditions.java @@ -0,0 +1,101 @@ +package net.momirealms.craftengine.core.loot; + +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.condition.*; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; +import net.momirealms.craftengine.core.registry.BuiltInRegistries; +import net.momirealms.craftengine.core.registry.Holder; +import net.momirealms.craftengine.core.registry.Registries; +import net.momirealms.craftengine.core.registry.WritableRegistry; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.core.util.ResourceKey; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; + +public class LootConditions { + + static { + register(CommonConditions.MATCH_ITEM, new MatchItemCondition.FactoryImpl<>()); + register(CommonConditions.MATCH_BLOCK_PROPERTY, new MatchBlockPropertyCondition.FactoryImpl<>()); + register(CommonConditions.TABLE_BONUS, new TableBonusCondition.FactoryImpl<>()); + register(CommonConditions.SURVIVES_EXPLOSION, new SurvivesExplosionCondition.FactoryImpl<>()); + register(CommonConditions.ANY_OF, new AnyOfCondition.FactoryImpl<>(LootConditions::fromMap)); + register(CommonConditions.ALL_OF, new AllOfCondition.FactoryImpl<>(LootConditions::fromMap)); + register(CommonConditions.ENCHANTMENT, new EnchantmentCondition.FactoryImpl<>()); + register(CommonConditions.INVERTED, new InvertedCondition.FactoryImpl<>(LootConditions::fromMap)); + register(CommonConditions.FALLING_BLOCK, new FallingBlockCondition.FactoryImpl<>()); + register(CommonConditions.RANDOM, new RandomCondition.FactoryImpl<>()); + register(CommonConditions.DISTANCE, new DistanceCondition.FactoryImpl<>()); + } + + public static void register(Key key, ConditionFactory factory) { + Holder.Reference> holder = ((WritableRegistry>) BuiltInRegistries.LOOT_CONDITION_FACTORY) + .registerForHolder(new ResourceKey<>(Registries.LOOT_CONDITION_FACTORY.location(), key)); + holder.bindValue(factory); + } + + public static Predicate andConditions(List> predicates) { + List> list = List.copyOf(predicates); + return switch (list.size()) { + case 0 -> ctx -> true; + case 1 -> list.get(0); + case 2 -> list.get(0).and(list.get(1)); + default -> (ctx -> { + for (Predicate predicate : list) { + if (!predicate.test(ctx)) { + return false; + } + } + return true; + }); + }; + } + + public static Predicate orConditions(List> predicates) { + List> list = List.copyOf(predicates); + return switch (list.size()) { + case 0 -> ctx -> false; + case 1 -> list.get(0); + case 2 -> list.get(0).or(list.get(1)); + default -> (ctx -> { + for (Predicate predicate : list) { + if (predicate.test(ctx)) { + return true; + } + } + return false; + }); + }; + } + + public static List> fromMapList(List> mapList) { + if (mapList == null || mapList.isEmpty()) return List.of(); + List> functions = new ArrayList<>(); + for (Map map : mapList) { + functions.add(fromMap(map)); + } + return functions; + } + + public static Condition fromMap(Map map) { + String type = ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("type"), "warning.config.loot_table.condition.missing_type"); + Key key = Key.withDefaultNamespace(type, Key.DEFAULT_NAMESPACE); + if (key.value().charAt(0) == '!') { + ConditionFactory factory = BuiltInRegistries.LOOT_CONDITION_FACTORY.getValue(new Key(key.namespace(), key.value().substring(1))); + if (factory == null) { + throw new LocalizedResourceConfigException("warning.config.loot_table.condition.invalid_type", type); + } + return new InvertedCondition<>(factory.create(map)); + } else { + ConditionFactory factory = BuiltInRegistries.LOOT_CONDITION_FACTORY.getValue(key); + if (factory == null) { + throw new LocalizedResourceConfigException("warning.config.loot_table.condition.invalid_type", type); + } + return factory.create(map); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/LootContext.java b/core/src/main/java/net/momirealms/craftengine/core/loot/LootContext.java index 2ad3dc4f4..c7251cd9e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/LootContext.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/LootContext.java @@ -1,50 +1,38 @@ package net.momirealms.craftengine.core.loot; -import net.momirealms.craftengine.core.util.context.ContextHolder; -import net.momirealms.craftengine.core.util.context.ContextKey; +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.plugin.context.ContextHolder; +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.world.World; +import org.jetbrains.annotations.NotNull; -import java.util.Optional; -import java.util.Random; +import javax.annotation.Nullable; -public class LootContext { +public class LootContext extends PlayerOptionalContext { private final World world; - private final ContextHolder contexts; - private final Random randomSource; private final float luck; + private Item tempLoot; - public LootContext(World world, ContextHolder contexts, Random randomSource, float luck) { - this.randomSource = randomSource; - this.contexts = contexts; + public LootContext(@NotNull World world, @Nullable Player player, float luck, @NotNull ContextHolder contexts) { + super(player, contexts); this.world = world; this.luck = luck; } - public Random randomSource() { - return randomSource; - } - - public Optional getOptionalParameter(ContextKey parameter) { - return this.contexts.getOptional(parameter); - } - - public boolean hasParameter(ContextKey parameter) { - return this.contexts.has(parameter); - } - - public T getParameterOrThrow(ContextKey parameter) { - return this.contexts.getOrThrow(parameter); - } - public float luck() { - return luck; - } - - public ContextHolder contexts() { - return contexts; + return this.luck; } public World world() { - return world; + return this.world; + } + + public Item tempLoot() { + return this.tempLoot; + } + + public void setTempLoot(Item tempLoot) { + this.tempLoot = tempLoot; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/LootPool.java b/core/src/main/java/net/momirealms/craftengine/core/loot/LootPool.java index 981093c85..41694006f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/LootPool.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/LootPool.java @@ -2,32 +2,31 @@ package net.momirealms.craftengine.core.loot; import com.google.common.collect.Lists; import net.momirealms.craftengine.core.item.Item; -import net.momirealms.craftengine.core.loot.condition.LootCondition; -import net.momirealms.craftengine.core.loot.condition.LootConditions; import net.momirealms.craftengine.core.loot.entry.LootEntry; import net.momirealms.craftengine.core.loot.entry.LootEntryContainer; import net.momirealms.craftengine.core.loot.function.LootFunction; import net.momirealms.craftengine.core.loot.function.LootFunctions; -import net.momirealms.craftengine.core.loot.number.NumberProvider; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; import net.momirealms.craftengine.core.util.MCUtils; import net.momirealms.craftengine.core.util.MutableInt; +import net.momirealms.craftengine.core.util.RandomUtils; import java.util.List; -import java.util.Random; import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Predicate; public class LootPool { private final List> entryContainers; - private final List conditions; + private final List> conditions; private final Predicate compositeCondition; private final List> functions; private final BiFunction, LootContext, Item> compositeFunction; private final NumberProvider rolls; private final NumberProvider bonusRolls; - public LootPool(List> entryContainers, List conditions, List> functions, NumberProvider rolls, NumberProvider bonusRolls) { + public LootPool(List> entryContainers, List> conditions, List> functions, NumberProvider rolls, NumberProvider bonusRolls) { this.entryContainers = entryContainers; this.conditions = conditions; this.functions = functions; @@ -38,7 +37,7 @@ public class LootPool { } public void addRandomItems(Consumer> lootConsumer, LootContext context) { - for (LootCondition condition : this.conditions) { + for (Condition condition : this.conditions) { if (!condition.test(context)) { return; } @@ -62,7 +61,6 @@ public class LootPool { } private void addRandomItem(Consumer> lootConsumer, LootContext context) { - Random randomSource = context.randomSource(); List> list = Lists.newArrayList(); MutableInt mutableInt = new MutableInt(0); for (LootEntryContainer lootPoolEntryContainer : this.entryContainers) { @@ -79,7 +77,7 @@ public class LootPool { if (i == 1) { list.get(0).createItem(lootConsumer, context); } else { - int j = randomSource.nextInt(mutableInt.intValue()); + int j = RandomUtils.generateRandomInt(0, mutableInt.intValue()); for (LootEntry loot : list) { j -= loot.getWeight(context.luck()); if (j < 0) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/LootTable.java b/core/src/main/java/net/momirealms/craftengine/core/loot/LootTable.java index e8b2176ff..3ea626c53 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/LootTable.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/LootTable.java @@ -1,19 +1,19 @@ package net.momirealms.craftengine.core.loot; import com.google.common.collect.Lists; +import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.item.Item; -import net.momirealms.craftengine.core.loot.condition.LootCondition; -import net.momirealms.craftengine.core.loot.condition.LootConditions; import net.momirealms.craftengine.core.loot.entry.LootEntryContainer; import net.momirealms.craftengine.core.loot.entry.LootEntryContainers; import net.momirealms.craftengine.core.loot.function.LootFunction; import net.momirealms.craftengine.core.loot.function.LootFunctions; -import net.momirealms.craftengine.core.loot.number.NumberProvider; -import net.momirealms.craftengine.core.loot.number.NumberProviders; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.ContextHolder; +import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; +import net.momirealms.craftengine.core.plugin.context.number.NumberProviders; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils; -import net.momirealms.craftengine.core.util.context.ContextHolder; import net.momirealms.craftengine.core.world.World; import org.jetbrains.annotations.Nullable; @@ -21,7 +21,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.concurrent.ThreadLocalRandom; import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Supplier; @@ -52,7 +51,7 @@ public class LootTable { Map pool = MiscUtils.castToMap(rawPoolMap, false); NumberProvider rolls = NumberProviders.fromObject(pool.getOrDefault("rolls", 1)); NumberProvider bonus_rolls = NumberProviders.fromObject(pool.getOrDefault("bonus_rolls", 0)); - List conditions = Optional.ofNullable(pool.get("conditions")) + List> conditions = Optional.ofNullable(pool.get("conditions")) .map(it -> LootConditions.fromMapList(castToMapListOrThrow(it, () -> new LocalizedResourceConfigException("warning.config.loot_table.invalid_conditions_type", it.getClass().getSimpleName())))) .orElse(Lists.newArrayList()); @@ -80,7 +79,11 @@ public class LootTable { } public ArrayList> getRandomItems(ContextHolder parameters, World world) { - return this.getRandomItems(new LootContext(world, parameters, ThreadLocalRandom.current(), 1)); + return this.getRandomItems(parameters, world, null); + } + + public ArrayList> getRandomItems(ContextHolder parameters, World world, @Nullable Player player) { + return this.getRandomItems(new LootContext(world, player, player == null ? 1f : (float) player.luck(), parameters)); } private ArrayList> getRandomItems(LootContext context) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/condition/AllOfCondition.java b/core/src/main/java/net/momirealms/craftengine/core/loot/condition/AllOfCondition.java deleted file mode 100644 index 6c1e9eaa1..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/condition/AllOfCondition.java +++ /dev/null @@ -1,40 +0,0 @@ -package net.momirealms.craftengine.core.loot.condition; - -import net.momirealms.craftengine.core.loot.LootContext; -import net.momirealms.craftengine.core.util.Key; - -import java.util.List; -import java.util.Map; - -public class AllOfCondition implements LootCondition { - public static final Factory FACTORY = new Factory(); - private final List conditions; - - public AllOfCondition(List conditions) { - this.conditions = conditions; - } - - @Override - public Key type() { - return LootConditions.ALL_OF; - } - - @Override - public boolean test(LootContext lootContext) { - for (LootCondition condition : conditions) { - if (!condition.test(lootContext)) { - return false; - } - } - return true; - } - - public static class Factory implements LootConditionFactory { - @SuppressWarnings("unchecked") - @Override - public LootCondition create(Map arguments) { - List> terms = (List>) arguments.get("terms"); - return new AllOfCondition(LootConditions.fromMapList(terms)); - } - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/condition/AnyOfCondition.java b/core/src/main/java/net/momirealms/craftengine/core/loot/condition/AnyOfCondition.java deleted file mode 100644 index 8ed439c3e..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/condition/AnyOfCondition.java +++ /dev/null @@ -1,40 +0,0 @@ -package net.momirealms.craftengine.core.loot.condition; - -import net.momirealms.craftengine.core.loot.LootContext; -import net.momirealms.craftengine.core.util.Key; - -import java.util.List; -import java.util.Map; - -public class AnyOfCondition implements LootCondition { - public static final Factory FACTORY = new Factory(); - private final List conditions; - - public AnyOfCondition(List conditions) { - this.conditions = conditions; - } - - @Override - public Key type() { - return LootConditions.ANY_OF; - } - - @Override - public boolean test(LootContext lootContext) { - for (LootCondition condition : conditions) { - if (condition.test(lootContext)) { - return true; - } - } - return false; - } - - public static class Factory implements LootConditionFactory { - @SuppressWarnings("unchecked") - @Override - public LootCondition create(Map arguments) { - List> terms = (List>) arguments.get("terms"); - return new AnyOfCondition(LootConditions.fromMapList(terms)); - } - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/condition/EnchantmentCondition.java b/core/src/main/java/net/momirealms/craftengine/core/loot/condition/EnchantmentCondition.java deleted file mode 100644 index 067a8a3e1..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/condition/EnchantmentCondition.java +++ /dev/null @@ -1,56 +0,0 @@ -package net.momirealms.craftengine.core.loot.condition; - -import net.momirealms.craftengine.core.item.Enchantment; -import net.momirealms.craftengine.core.item.Item; -import net.momirealms.craftengine.core.loot.LootContext; -import net.momirealms.craftengine.core.loot.parameter.LootParameters; -import net.momirealms.craftengine.core.util.Key; - -import java.util.Map; -import java.util.Optional; -import java.util.function.Function; - -public class EnchantmentCondition implements LootCondition { - public static final Factory FACTORY = new Factory(); - private final Key id; - private final Function expression; - - public EnchantmentCondition(Key id, Function expression) { - this.id = id; - this.expression = expression; - } - - @Override - public Key type() { - return LootConditions.ENCHANTMENT; - } - - @Override - public boolean test(LootContext lootContext) { - Optional> item = lootContext.getOptionalParameter(LootParameters.TOOL); - if (item.isEmpty()) return false; - Optional enchantment = item.get().getEnchantment(id); - int level = enchantment.map(Enchantment::level).orElse(0); - return this.expression.apply(level); - } - - public static class Factory implements LootConditionFactory { - @Override - public LootCondition create(Map arguments) { - String predicate = (String) arguments.get("predicate"); - String[] split = predicate.split("(<=|>=|<|>|==|=)", 2); - int level = Integer.parseInt(split[1]); - String operator = predicate.substring(split[0].length(), predicate.length() - split[1].length()); - Function expression; - switch (operator) { - case "<" -> expression = (i -> i < level); - case ">" -> expression = (i -> i > level); - case "==", "=" -> expression = (i -> i == level); - case "<=" -> expression = (i -> i <= level); - case ">=" -> expression = (i -> i >= level); - default -> throw new IllegalArgumentException("Unknown operator: " + operator); - } - return new EnchantmentCondition(Key.of(split[0]), expression); - } - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/condition/FallingCondition.java b/core/src/main/java/net/momirealms/craftengine/core/loot/condition/FallingCondition.java deleted file mode 100644 index 0e4b6324b..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/condition/FallingCondition.java +++ /dev/null @@ -1,29 +0,0 @@ -package net.momirealms.craftengine.core.loot.condition; - -import net.momirealms.craftengine.core.loot.LootContext; -import net.momirealms.craftengine.core.loot.parameter.LootParameters; -import net.momirealms.craftengine.core.util.Key; - -import java.util.Map; - -public class FallingCondition implements LootCondition { - public static final Factory FACTORY = new Factory(); - public static final FallingCondition INSTANCE = new FallingCondition(); - - @Override - public Key type() { - return LootConditions.FALLING_BLOCK; - } - - @Override - public boolean test(LootContext lootContext) { - return lootContext.getOptionalParameter(LootParameters.FALLING_BLOCK).orElse(false); - } - - public static class Factory implements LootConditionFactory { - @Override - public LootCondition create(Map arguments) { - return INSTANCE; - } - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/condition/InvertedCondition.java b/core/src/main/java/net/momirealms/craftengine/core/loot/condition/InvertedCondition.java deleted file mode 100644 index 7dc3a9cd7..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/condition/InvertedCondition.java +++ /dev/null @@ -1,34 +0,0 @@ -package net.momirealms.craftengine.core.loot.condition; - -import net.momirealms.craftengine.core.loot.LootContext; -import net.momirealms.craftengine.core.util.Key; - -import java.util.Map; - -public class InvertedCondition implements LootCondition { - public static final Factory FACTORY = new Factory(); - private final LootCondition condition; - - public InvertedCondition(LootCondition condition) { - this.condition = condition; - } - - @Override - public Key type() { - return LootConditions.INVERTED; - } - - @Override - public boolean test(LootContext lootContext) { - return !condition.test(lootContext); - } - - public static class Factory implements LootConditionFactory { - @SuppressWarnings("unchecked") - @Override - public LootCondition create(Map arguments) { - Map term = (Map) arguments.get("term"); - return new InvertedCondition(LootConditions.fromMap(term)); - } - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/condition/LootCondition.java b/core/src/main/java/net/momirealms/craftengine/core/loot/condition/LootCondition.java deleted file mode 100644 index 5a684a171..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/condition/LootCondition.java +++ /dev/null @@ -1,11 +0,0 @@ -package net.momirealms.craftengine.core.loot.condition; - -import net.momirealms.craftengine.core.loot.LootContext; -import net.momirealms.craftengine.core.util.Key; - -import java.util.function.Predicate; - -public interface LootCondition extends Predicate { - - Key type(); -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/condition/LootConditionFactory.java b/core/src/main/java/net/momirealms/craftengine/core/loot/condition/LootConditionFactory.java deleted file mode 100644 index 6f8173511..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/condition/LootConditionFactory.java +++ /dev/null @@ -1,8 +0,0 @@ -package net.momirealms.craftengine.core.loot.condition; - -import java.util.Map; - -public interface LootConditionFactory { - - LootCondition create(Map arguments); -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/condition/LootConditions.java b/core/src/main/java/net/momirealms/craftengine/core/loot/condition/LootConditions.java deleted file mode 100644 index fd8f55e2b..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/condition/LootConditions.java +++ /dev/null @@ -1,102 +0,0 @@ -package net.momirealms.craftengine.core.loot.condition; - -import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; -import net.momirealms.craftengine.core.registry.BuiltInRegistries; -import net.momirealms.craftengine.core.registry.Holder; -import net.momirealms.craftengine.core.registry.Registries; -import net.momirealms.craftengine.core.registry.WritableRegistry; -import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.ResourceKey; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.function.Predicate; - -public class LootConditions { - public static final Key MATCH_ITEM = Key.from("craftengine:match_item"); - public static final Key MATCH_BLOCK_PROPERTY = Key.from("craftengine:match_block_property"); - public static final Key TABLE_BONUS = Key.from("craftengine:table_bonus"); - public static final Key SURVIVES_EXPLOSION = Key.from("craftengine:survives_explosion"); - public static final Key RANDOM = Key.from("craftengine:random"); - public static final Key ANY_OF = Key.from("craftengine:any_of"); - public static final Key ALL_OF = Key.from("craftengine:all_of"); - public static final Key ENCHANTMENT = Key.from("craftengine:enchantment"); - public static final Key INVERTED = Key.from("craftengine:inverted"); - public static final Key FALLING_BLOCK = Key.from("craftengine:falling_block"); - - static { - register(MATCH_ITEM, MatchItemCondition.FACTORY); - register(MATCH_BLOCK_PROPERTY, MatchBlockPropertyCondition.FACTORY); - register(TABLE_BONUS, TableBonusCondition.FACTORY); - register(SURVIVES_EXPLOSION, SurvivesExplosionCondition.FACTORY); - register(ANY_OF, AnyOfCondition.FACTORY); - register(ALL_OF, AllOfCondition.FACTORY); - register(ENCHANTMENT, EnchantmentCondition.FACTORY); - register(INVERTED, InvertedCondition.FACTORY); - register(FALLING_BLOCK, FallingCondition.FACTORY); - register(RANDOM, RandomCondition.FACTORY); - } - - public static void register(Key key, LootConditionFactory factory) { - Holder.Reference holder = ((WritableRegistry) BuiltInRegistries.LOOT_CONDITION_FACTORY) - .registerForHolder(new ResourceKey<>(Registries.LOOT_CONDITION_FACTORY.location(), key)); - holder.bindValue(factory); - } - - public static Predicate andConditions(List> predicates) { - List> list = List.copyOf(predicates); - return switch (list.size()) { - case 0 -> ctx -> true; - case 1 -> list.get(0); - case 2 -> list.get(0).and(list.get(1)); - default -> (ctx -> { - for (Predicate predicate : list) { - if (!predicate.test(ctx)) { - return false; - } - } - return true; - }); - }; - } - - public static Predicate orConditions(List> predicates) { - List> list = List.copyOf(predicates); - return switch (list.size()) { - case 0 -> ctx -> false; - case 1 -> list.get(0); - case 2 -> list.get(0).or(list.get(1)); - default -> (ctx -> { - for (Predicate predicate : list) { - if (predicate.test(ctx)) { - return true; - } - } - return false; - }); - }; - } - - public static List fromMapList(List> mapList) { - if (mapList == null || mapList.isEmpty()) return List.of(); - List functions = new ArrayList<>(); - for (Map map : mapList) { - functions.add(fromMap(map)); - } - return functions; - } - - public static LootCondition fromMap(Map map) { - String type = (String) map.get("type"); - if (type == null) { - throw new LocalizedResourceConfigException("warning.config.loot_table.condition.missing_type"); - } - Key key = Key.withDefaultNamespace(type, "craftengine"); - LootConditionFactory factory = BuiltInRegistries.LOOT_CONDITION_FACTORY.getValue(key); - if (factory == null) { - throw new LocalizedResourceConfigException("warning.config.loot_table.condition.invalid_type", type); - } - return factory.create(map); - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/condition/RandomCondition.java b/core/src/main/java/net/momirealms/craftengine/core/loot/condition/RandomCondition.java deleted file mode 100644 index 50cb43f1e..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/condition/RandomCondition.java +++ /dev/null @@ -1,35 +0,0 @@ -package net.momirealms.craftengine.core.loot.condition; - -import net.momirealms.craftengine.core.loot.LootContext; -import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.RandomUtils; -import net.momirealms.craftengine.core.util.ResourceConfigUtils; - -import java.util.Map; - -public class RandomCondition implements LootCondition { - public static final Factory FACTORY = new Factory(); - private final float chance; - - public RandomCondition(float chance) { - this.chance = chance; - } - - @Override - public Key type() { - return LootConditions.RANDOM; - } - - @Override - public boolean test(LootContext lootContext) { - return RandomUtils.generateRandomFloat(0, 1) < this.chance; - } - - public static class Factory implements LootConditionFactory { - @Override - public LootCondition create(Map arguments) { - float chance = ResourceConfigUtils.getAsFloat(arguments.getOrDefault("value", 0.5f), "value"); - return new RandomCondition(chance); - } - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/condition/SurvivesExplosionCondition.java b/core/src/main/java/net/momirealms/craftengine/core/loot/condition/SurvivesExplosionCondition.java deleted file mode 100644 index 3fd8f8cf6..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/condition/SurvivesExplosionCondition.java +++ /dev/null @@ -1,35 +0,0 @@ -package net.momirealms.craftengine.core.loot.condition; - -import net.momirealms.craftengine.core.loot.LootContext; -import net.momirealms.craftengine.core.loot.parameter.LootParameters; -import net.momirealms.craftengine.core.util.Key; - -import java.util.Map; -import java.util.Optional; - -public class SurvivesExplosionCondition implements LootCondition { - public static final Factory FACTORY = new Factory(); - private static final SurvivesExplosionCondition INSTANCE = new SurvivesExplosionCondition(); - - @Override - public Key type() { - return LootConditions.SURVIVES_EXPLOSION; - } - - @Override - public boolean test(LootContext lootContext) { - Optional radius = lootContext.getOptionalParameter(LootParameters.EXPLOSION_RADIUS); - if (radius.isPresent()) { - float f = 1f / radius.get(); - return lootContext.randomSource().nextFloat() < f; - } - return true; - } - - public static class Factory implements LootConditionFactory { - @Override - public LootCondition create(Map arguments) { - return INSTANCE; - } - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/entry/AbstractCompositeLootEntryContainer.java b/core/src/main/java/net/momirealms/craftengine/core/loot/entry/AbstractCompositeLootEntryContainer.java index 76f4a57ea..c30f2407a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/entry/AbstractCompositeLootEntryContainer.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/entry/AbstractCompositeLootEntryContainer.java @@ -1,7 +1,7 @@ package net.momirealms.craftengine.core.loot.entry; import net.momirealms.craftengine.core.loot.LootContext; -import net.momirealms.craftengine.core.loot.condition.LootCondition; +import net.momirealms.craftengine.core.plugin.context.Condition; import java.util.List; import java.util.function.Consumer; @@ -10,7 +10,7 @@ public abstract class AbstractCompositeLootEntryContainer extends AbstractLoo protected final List> children; private final LootEntryContainer composedChildren; - protected AbstractCompositeLootEntryContainer(List conditions, List> children) { + protected AbstractCompositeLootEntryContainer(List> conditions, List> children) { super(conditions); this.children = children; this.composedChildren = compose(children); diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/entry/AbstractLootEntryContainer.java b/core/src/main/java/net/momirealms/craftengine/core/loot/entry/AbstractLootEntryContainer.java index a71d1651d..7538d3f7f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/entry/AbstractLootEntryContainer.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/entry/AbstractLootEntryContainer.java @@ -1,7 +1,7 @@ package net.momirealms.craftengine.core.loot.entry; import net.momirealms.craftengine.core.loot.LootContext; -import net.momirealms.craftengine.core.loot.condition.LootCondition; +import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MCUtils; @@ -9,10 +9,10 @@ import java.util.List; import java.util.function.Predicate; public abstract class AbstractLootEntryContainer implements LootEntryContainer, Predicate { - protected final List conditions; + protected final List> conditions; private final Predicate compositeCondition; - protected AbstractLootEntryContainer(List conditions) { + protected AbstractLootEntryContainer(List> conditions) { this.conditions = conditions; this.compositeCondition = MCUtils.allOf(conditions); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/entry/AbstractSingleLootEntryContainer.java b/core/src/main/java/net/momirealms/craftengine/core/loot/entry/AbstractSingleLootEntryContainer.java index 86f866a29..0d57d6d39 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/entry/AbstractSingleLootEntryContainer.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/entry/AbstractSingleLootEntryContainer.java @@ -2,9 +2,9 @@ package net.momirealms.craftengine.core.loot.entry; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.loot.LootContext; -import net.momirealms.craftengine.core.loot.condition.LootCondition; import net.momirealms.craftengine.core.loot.function.LootFunction; import net.momirealms.craftengine.core.loot.function.LootFunctions; +import net.momirealms.craftengine.core.plugin.context.Condition; import java.util.List; import java.util.function.BiFunction; @@ -24,7 +24,7 @@ public abstract class AbstractSingleLootEntryContainer extends AbstractLootEn } }; - protected AbstractSingleLootEntryContainer(List conditions, List> functions, int weight, int quality) { + protected AbstractSingleLootEntryContainer(List> conditions, List> functions, int weight, int quality) { super(conditions); this.weight = weight; this.quality = quality; diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/entry/AlternativesLootEntryContainer.java b/core/src/main/java/net/momirealms/craftengine/core/loot/entry/AlternativesLootEntryContainer.java index 3c5e91f4e..9ed2f42e4 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/entry/AlternativesLootEntryContainer.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/entry/AlternativesLootEntryContainer.java @@ -1,7 +1,8 @@ package net.momirealms.craftengine.core.loot.entry; -import net.momirealms.craftengine.core.loot.condition.LootCondition; -import net.momirealms.craftengine.core.loot.condition.LootConditions; +import net.momirealms.craftengine.core.loot.LootConditions; +import net.momirealms.craftengine.core.loot.LootContext; +import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.util.Key; import java.util.*; @@ -9,7 +10,7 @@ import java.util.*; public class AlternativesLootEntryContainer extends AbstractCompositeLootEntryContainer { public static final Factory FACTORY = new Factory<>(); - protected AlternativesLootEntryContainer(List conditions, List> children) { + protected AlternativesLootEntryContainer(List> conditions, List> children) { super(conditions, children); } @@ -42,7 +43,7 @@ public class AlternativesLootEntryContainer extends AbstractCompositeLootEntr List> containers = Optional.ofNullable(arguments.get("children")) .map(it -> (List>) new ArrayList>(LootEntryContainers.fromMapList((List>) it))) .orElse(Collections.emptyList()); - List conditions = Optional.ofNullable(arguments.get("conditions")) + List> conditions = Optional.ofNullable(arguments.get("conditions")) .map(it -> LootConditions.fromMapList((List>) it)) .orElse(Collections.emptyList()); return new AlternativesLootEntryContainer<>(conditions, containers); diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/entry/ExpLootEntryContainer.java b/core/src/main/java/net/momirealms/craftengine/core/loot/entry/ExpLootEntryContainer.java index 41d0d5de8..eaf7a96ac 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/entry/ExpLootEntryContainer.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/entry/ExpLootEntryContainer.java @@ -1,11 +1,11 @@ package net.momirealms.craftengine.core.loot.entry; +import net.momirealms.craftengine.core.loot.LootConditions; import net.momirealms.craftengine.core.loot.LootContext; -import net.momirealms.craftengine.core.loot.condition.LootCondition; -import net.momirealms.craftengine.core.loot.condition.LootConditions; -import net.momirealms.craftengine.core.loot.number.NumberProvider; -import net.momirealms.craftengine.core.loot.number.NumberProviders; -import net.momirealms.craftengine.core.loot.parameter.LootParameters; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; +import net.momirealms.craftengine.core.plugin.context.number.NumberProviders; +import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; @@ -19,7 +19,7 @@ public class ExpLootEntryContainer extends AbstractLootEntryContainer { public static final Factory FACTORY = new Factory<>(); private final NumberProvider value; - protected ExpLootEntryContainer(NumberProvider value, List conditions) { + protected ExpLootEntryContainer(NumberProvider value, List> conditions) { super(conditions); this.value = value; } @@ -32,8 +32,8 @@ public class ExpLootEntryContainer extends AbstractLootEntryContainer { @Override public boolean expand(LootContext context, Consumer> choiceConsumer) { if (super.test(context)) { - context.getOptionalParameter(LootParameters.WORLD) - .ifPresent(it -> context.getOptionalParameter(LootParameters.LOCATION).ifPresent(loc -> it.dropExp(loc.toCenter(), value.getInt(context)))); + context.getOptionalParameter(CommonParameters.WORLD) + .ifPresent(it -> context.getOptionalParameter(CommonParameters.LOCATION).ifPresent(loc -> it.dropExp(loc.toCenter(), value.getInt(context)))); return true; } else { return false; @@ -45,7 +45,7 @@ public class ExpLootEntryContainer extends AbstractLootEntryContainer { @Override public LootEntryContainer create(Map arguments) { Object value = ResourceConfigUtils.requireNonNullOrThrow(arguments.get("count"), "warning.config.loot_table.entry.exp.missing_count"); - List conditions = Optional.ofNullable(arguments.get("conditions")) + List> conditions = Optional.ofNullable(arguments.get("conditions")) .map(it -> LootConditions.fromMapList((List>) it)) .orElse(Collections.emptyList()); return new ExpLootEntryContainer<>(NumberProviders.fromObject(value), conditions); diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/entry/LootEntryContainers.java b/core/src/main/java/net/momirealms/craftengine/core/loot/entry/LootEntryContainers.java index b9f9ce3e0..5d44629dc 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/entry/LootEntryContainers.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/entry/LootEntryContainers.java @@ -42,7 +42,7 @@ public class LootEntryContainers { @SuppressWarnings("unchecked") public static LootEntryContainer fromMap(Map map) { String type = ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("type"), "warning.config.loot_table.entry.missing_type"); - Key key = Key.withDefaultNamespace(type, "craftengine"); + Key key = Key.withDefaultNamespace(type, Key.DEFAULT_NAMESPACE); LootEntryContainerFactory factory = (LootEntryContainerFactory) BuiltInRegistries.LOOT_ENTRY_CONTAINER_FACTORY.getValue(key); if (factory == null) { throw new LocalizedResourceConfigException("warning.config.loot_table.entry.invalid_type", type); diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/entry/SingleItemLootEntryContainer.java b/core/src/main/java/net/momirealms/craftengine/core/loot/entry/SingleItemLootEntryContainer.java index 28830b557..4b5c300f2 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/entry/SingleItemLootEntryContainer.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/entry/SingleItemLootEntryContainer.java @@ -1,13 +1,13 @@ package net.momirealms.craftengine.core.loot.entry; import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.loot.LootConditions; import net.momirealms.craftengine.core.loot.LootContext; -import net.momirealms.craftengine.core.loot.condition.LootCondition; -import net.momirealms.craftengine.core.loot.condition.LootConditions; import net.momirealms.craftengine.core.loot.function.LootFunction; import net.momirealms.craftengine.core.loot.function.LootFunctions; -import net.momirealms.craftengine.core.loot.parameter.LootParameters; import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; @@ -18,7 +18,7 @@ public class SingleItemLootEntryContainer extends AbstractSingleLootEntryCont public static final Factory FACTORY = new Factory<>(); private final Key item; - protected SingleItemLootEntryContainer(Key item, List conditions, List> lootFunctions, int weight, int quality) { + protected SingleItemLootEntryContainer(Key item, List> conditions, List> lootFunctions, int weight, int quality) { super(conditions, lootFunctions, weight, quality); this.item = item; } @@ -31,7 +31,7 @@ public class SingleItemLootEntryContainer extends AbstractSingleLootEntryCont @SuppressWarnings("unchecked") @Override protected void createItem(Consumer> lootConsumer, LootContext context) { - Item tItem = (Item) CraftEngine.instance().itemManager().createWrappedItem(this.item, context.getOptionalParameter(LootParameters.PLAYER).orElse(null)); + Item tItem = (Item) CraftEngine.instance().itemManager().createWrappedItem(this.item, context.getOptionalParameter(CommonParameters.PLAYER).orElse(null)); if (tItem != null) { lootConsumer.accept(tItem); } else { @@ -47,7 +47,7 @@ public class SingleItemLootEntryContainer extends AbstractSingleLootEntryCont Key item = Key.from(itemObj); int weight = ResourceConfigUtils.getAsInt(arguments.getOrDefault("weight", 1), "weight"); int quality = ResourceConfigUtils.getAsInt(arguments.getOrDefault("quality", 0), "quality"); - List conditions = Optional.ofNullable(arguments.get("conditions")) + List> conditions = Optional.ofNullable(arguments.get("conditions")) .map(it -> LootConditions.fromMapList((List>) it)) .orElse(Collections.emptyList()); List> functions = Optional.ofNullable(arguments.get("functions")) diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/function/AbstractLootConditionalFunction.java b/core/src/main/java/net/momirealms/craftengine/core/loot/function/AbstractLootConditionalFunction.java index c0de92238..89a918222 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/function/AbstractLootConditionalFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/function/AbstractLootConditionalFunction.java @@ -2,17 +2,17 @@ package net.momirealms.craftengine.core.loot.function; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.loot.LootContext; -import net.momirealms.craftengine.core.loot.condition.LootCondition; +import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.util.MCUtils; import java.util.List; import java.util.function.Predicate; public abstract class AbstractLootConditionalFunction implements LootFunction { - protected final List predicates; + protected final List> predicates; private final Predicate compositePredicates; - public AbstractLootConditionalFunction(List predicates) { + public AbstractLootConditionalFunction(List> predicates) { this.predicates = predicates; this.compositePredicates = MCUtils.allOf(predicates); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/function/ApplyBonusCountFunction.java b/core/src/main/java/net/momirealms/craftengine/core/loot/function/ApplyBonusCountFunction.java index 3e55a198f..ea6f98583 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/function/ApplyBonusCountFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/function/ApplyBonusCountFunction.java @@ -2,10 +2,10 @@ package net.momirealms.craftengine.core.loot.function; import net.momirealms.craftengine.core.item.Enchantment; import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.loot.LootConditions; import net.momirealms.craftengine.core.loot.LootContext; -import net.momirealms.craftengine.core.loot.condition.LootCondition; -import net.momirealms.craftengine.core.loot.condition.LootConditions; -import net.momirealms.craftengine.core.loot.parameter.LootParameters; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.parameter.PlayerParameters; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Holder; @@ -17,14 +17,13 @@ import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.concurrent.ThreadLocalRandom; public class ApplyBonusCountFunction extends AbstractLootConditionalFunction { public static final Factory FACTORY = new Factory<>(); private final Key enchantment; private final Formula formula; - public ApplyBonusCountFunction(List predicates, Key enchantment, Formula formula) { + public ApplyBonusCountFunction(List> predicates, Key enchantment, Formula formula) { super(predicates); this.enchantment = enchantment; this.formula = formula; @@ -32,7 +31,7 @@ public class ApplyBonusCountFunction extends AbstractLootConditionalFunction< @Override protected Item applyInternal(Item item, LootContext context) { - Optional> itemInHand = context.getOptionalParameter(LootParameters.TOOL); + Optional> itemInHand = context.getOptionalParameter(PlayerParameters.MAIN_HAND_ITEM); int level = itemInHand.map(value -> value.getEnchantment(this.enchantment).map(Enchantment::level).orElse(0)).orElse(0); int newCount = this.formula.apply(item.count(), level); item.count(newCount); @@ -54,7 +53,7 @@ public class ApplyBonusCountFunction extends AbstractLootConditionalFunction< if (formulaMap == null) { throw new LocalizedResourceConfigException("warning.config.loot_table.function.apply_bonus.missing_formula"); } - List conditions = Optional.ofNullable(arguments.get("conditions")) + List> conditions = Optional.ofNullable(arguments.get("conditions")) .map(it -> LootConditions.fromMapList((List>) it)) .orElse(Collections.emptyList()); return new ApplyBonusCountFunction<>(conditions, Key.from(enchantment), Formulas.fromMap(formulaMap)); @@ -92,7 +91,7 @@ public class ApplyBonusCountFunction extends AbstractLootConditionalFunction< if (type == null) { throw new NullPointerException("number type cannot be null"); } - Key key = Key.withDefaultNamespace(type, "craftengine"); + Key key = Key.withDefaultNamespace(type, Key.DEFAULT_NAMESPACE); FormulaFactory factory = BuiltInRegistries.FORMULA_FACTORY.getValue(key); if (factory == null) { throw new IllegalArgumentException("Unknown formula type: " + type); @@ -108,7 +107,7 @@ public class ApplyBonusCountFunction extends AbstractLootConditionalFunction< @Override public int apply(int initialCount, int enchantmentLevel) { if (enchantmentLevel > 0) { - int i = ThreadLocalRandom.current().nextInt(enchantmentLevel + 2) - 1; + int i = RandomUtils.generateRandomInt(0, enchantmentLevel + 2) - 1; if (i < 0) { i = 0; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/function/DropExpFunction.java b/core/src/main/java/net/momirealms/craftengine/core/loot/function/DropExpFunction.java index cecd00e2e..88e9664dc 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/function/DropExpFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/function/DropExpFunction.java @@ -1,12 +1,12 @@ package net.momirealms.craftengine.core.loot.function; import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.loot.LootConditions; import net.momirealms.craftengine.core.loot.LootContext; -import net.momirealms.craftengine.core.loot.condition.LootCondition; -import net.momirealms.craftengine.core.loot.condition.LootConditions; -import net.momirealms.craftengine.core.loot.number.NumberProvider; -import net.momirealms.craftengine.core.loot.number.NumberProviders; -import net.momirealms.craftengine.core.loot.parameter.LootParameters; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; +import net.momirealms.craftengine.core.plugin.context.number.NumberProviders; +import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; @@ -19,15 +19,15 @@ public class DropExpFunction extends AbstractLootConditionalFunction { public static final Factory FACTORY = new Factory<>(); private final NumberProvider value; - public DropExpFunction(NumberProvider value, List predicates) { + public DropExpFunction(NumberProvider value, List> predicates) { super(predicates); this.value = value; } @Override protected Item applyInternal(Item item, LootContext context) { - context.getOptionalParameter(LootParameters.WORLD) - .ifPresent(it -> context.getOptionalParameter(LootParameters.LOCATION).ifPresent(loc -> it.dropExp(loc.toCenter(), value.getInt(context)))); + context.getOptionalParameter(CommonParameters.WORLD) + .ifPresent(it -> context.getOptionalParameter(CommonParameters.LOCATION).ifPresent(loc -> it.dropExp(loc.toCenter(), value.getInt(context)))); return item; } @@ -41,7 +41,7 @@ public class DropExpFunction extends AbstractLootConditionalFunction { @Override public LootFunction create(Map arguments) { Object value = ResourceConfigUtils.requireNonNullOrThrow(arguments.get("count"), "warning.config.loot_table.function.drop_exp.missing_count"); - List conditions = Optional.ofNullable(arguments.get("conditions")) + List> conditions = Optional.ofNullable(arguments.get("conditions")) .map(it -> LootConditions.fromMapList((List>) it)) .orElse(Collections.emptyList()); return new DropExpFunction<>(NumberProviders.fromObject(value), conditions); diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/function/ExplosionDecayFunction.java b/core/src/main/java/net/momirealms/craftengine/core/loot/function/ExplosionDecayFunction.java index 9a3fc8689..0ab1b6f5e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/function/ExplosionDecayFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/function/ExplosionDecayFunction.java @@ -1,31 +1,34 @@ package net.momirealms.craftengine.core.loot.function; import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.loot.LootConditions; import net.momirealms.craftengine.core.loot.LootContext; -import net.momirealms.craftengine.core.loot.condition.LootCondition; -import net.momirealms.craftengine.core.loot.condition.LootConditions; -import net.momirealms.craftengine.core.loot.parameter.LootParameters; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.RandomUtils; -import java.util.*; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Optional; public class ExplosionDecayFunction extends AbstractLootConditionalFunction { public static final Factory FACTORY = new Factory<>(); - public ExplosionDecayFunction(List predicates) { + public ExplosionDecayFunction(List> predicates) { super(predicates); } @Override protected Item applyInternal(Item item, LootContext context) { - Optional radius = context.getOptionalParameter(LootParameters.EXPLOSION_RADIUS); + Optional radius = context.getOptionalParameter(CommonParameters.EXPLOSION_RADIUS); if (radius.isPresent()) { - Random random = context.randomSource(); float f = 1f / radius.get(); int amount = item.count(); int survive = 0; for (int j = 0; j < amount; j++) { - if (random.nextFloat() <= f) { + if (RandomUtils.generateRandomFloat(0, 1) <= f) { survive++; } } @@ -43,7 +46,7 @@ public class ExplosionDecayFunction extends AbstractLootConditionalFunction create(Map arguments) { - List conditions = Optional.ofNullable(arguments.get("conditions")) + List> conditions = Optional.ofNullable(arguments.get("conditions")) .map(it -> LootConditions.fromMapList((List>) it)) .orElse(Collections.emptyList()); return new ExplosionDecayFunction<>(conditions); diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/function/LootFunctions.java b/core/src/main/java/net/momirealms/craftengine/core/loot/function/LootFunctions.java index 17a88c0c7..e380bf022 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/function/LootFunctions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/function/LootFunctions.java @@ -70,7 +70,7 @@ public class LootFunctions { @SuppressWarnings("unchecked") public static LootFunction fromMap(Map map) { String type = ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("type"), "warning.config.loot_table.function.missing_type"); - Key key = Key.withDefaultNamespace(type, "craftengine"); + Key key = Key.withDefaultNamespace(type, Key.DEFAULT_NAMESPACE); LootFunctionFactory factory = (LootFunctionFactory) BuiltInRegistries.LOOT_FUNCTION_FACTORY.getValue(key); if (factory == null) { throw new LocalizedResourceConfigException("warning.config.loot_table.function.invalid_type", type); diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/function/SetCountFunction.java b/core/src/main/java/net/momirealms/craftengine/core/loot/function/SetCountFunction.java index 969c778f9..02cfdaa73 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/function/SetCountFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/function/SetCountFunction.java @@ -1,11 +1,11 @@ package net.momirealms.craftengine.core.loot.function; import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.loot.LootConditions; import net.momirealms.craftengine.core.loot.LootContext; -import net.momirealms.craftengine.core.loot.condition.LootCondition; -import net.momirealms.craftengine.core.loot.condition.LootConditions; -import net.momirealms.craftengine.core.loot.number.NumberProvider; -import net.momirealms.craftengine.core.loot.number.NumberProviders; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; +import net.momirealms.craftengine.core.plugin.context.number.NumberProviders; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; @@ -20,7 +20,7 @@ public class SetCountFunction extends AbstractLootConditionalFunction { private final NumberProvider value; private final boolean add; - public SetCountFunction(List conditions, NumberProvider value, boolean add) { + public SetCountFunction(List> conditions, NumberProvider value, boolean add) { super(conditions); this.value = value; this.add = add; @@ -44,7 +44,7 @@ public class SetCountFunction extends AbstractLootConditionalFunction { public LootFunction create(Map arguments) { Object value = ResourceConfigUtils.requireNonNullOrThrow(arguments.get("count"), "warning.config.loot_table.function.set_count.missing_count"); boolean add = (boolean) arguments.getOrDefault("add", false); - List conditions = Optional.ofNullable(arguments.get("conditions")) + List> conditions = Optional.ofNullable(arguments.get("conditions")) .map(it -> LootConditions.fromMapList((List>) it)) .orElse(Collections.emptyList()); return new SetCountFunction<>(conditions, NumberProviders.fromObject(value), add); diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/number/FixedNumberProvider.java b/core/src/main/java/net/momirealms/craftengine/core/loot/number/FixedNumberProvider.java deleted file mode 100644 index 653bd3825..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/number/FixedNumberProvider.java +++ /dev/null @@ -1,33 +0,0 @@ -package net.momirealms.craftengine.core.loot.number; - -import net.momirealms.craftengine.core.loot.LootContext; -import net.momirealms.craftengine.core.util.Key; - -import java.util.Map; - -public class FixedNumberProvider implements NumberProvider { - public static final Factory FACTORY = new Factory(); - private final float value; - - public FixedNumberProvider(float value) { - this.value = value; - } - - @Override - public float getFloat(LootContext context) { - return this.value; - } - - @Override - public Key type() { - return NumberProviders.FIXED; - } - - public static class Factory implements NumberProviderFactory { - @Override - public NumberProvider create(Map arguments) { - Number value = (Number) arguments.get("value"); - return new FixedNumberProvider(value.floatValue()); - } - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/number/NumberProvider.java b/core/src/main/java/net/momirealms/craftengine/core/loot/number/NumberProvider.java deleted file mode 100644 index 80352d2af..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/number/NumberProvider.java +++ /dev/null @@ -1,15 +0,0 @@ -package net.momirealms.craftengine.core.loot.number; - -import net.momirealms.craftengine.core.loot.LootContext; -import net.momirealms.craftengine.core.util.Key; - -public interface NumberProvider { - - float getFloat(LootContext context); - - default int getInt(LootContext context) { - return Math.round(this.getFloat(context)); - } - - Key type(); -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/number/NumberProviderFactory.java b/core/src/main/java/net/momirealms/craftengine/core/loot/number/NumberProviderFactory.java deleted file mode 100644 index cc163082e..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/number/NumberProviderFactory.java +++ /dev/null @@ -1,8 +0,0 @@ -package net.momirealms.craftengine.core.loot.number; - -import java.util.Map; - -public interface NumberProviderFactory { - - NumberProvider create(Map arguments); -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/number/NumberProviders.java b/core/src/main/java/net/momirealms/craftengine/core/loot/number/NumberProviders.java deleted file mode 100644 index 32af65b44..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/number/NumberProviders.java +++ /dev/null @@ -1,64 +0,0 @@ -package net.momirealms.craftengine.core.loot.number; - -import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; -import net.momirealms.craftengine.core.registry.BuiltInRegistries; -import net.momirealms.craftengine.core.registry.Holder; -import net.momirealms.craftengine.core.registry.Registries; -import net.momirealms.craftengine.core.registry.WritableRegistry; -import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.ResourceConfigUtils; -import net.momirealms.craftengine.core.util.ResourceKey; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -public class NumberProviders { - public static final Key FIXED = Key.of("craftengine:constant"); - public static final Key UNIFORM = Key.of("craftengine:uniform"); - - static { - register(FIXED, FixedNumberProvider.FACTORY); - register(UNIFORM, UniformNumberProvider.FACTORY); - } - - public static void register(Key key, NumberProviderFactory factory) { - Holder.Reference holder = ((WritableRegistry) BuiltInRegistries.NUMBER_PROVIDER_FACTORY) - .registerForHolder(new ResourceKey<>(Registries.NUMBER_PROVIDER_FACTORY.location(), key)); - holder.bindValue(factory); - } - - public static List fromMapList(List> mapList) { - if (mapList == null || mapList.isEmpty()) return List.of(); - List functions = new ArrayList<>(); - for (Map map : mapList) { - functions.add(fromMap(map)); - } - return functions; - } - - public static NumberProvider fromMap(Map map) { - String type = ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("type"), "warning.config.loot_table.number.missing_type"); - Key key = Key.withDefaultNamespace(type, "craftengine"); - NumberProviderFactory factory = BuiltInRegistries.NUMBER_PROVIDER_FACTORY.getValue(key); - if (factory == null) { - throw new LocalizedResourceConfigException("warning.config.loot_table.number.invalid_type", type); - } - return factory.create(map); - } - - @SuppressWarnings("unchecked") - public static NumberProvider fromObject(Object object) { - if (object == null) { - throw new NullPointerException("number argument is null"); - } - if (object instanceof Number number) { - return new FixedNumberProvider(number.floatValue()); - } else if (object instanceof String string) { - return new FixedNumberProvider(Float.parseFloat(string)); - } else if (object instanceof Map map) { - return fromMap((Map) map); - } - throw new IllegalArgumentException("Can't convert " + object + " to " + NumberProvider.class.getSimpleName()); - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/number/UniformNumberProvider.java b/core/src/main/java/net/momirealms/craftengine/core/loot/number/UniformNumberProvider.java deleted file mode 100644 index b294daea1..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/number/UniformNumberProvider.java +++ /dev/null @@ -1,41 +0,0 @@ -package net.momirealms.craftengine.core.loot.number; - -import net.momirealms.craftengine.core.loot.LootContext; -import net.momirealms.craftengine.core.util.Key; - -import java.util.Map; - -public class UniformNumberProvider implements NumberProvider { - public static final Factory FACTORY = new Factory(); - private final NumberProvider min; - private final NumberProvider max; - - public UniformNumberProvider(NumberProvider min, NumberProvider max) { - this.min = min; - this.max = max; - } - - @Override - public int getInt(LootContext context) { - return context.randomSource().nextInt(this.min.getInt(context), this.max.getInt(context) + 1); - } - - @Override - public float getFloat(LootContext context) { - return context.randomSource().nextFloat(this.min.getFloat(context), this.max.getFloat(context)); - } - - @Override - public Key type() { - return NumberProviders.UNIFORM; - } - - public static class Factory implements NumberProviderFactory { - @Override - public NumberProvider create(Map arguments) { - Object min = arguments.getOrDefault("min", 1); - Object max = arguments.getOrDefault("max", 1); - return new UniformNumberProvider(NumberProviders.fromObject(min), NumberProviders.fromObject(max)); - } - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/parameter/LootParameters.java b/core/src/main/java/net/momirealms/craftengine/core/loot/parameter/LootParameters.java deleted file mode 100644 index ca09453ea..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/parameter/LootParameters.java +++ /dev/null @@ -1,21 +0,0 @@ -package net.momirealms.craftengine.core.loot.parameter; - -import net.momirealms.craftengine.core.block.ImmutableBlockState; -import net.momirealms.craftengine.core.entity.Entity; -import net.momirealms.craftengine.core.entity.player.Player; -import net.momirealms.craftengine.core.item.Item; -import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.context.ContextKey; -import net.momirealms.craftengine.core.world.Vec3d; -import net.momirealms.craftengine.core.world.World; - -public class LootParameters { - public static final ContextKey LOCATION = new ContextKey<>(Key.of("craftengine:location")); - public static final ContextKey WORLD = new ContextKey<>(Key.of("craftengine:world")); - public static final ContextKey ENTITY = new ContextKey<>(Key.of("craftengine:entity")); - public static final ContextKey FALLING_BLOCK = new ContextKey<>(Key.of("craftengine:falling_block")); - public static final ContextKey EXPLOSION_RADIUS = new ContextKey<>(Key.of("craftengine:explosion_radius")); - public static final ContextKey PLAYER = new ContextKey<>(Key.of("craftengine:player")); - public static final ContextKey> TOOL = new ContextKey<>(Key.of("craftengine:tool")); - public static final ContextKey BLOCK_STATE = new ContextKey<>(Key.of("craftengine:block_state")); -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java index 75cf89e13..b582cb7d9 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java @@ -6,7 +6,8 @@ import dev.dejvokep.boostedyaml.block.implementation.Section; import net.momirealms.craftengine.core.font.BitmapImage; import net.momirealms.craftengine.core.font.Font; import net.momirealms.craftengine.core.item.EquipmentData; -import net.momirealms.craftengine.core.pack.conflict.resolution.ConditionalResolution; +import net.momirealms.craftengine.core.pack.conflict.PathContext; +import net.momirealms.craftengine.core.pack.conflict.resolution.ResolutionConditional; import net.momirealms.craftengine.core.pack.host.ResourcePackHost; import net.momirealms.craftengine.core.pack.host.ResourcePackHosts; import net.momirealms.craftengine.core.pack.host.impl.NoneHost; @@ -43,6 +44,7 @@ import java.util.*; import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Predicate; +import java.util.stream.Stream; import static net.momirealms.craftengine.core.util.MiscUtils.castToMap; @@ -140,6 +142,7 @@ public abstract class AbstractPackManager implements PackManager { @Override public void load() { + initFileSystemProvider(); List> list = Config.instance().settings().getMapList("resource-pack.delivery.hosting"); if (list == null || list.isEmpty()) { this.resourcePackHost = NoneHost.INSTANCE; @@ -483,6 +486,36 @@ public abstract class AbstractPackManager implements PackManager { } } + private static void initFileSystemProvider() { + String osName = System.getProperty("os.name").toLowerCase(); + String providerClass = null; + if (osName.contains("win")) { + providerClass = "sun.nio.fs.WindowsFileSystemProvider"; + } else if (osName.contains("nix") || osName.contains("nux") || osName.contains("aix")) { + providerClass = "sun.nio.fs.LinuxFileSystemProvider"; + } else if (osName.contains("mac")) { + providerClass = "sun.nio.fs.MacOSXFileSystemProvider"; + } + if (providerClass != null) { + try { + System.setProperty("java.nio.file.spi.DefaultFileSystemProvider", providerClass); + } catch (Exception ignored) {} + } + } + + private static void deleteDirectory(Path folder) throws IOException { + if (!Files.exists(folder)) return; + try (Stream walk = Files.walk(folder)) { + walk.sorted(Comparator.reverseOrder()) + .parallel() + .forEach(path -> { + try { + Files.delete(path); + } catch (IOException ignored) {} + }); + } + } + @Override public void generateResourcePack() { this.plugin.logger().info("Generating resource pack..."); @@ -493,7 +526,7 @@ public abstract class AbstractPackManager implements PackManager { .resolve("resource_pack"); try { - org.apache.commons.io.FileUtils.deleteDirectory(generatedPackPath.toFile()); + deleteDirectory(generatedPackPath); } catch (IOException e) { this.plugin.logger().severe("Error deleting previous resource pack", e); } @@ -1155,9 +1188,12 @@ public abstract class AbstractPackManager implements PackManager { Files.copy(file, targetPath, StandardCopyOption.REPLACE_EXISTING); conflicts.add(file); } else { - for (ConditionalResolution resolution : Config.resolutions()) { - if (resolution.matcher().test(relative)) { - resolution.resolution().run(targetPath, file); + PathContext relativeCTX = PathContext.of(relative); + PathContext targetCTX = PathContext.of(targetPath); + PathContext fileCTX = PathContext.of(file); + for (ResolutionConditional resolution : Config.resolutions()) { + if (resolution.matcher().test(relativeCTX)) { + resolution.resolution().run(targetCTX, fileCTX); return FileVisitResult.CONTINUE; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/PathContext.java b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/PathContext.java new file mode 100644 index 000000000..55bdce4db --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/PathContext.java @@ -0,0 +1,23 @@ +package net.momirealms.craftengine.core.pack.conflict; + +import net.momirealms.craftengine.core.plugin.context.AbstractCommonContext; +import net.momirealms.craftengine.core.plugin.context.ContextHolder; + +import java.nio.file.Path; + +public class PathContext extends AbstractCommonContext { + private final Path path; + + public PathContext(ContextHolder holder, Path path) { + super(holder); + this.path = path; + } + + public Path path() { + return path; + } + + public static PathContext of(Path path) { + return new PathContext(ContextHolder.EMPTY, path); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/AllOfPathMatcher.java b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/AllOfPathMatcher.java deleted file mode 100644 index a353f7591..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/AllOfPathMatcher.java +++ /dev/null @@ -1,51 +0,0 @@ -package net.momirealms.craftengine.core.pack.conflict.matcher; - -import net.momirealms.craftengine.core.plugin.locale.LocalizedException; -import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.MiscUtils; - -import java.nio.file.Path; -import java.util.List; -import java.util.Map; - -public class AllOfPathMatcher implements PathMatcher { - public static final Factory FACTORY = new Factory(); - private final List matchers; - - public AllOfPathMatcher(List matchers) { - this.matchers = matchers; - } - - @Override - public Key type() { - return PathMatchers.ALL_OF; - } - - @Override - public boolean test(Path path) { - for (PathMatcher matcher : matchers) { - if (!matcher.test(path)) { - return false; - } - } - return true; - } - - public static class Factory implements PathMatcherFactory { - - @SuppressWarnings("unchecked") - @Override - public PathMatcher create(Map arguments) { - Object termsObj = arguments.get("terms"); - if (termsObj instanceof List list) { - List> terms = (List>) list; - return new AllOfPathMatcher(PathMatchers.fromMapList(terms)); - } else if (termsObj instanceof Map) { - Map terms = MiscUtils.castToMap(termsObj, false); - return new AllOfPathMatcher(PathMatchers.fromMapList(List.of(terms))); - } else { - throw new LocalizedException("warning.config.conflict_matcher.all_of.missing_terms"); - } - } - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/AnyOfPathMatcher.java b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/AnyOfPathMatcher.java deleted file mode 100644 index ad0632b19..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/AnyOfPathMatcher.java +++ /dev/null @@ -1,51 +0,0 @@ -package net.momirealms.craftengine.core.pack.conflict.matcher; - -import net.momirealms.craftengine.core.plugin.locale.LocalizedException; -import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.MiscUtils; - -import java.nio.file.Path; -import java.util.List; -import java.util.Map; - -public class AnyOfPathMatcher implements PathMatcher { - public static final Factory FACTORY = new Factory(); - private final List matchers; - - public AnyOfPathMatcher(List matchers) { - this.matchers = matchers; - } - - @Override - public Key type() { - return PathMatchers.ANY_OF; - } - - @Override - public boolean test(Path path) { - for (PathMatcher matcher : matchers) { - if (matcher.test(path)) { - return true; - } - } - return false; - } - - public static class Factory implements PathMatcherFactory { - - @SuppressWarnings("unchecked") - @Override - public PathMatcher create(Map arguments) { - Object termsObj = arguments.get("terms"); - if (termsObj instanceof List list) { - List> terms = (List>) list; - return new AnyOfPathMatcher(PathMatchers.fromMapList(terms)); - } else if (termsObj instanceof Map) { - Map terms = MiscUtils.castToMap(termsObj, false); - return new AnyOfPathMatcher(PathMatchers.fromMapList(List.of(terms))); - } else { - throw new LocalizedException("warning.config.conflict_matcher.any_of.missing_terms"); - } - } - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/InvertedPathMatcher.java b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/InvertedPathMatcher.java deleted file mode 100644 index f95c47da9..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/InvertedPathMatcher.java +++ /dev/null @@ -1,38 +0,0 @@ -package net.momirealms.craftengine.core.pack.conflict.matcher; - -import net.momirealms.craftengine.core.plugin.locale.LocalizedException; -import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.MiscUtils; -import net.momirealms.craftengine.core.util.ResourceConfigUtils; - -import java.nio.file.Path; -import java.util.Map; - -public class InvertedPathMatcher implements PathMatcher { - public static final Factory FACTORY = new Factory(); - private final PathMatcher matcher; - - public InvertedPathMatcher(PathMatcher matcher) { - this.matcher = matcher; - } - - @Override - public Key type() { - return PathMatchers.INVERTED; - } - - @Override - public boolean test(Path path) { - return !matcher.test(path); - } - - public static class Factory implements PathMatcherFactory { - - @Override - public PathMatcher create(Map arguments) { - Object inverted = ResourceConfigUtils.requireNonNullOrThrow(arguments.get("term"), () -> new LocalizedException("warning.config.conflict_matcher.inverted.missing_term")); - Map term = MiscUtils.castToMap(inverted, false); - return new InvertedPathMatcher(PathMatchers.fromMap(term)); - } - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathMatcher.java b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathMatcher.java deleted file mode 100644 index a03126da9..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathMatcher.java +++ /dev/null @@ -1,11 +0,0 @@ -package net.momirealms.craftengine.core.pack.conflict.matcher; - -import net.momirealms.craftengine.core.util.Key; - -import java.nio.file.Path; -import java.util.function.Predicate; - -public interface PathMatcher extends Predicate { - - Key type(); -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathContainsMatcher.java b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathMatcherContains.java similarity index 52% rename from core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathContainsMatcher.java rename to core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathMatcherContains.java index c8225f57e..3c17607ca 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathContainsMatcher.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathMatcherContains.java @@ -1,23 +1,24 @@ package net.momirealms.craftengine.core.pack.conflict.matcher; +import net.momirealms.craftengine.core.pack.conflict.PathContext; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.condition.ConditionFactory; import net.momirealms.craftengine.core.plugin.locale.LocalizedException; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; -import java.nio.file.Path; import java.util.Map; -public class PathContainsMatcher implements PathMatcher { - public static final Factory FACTORY = new Factory(); +public class PathMatcherContains implements Condition { private final String path; - public PathContainsMatcher(String path) { + public PathMatcherContains(String path) { this.path = path; } @Override - public boolean test(Path path) { - String pathStr = path.toString().replace("\\", "/"); + public boolean test(PathContext path) { + String pathStr = path.path().toString().replace("\\", "/"); return pathStr.contains(this.path); } @@ -26,12 +27,12 @@ public class PathContainsMatcher implements PathMatcher { return PathMatchers.CONTAINS; } - public static class Factory implements PathMatcherFactory { + public static class FactoryImpl implements ConditionFactory { @Override - public PathMatcher create(Map arguments) { + public Condition create(Map arguments) { String path = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("path"), () -> new LocalizedException("warning.config.conflict_matcher.contains.missing_path")); - return new PathContainsMatcher(path); + return new PathMatcherContains(path); } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/ExactPathMatcher.java b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathMatcherExact.java similarity index 52% rename from core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/ExactPathMatcher.java rename to core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathMatcherExact.java index 0fbdedb4b..bebd9c61a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/ExactPathMatcher.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathMatcherExact.java @@ -1,23 +1,24 @@ package net.momirealms.craftengine.core.pack.conflict.matcher; +import net.momirealms.craftengine.core.pack.conflict.PathContext; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.condition.ConditionFactory; import net.momirealms.craftengine.core.plugin.locale.LocalizedException; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; -import java.nio.file.Path; import java.util.Map; -public class ExactPathMatcher implements PathMatcher { - public static final Factory FACTORY = new Factory(); +public class PathMatcherExact implements Condition { private final String path; - public ExactPathMatcher(String path) { + public PathMatcherExact(String path) { this.path = path; } @Override - public boolean test(Path path) { - String pathStr = path.toString().replace("\\", "/"); + public boolean test(PathContext path) { + String pathStr = path.path().toString().replace("\\", "/"); return pathStr.equals(this.path); } @@ -26,12 +27,12 @@ public class ExactPathMatcher implements PathMatcher { return PathMatchers.EXACT; } - public static class Factory implements PathMatcherFactory { + public static class FactoryImpl implements ConditionFactory { @Override - public PathMatcher create(Map arguments) { + public Condition create(Map arguments) { String path = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("path"), () -> new LocalizedException("warning.config.conflict_matcher.exact.missing_path")); - return new ExactPathMatcher(path); + return new PathMatcherExact(path); } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathMatcherFactory.java b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathMatcherFactory.java deleted file mode 100644 index 7b9b2d9a0..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathMatcherFactory.java +++ /dev/null @@ -1,8 +0,0 @@ -package net.momirealms.craftengine.core.pack.conflict.matcher; - -import java.util.Map; - -public interface PathMatcherFactory { - - PathMatcher create(Map arguments); -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/FilenameMatcher.java b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathMatcherFilename.java similarity index 52% rename from core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/FilenameMatcher.java rename to core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathMatcherFilename.java index 9bfac4789..b7b7f2f26 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/FilenameMatcher.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathMatcherFilename.java @@ -1,23 +1,24 @@ package net.momirealms.craftengine.core.pack.conflict.matcher; +import net.momirealms.craftengine.core.pack.conflict.PathContext; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.condition.ConditionFactory; import net.momirealms.craftengine.core.plugin.locale.LocalizedException; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; -import java.nio.file.Path; import java.util.Map; -public class FilenameMatcher implements PathMatcher { - public static final Factory FACTORY = new Factory(); +public class PathMatcherFilename implements Condition { private final String name; - public FilenameMatcher(String name) { + public PathMatcherFilename(String name) { this.name = name; } @Override - public boolean test(Path path) { - String fileName = String.valueOf(path.getFileName()); + public boolean test(PathContext path) { + String fileName = String.valueOf(path.path().getFileName()); return fileName.equals(name); } @@ -26,12 +27,12 @@ public class FilenameMatcher implements PathMatcher { return PathMatchers.FILENAME; } - public static class Factory implements PathMatcherFactory { + public static class FactoryImpl implements ConditionFactory { @Override - public PathMatcher create(Map arguments) { + public Condition create(Map arguments) { String name = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("name"), () -> new LocalizedException("warning.config.conflict_matcher.filename.missing_name")); - return new FilenameMatcher(name); + return new PathMatcherFilename(name); } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/ParentPathPrefixMatcher.java b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathMatcherParentPrefix.java similarity index 57% rename from core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/ParentPathPrefixMatcher.java rename to core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathMatcherParentPrefix.java index 706010712..212ff4c39 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/ParentPathPrefixMatcher.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathMatcherParentPrefix.java @@ -1,5 +1,8 @@ package net.momirealms.craftengine.core.pack.conflict.matcher; +import net.momirealms.craftengine.core.pack.conflict.PathContext; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.condition.ConditionFactory; import net.momirealms.craftengine.core.plugin.locale.LocalizedException; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; @@ -7,17 +10,16 @@ import net.momirealms.craftengine.core.util.ResourceConfigUtils; import java.nio.file.Path; import java.util.Map; -public class ParentPathPrefixMatcher implements PathMatcher { - public static final Factory FACTORY = new Factory(); +public class PathMatcherParentPrefix implements Condition { private final String prefix; - public ParentPathPrefixMatcher(String prefix) { + public PathMatcherParentPrefix(String prefix) { this.prefix = prefix; } @Override - public boolean test(Path path) { - Path parent = path.getParent(); + public boolean test(PathContext path) { + Path parent = path.path().getParent(); if (parent == null) return false; String pathStr = parent.toString().replace("\\", "/"); return pathStr.startsWith(this.prefix); @@ -28,12 +30,12 @@ public class ParentPathPrefixMatcher implements PathMatcher { return PathMatchers.PARENT_PATH_PREFIX; } - public static class Factory implements PathMatcherFactory { + public static class FactoryImpl implements ConditionFactory { @Override - public PathMatcher create(Map arguments) { + public Condition create(Map arguments) { String prefix = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("prefix"), () -> new LocalizedException("warning.config.conflict_matcher.parent_prefix.missing_prefix")); - return new ParentPathPrefixMatcher(prefix); + return new PathMatcherParentPrefix(prefix); } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/ParentPathSuffixMatcher.java b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathMatcherParentSuffix.java similarity index 57% rename from core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/ParentPathSuffixMatcher.java rename to core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathMatcherParentSuffix.java index f31a62c83..77c061228 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/ParentPathSuffixMatcher.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathMatcherParentSuffix.java @@ -1,5 +1,8 @@ package net.momirealms.craftengine.core.pack.conflict.matcher; +import net.momirealms.craftengine.core.pack.conflict.PathContext; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.condition.ConditionFactory; import net.momirealms.craftengine.core.plugin.locale.LocalizedException; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; @@ -7,17 +10,16 @@ import net.momirealms.craftengine.core.util.ResourceConfigUtils; import java.nio.file.Path; import java.util.Map; -public class ParentPathSuffixMatcher implements PathMatcher { - public static final Factory FACTORY = new Factory(); +public class PathMatcherParentSuffix implements Condition { private final String suffix; - public ParentPathSuffixMatcher(String suffix) { + public PathMatcherParentSuffix(String suffix) { this.suffix = suffix; } @Override - public boolean test(Path path) { - Path parent = path.getParent(); + public boolean test(PathContext path) { + Path parent = path.path().getParent(); if (parent == null) return false; String pathStr = parent.toString().replace("\\", "/"); return pathStr.endsWith(suffix); @@ -28,12 +30,12 @@ public class ParentPathSuffixMatcher implements PathMatcher { return PathMatchers.PARENT_PATH_SUFFIX; } - public static class Factory implements PathMatcherFactory { + public static class FactoryImpl implements ConditionFactory { @Override - public PathMatcher create(Map arguments) { + public Condition create(Map arguments) { String suffix = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("suffix"), () -> new LocalizedException("warning.config.conflict_matcher.parent_suffix.missing_suffix")); - return new ParentPathSuffixMatcher(suffix); + return new PathMatcherParentSuffix(suffix); } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathMatchers.java b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathMatchers.java index a9de55bfd..7bffb8178 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathMatchers.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathMatchers.java @@ -1,5 +1,8 @@ package net.momirealms.craftengine.core.pack.conflict.matcher; +import net.momirealms.craftengine.core.pack.conflict.PathContext; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.condition.*; import net.momirealms.craftengine.core.plugin.locale.LocalizedException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Holder; @@ -20,42 +23,48 @@ public class PathMatchers { public static final Key PARENT_PATH_SUFFIX = Key.of("craftengine:parent_path_suffix"); public static final Key PARENT_PATH_PREFIX = Key.of("craftengine:parent_path_prefix"); public static final Key PATTERN = Key.of("craftengine:pattern"); - public static final Key ANY_OF = Key.of("craftengine:any_of"); - public static final Key ALL_OF = Key.of("craftengine:all_of"); - public static final Key INVERTED = Key.of("craftengine:inverted"); static { - register(PARENT_PATH_SUFFIX, ParentPathSuffixMatcher.FACTORY); - register(PARENT_PATH_PREFIX, ParentPathPrefixMatcher.FACTORY); - register(PATTERN, PathPatternMatcher.FACTORY); - register(EXACT, ExactPathMatcher.FACTORY); - register(FILENAME, FilenameMatcher.FACTORY); - register(ANY_OF, AnyOfPathMatcher.FACTORY); - register(ALL_OF, AllOfPathMatcher.FACTORY); - register(INVERTED, InvertedPathMatcher.FACTORY); - register(CONTAINS, PathContainsMatcher.FACTORY); + register(CommonConditions.ANY_OF, new AnyOfCondition.FactoryImpl<>(PathMatchers::fromMap)); + register(CommonConditions.ALL_OF, new AllOfCondition.FactoryImpl<>(PathMatchers::fromMap)); + register(CommonConditions.INVERTED, new InvertedCondition.FactoryImpl<>(PathMatchers::fromMap)); + register(PARENT_PATH_SUFFIX, new PathMatcherParentSuffix.FactoryImpl()); + register(PARENT_PATH_PREFIX, new PathMatcherParentPrefix.FactoryImpl()); + register(PATTERN, new PathPatternMatcher.FactoryImpl()); + register(EXACT, new PathMatcherExact.FactoryImpl()); + register(FILENAME, new PathMatcherFilename.FactoryImpl()); + register(CONTAINS, new PathMatcherContains.FactoryImpl()); } - public static void register(Key key, PathMatcherFactory factory) { - Holder.Reference holder = ((WritableRegistry) BuiltInRegistries.PATH_MATCHER_FACTORY).registerForHolder(new ResourceKey<>(Registries.PATH_MATCHER_FACTORY.location(), key)); + public static void register(Key key, ConditionFactory factory) { + Holder.Reference> holder = ((WritableRegistry>) BuiltInRegistries.PATH_MATCHER_FACTORY) + .registerForHolder(new ResourceKey<>(Registries.PATH_MATCHER_FACTORY.location(), key)); holder.bindValue(factory); } - public static List fromMapList(List> arguments) { - List matchers = new ArrayList<>(); + public static List> fromMapList(List> arguments) { + List> matchers = new ArrayList<>(); for (Map term : arguments) { matchers.add(PathMatchers.fromMap(term)); } return matchers; } - public static PathMatcher fromMap(Map map) { + public static Condition fromMap(Map map) { String type = ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("type"), () -> new LocalizedException("warning.config.conflict_matcher.missing_type")); - Key key = Key.withDefaultNamespace(type, "craftengine"); - PathMatcherFactory factory = BuiltInRegistries.PATH_MATCHER_FACTORY.getValue(key); - if (factory == null) { - throw new LocalizedException("warning.config.conflict_matcher.invalid_type", type); + Key key = Key.withDefaultNamespace(type, Key.DEFAULT_NAMESPACE); + if (key.value().charAt(0) == '!') { + ConditionFactory factory = BuiltInRegistries.PATH_MATCHER_FACTORY.getValue(new Key(key.namespace(), key.value().substring(1))); + if (factory == null) { + throw new LocalizedException("warning.config.conflict_matcher.invalid_type", type); + } + return new InvertedCondition<>(factory.create(map)); + } else { + ConditionFactory factory = BuiltInRegistries.PATH_MATCHER_FACTORY.getValue(key); + if (factory == null) { + throw new LocalizedException("warning.config.conflict_matcher.invalid_type", type); + } + return factory.create(map); } - return factory.create(map); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathPatternMatcher.java b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathPatternMatcher.java index e469c7a6e..6826a42aa 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathPatternMatcher.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathPatternMatcher.java @@ -1,15 +1,16 @@ package net.momirealms.craftengine.core.pack.conflict.matcher; +import net.momirealms.craftengine.core.pack.conflict.PathContext; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.condition.ConditionFactory; import net.momirealms.craftengine.core.plugin.locale.LocalizedException; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; -import java.nio.file.Path; import java.util.Map; import java.util.regex.Pattern; -public class PathPatternMatcher implements PathMatcher { - public static final Factory FACTORY = new Factory(); +public class PathPatternMatcher implements Condition { private final Pattern pattern; public PathPatternMatcher(String pattern) { @@ -21,8 +22,8 @@ public class PathPatternMatcher implements PathMatcher { } @Override - public boolean test(Path path) { - String pathStr = path.toString().replace("\\", "/"); + public boolean test(PathContext path) { + String pathStr = path.path().toString().replace("\\", "/"); return this.pattern.matcher(pathStr).matches(); } @@ -35,10 +36,10 @@ public class PathPatternMatcher implements PathMatcher { return pattern; } - public static class Factory implements PathMatcherFactory { + public static class FactoryImpl implements ConditionFactory { @Override - public PathMatcher create(Map arguments) { + public Condition create(Map arguments) { String pattern = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("pattern"), () -> new LocalizedException("warning.config.conflict_matcher.pattern.missing_pattern")); return new PathPatternMatcher(pattern); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/Resolution.java b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/Resolution.java index b33592e38..d1566f811 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/Resolution.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/Resolution.java @@ -1,12 +1,11 @@ package net.momirealms.craftengine.core.pack.conflict.resolution; +import net.momirealms.craftengine.core.pack.conflict.PathContext; import net.momirealms.craftengine.core.util.Key; -import java.nio.file.Path; - public interface Resolution { - void run(Path existing, Path conflict); + void run(PathContext existing, PathContext conflict); Key type(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/ConditionalResolution.java b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/ResolutionConditional.java similarity index 66% rename from core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/ConditionalResolution.java rename to core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/ResolutionConditional.java index d0079cf50..4eb182943 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/ConditionalResolution.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/ResolutionConditional.java @@ -1,18 +1,18 @@ package net.momirealms.craftengine.core.pack.conflict.resolution; -import net.momirealms.craftengine.core.pack.conflict.matcher.PathMatcher; +import net.momirealms.craftengine.core.pack.conflict.PathContext; import net.momirealms.craftengine.core.pack.conflict.matcher.PathMatchers; +import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; -import java.nio.file.Path; import java.util.Map; -public record ConditionalResolution(PathMatcher matcher, Resolution resolution) implements Resolution { +public record ResolutionConditional(Condition matcher, Resolution resolution) implements Resolution { public static final Factory FACTORY = new Factory(); @Override - public void run(Path existing, Path conflict) { + public void run(PathContext existing, PathContext conflict) { if (this.matcher.test(existing)) { this.resolution.run(existing, conflict); } @@ -26,10 +26,10 @@ public record ConditionalResolution(PathMatcher matcher, Resolution resolution) public static class Factory implements ResolutionFactory { @Override - public ConditionalResolution create(Map arguments) { + public ResolutionConditional create(Map arguments) { Map term = MiscUtils.castToMap(arguments.get("term"), false); Map resolution = MiscUtils.castToMap(arguments.get("resolution"), false); - return new ConditionalResolution(PathMatchers.fromMap(term), Resolutions.fromMap(resolution)); + return new ResolutionConditional(PathMatchers.fromMap(term), Resolutions.fromMap(resolution)); } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/ResolutionFactory.java b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/ResolutionFactory.java index b6533aa87..0e6235274 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/ResolutionFactory.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/ResolutionFactory.java @@ -2,6 +2,7 @@ package net.momirealms.craftengine.core.pack.conflict.resolution; import java.util.Map; +@FunctionalInterface public interface ResolutionFactory { Resolution create(Map arguments); diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/MergeAltasResolution.java b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/ResolutionMergeAltas.java similarity index 68% rename from core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/MergeAltasResolution.java rename to core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/ResolutionMergeAltas.java index 0445a763f..65e0daf81 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/MergeAltasResolution.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/ResolutionMergeAltas.java @@ -3,42 +3,41 @@ package net.momirealms.craftengine.core.pack.conflict.resolution; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import net.momirealms.craftengine.core.pack.conflict.PathContext; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.util.GsonHelper; import net.momirealms.craftengine.core.util.Key; -import java.io.IOException; -import java.nio.file.Path; import java.util.HashSet; import java.util.Map; -public class MergeAltasResolution implements Resolution { +public class ResolutionMergeAltas implements Resolution { public static final Factory FACTORY = new Factory(); - public static final MergeAltasResolution INSTANCE = new MergeAltasResolution(); + public static final ResolutionMergeAltas INSTANCE = new ResolutionMergeAltas(); @Override - public void run(Path existing, Path conflict) { + public void run(PathContext existing, PathContext conflict) { try { - JsonObject j1 = GsonHelper.readJsonFile(existing).getAsJsonObject(); - JsonObject j2 = GsonHelper.readJsonFile(conflict).getAsJsonObject(); + JsonObject j1 = GsonHelper.readJsonFile(existing.path()).getAsJsonObject(); + JsonObject j2 = GsonHelper.readJsonFile(conflict.path()).getAsJsonObject(); JsonObject j3 = new JsonObject(); JsonArray ja1 = j1.getAsJsonArray("sources"); JsonArray ja2 = j2.getAsJsonArray("sources"); JsonArray ja3 = new JsonArray(); HashSet elements = new HashSet<>(); for (JsonElement je : ja1) { - if (elements.add(je.getAsString())) { + if (elements.add(je.toString())) { ja3.add(je); } } for (JsonElement je : ja2) { - if (elements.add(je.getAsString())) { + if (elements.add(je.toString())) { ja3.add(je); } } j3.add("sources", ja3); - GsonHelper.writeJsonFile(j3, existing); - } catch (IOException e) { + GsonHelper.writeJsonFile(j3, existing.path()); + } catch (Exception e) { CraftEngine.instance().logger().severe("Failed to merge json when resolving file conflicts", e); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/MergeJsonResolution.java b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/ResolutionMergeJson.java similarity index 68% rename from core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/MergeJsonResolution.java rename to core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/ResolutionMergeJson.java index db9c77242..88679856d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/MergeJsonResolution.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/ResolutionMergeJson.java @@ -1,34 +1,34 @@ package net.momirealms.craftengine.core.pack.conflict.resolution; import com.google.gson.JsonObject; +import net.momirealms.craftengine.core.pack.conflict.PathContext; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.util.GsonHelper; import net.momirealms.craftengine.core.util.Key; import java.io.IOException; -import java.nio.file.Path; import java.util.Map; -public class MergeJsonResolution implements Resolution { +public class ResolutionMergeJson implements Resolution { public static final Factory FACTORY = new Factory(); private final boolean deeply; - public MergeJsonResolution(boolean deeply) { + public ResolutionMergeJson(boolean deeply) { this.deeply = deeply; } @Override - public void run(Path existing, Path conflict) { + public void run(PathContext existing, PathContext conflict) { try { - JsonObject j1 = GsonHelper.readJsonFile(existing).getAsJsonObject(); - JsonObject j2 = GsonHelper.readJsonFile(conflict).getAsJsonObject(); + JsonObject j1 = GsonHelper.readJsonFile(existing.path()).getAsJsonObject(); + JsonObject j2 = GsonHelper.readJsonFile(conflict.path()).getAsJsonObject(); JsonObject j3; if (deeply) { j3 = GsonHelper.deepMerge(j1, j2); } else { j3 = GsonHelper.shallowMerge(j1, j2); } - GsonHelper.writeJsonFile(j3, existing); + GsonHelper.writeJsonFile(j3, existing.path()); } catch (IOException e) { CraftEngine.instance().logger().severe("Failed to merge json when resolving file conflicts", e); } @@ -44,7 +44,7 @@ public class MergeJsonResolution implements Resolution { @Override public Resolution create(Map arguments) { boolean deeply = (boolean) arguments.getOrDefault("deeply", false); - return new MergeJsonResolution(deeply); + return new ResolutionMergeJson(deeply); } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/MergePackMcMetaResolution.java b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/ResolutionMergePackMcMeta.java similarity index 93% rename from core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/MergePackMcMetaResolution.java rename to core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/ResolutionMergePackMcMeta.java index 799466cc3..186a1c3eb 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/MergePackMcMetaResolution.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/ResolutionMergePackMcMeta.java @@ -1,6 +1,7 @@ package net.momirealms.craftengine.core.pack.conflict.resolution; import com.google.gson.*; +import net.momirealms.craftengine.core.pack.conflict.PathContext; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.util.AdventureHelper; import net.momirealms.craftengine.core.util.GsonHelper; @@ -10,11 +11,11 @@ import java.io.IOException; import java.nio.file.Path; import java.util.Map; -public class MergePackMcMetaResolution implements Resolution { +public class ResolutionMergePackMcMeta implements Resolution { public static final Factory FACTORY = new Factory(); private final String description; - public MergePackMcMetaResolution(String description) { + public ResolutionMergePackMcMeta(String description) { this.description = description; } @@ -191,9 +192,9 @@ public class MergePackMcMetaResolution implements Resolution { } @Override - public void run(Path existing, Path conflict) { + public void run(PathContext existing, PathContext conflict) { try { - mergeMcMeta(existing, conflict, AdventureHelper.componentToJsonElement(AdventureHelper.miniMessage().deserialize(this.description))); + mergeMcMeta(existing.path(), conflict.path(), AdventureHelper.componentToJsonElement(AdventureHelper.miniMessage().deserialize(this.description))); } catch (IOException e) { CraftEngine.instance().logger().severe("Failed to merge pack.mcmeta when resolving file conflicts", e); } @@ -208,7 +209,7 @@ public class MergePackMcMetaResolution implements Resolution { @Override public Resolution create(Map arguments) { String description = arguments.getOrDefault("description", "CraftEngine ResourcePack").toString(); - return new MergePackMcMetaResolution(description); + return new ResolutionMergePackMcMeta(description); } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/Resolutions.java b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/Resolutions.java index 38f7754ca..b80302a07 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/Resolutions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/Resolutions.java @@ -20,10 +20,10 @@ public class Resolutions { static { register(RETAIN_MATCHING, RetainMatchingResolution.FACTORY); - register(MERGE_JSON, MergeJsonResolution.FACTORY); - register(CONDITIONAL, ConditionalResolution.FACTORY); - register(MERGE_PACK_MCMETA, MergePackMcMetaResolution.FACTORY); - register(MERGE_ATLAS, MergeAltasResolution.FACTORY); + register(MERGE_JSON, ResolutionMergeJson.FACTORY); + register(CONDITIONAL, ResolutionConditional.FACTORY); + register(MERGE_PACK_MCMETA, ResolutionMergePackMcMeta.FACTORY); + register(MERGE_ATLAS, ResolutionMergeAltas.FACTORY); } public static void register(Key key, ResolutionFactory factory) { @@ -33,7 +33,7 @@ public class Resolutions { public static Resolution fromMap(Map map) { String type = ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("type"), () -> new LocalizedException("warning.config.conflict_resolution.missing_type")); - Key key = Key.withDefaultNamespace(type, "craftengine"); + Key key = Key.withDefaultNamespace(type, Key.DEFAULT_NAMESPACE); ResolutionFactory factory = BuiltInRegistries.RESOLUTION_FACTORY.getValue(key); if (factory == null) { throw new LocalizedException("warning.config.conflict_resolution.invalid_type", type); diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/RetainMatchingResolution.java b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/RetainMatchingResolution.java index 874279027..490e46671 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/RetainMatchingResolution.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/RetainMatchingResolution.java @@ -1,30 +1,30 @@ package net.momirealms.craftengine.core.pack.conflict.resolution; -import net.momirealms.craftengine.core.pack.conflict.matcher.PathMatcher; +import net.momirealms.craftengine.core.pack.conflict.PathContext; import net.momirealms.craftengine.core.pack.conflict.matcher.PathMatchers; import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; import java.io.IOException; import java.nio.file.Files; -import java.nio.file.Path; import java.nio.file.StandardCopyOption; import java.util.Map; public class RetainMatchingResolution implements Resolution { public static final Factory FACTORY = new Factory(); - private final PathMatcher matcher; + private final Condition matcher; - public RetainMatchingResolution(PathMatcher matcher) { + public RetainMatchingResolution(Condition matcher) { this.matcher = matcher; } @Override - public void run(Path existing, Path conflict) { + public void run(PathContext existing, PathContext conflict) { if (this.matcher.test(conflict)) { try { - Files.copy(conflict, existing, StandardCopyOption.REPLACE_EXISTING); + Files.copy(conflict.path(), existing.path(), StandardCopyOption.REPLACE_EXISTING); } catch (IOException e) { CraftEngine.instance().logger().warn("Failed to copy conflict file " + conflict + " to " + existing, e); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/host/ResourcePackHosts.java b/core/src/main/java/net/momirealms/craftengine/core/pack/host/ResourcePackHosts.java index 8421c62c8..3c88658fd 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/host/ResourcePackHosts.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/host/ResourcePackHosts.java @@ -27,7 +27,7 @@ public class ResourcePackHosts { register(SELF, SelfHost.FACTORY); register(EXTERNAL, ExternalHost.FACTORY); register(LOBFILE, LobFileHost.FACTORY); - register(S3, S3Host.FACTORY); + register(S3, S3HostFactory.INSTANCE); register(ALIST, AlistHost.FACTORY); register(DROPBOX, DropboxHost.FACTORY); register(ONEDRIVE, OneDriveHost.FACTORY); @@ -45,7 +45,7 @@ public class ResourcePackHosts { if (type == null) { throw new LocalizedException("warning.config.host.missing_type"); } - Key key = Key.withDefaultNamespace(type, "craftengine"); + Key key = Key.withDefaultNamespace(type, Key.DEFAULT_NAMESPACE); ResourcePackHostFactory factory = BuiltInRegistries.RESOURCE_PACK_HOST_FACTORY.getValue(key); if (factory == null) { throw new LocalizedException("warning.config.host.invalid_type", type); diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/S3HostFactory.java b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/S3HostFactory.java new file mode 100644 index 000000000..5de2fa3b0 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/S3HostFactory.java @@ -0,0 +1,54 @@ +package net.momirealms.craftengine.core.pack.host.impl; + +import net.momirealms.craftengine.core.pack.host.ResourcePackHost; +import net.momirealms.craftengine.core.pack.host.ResourcePackHostFactory; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.dependency.Dependencies; + +import java.util.List; +import java.util.Map; + +public class S3HostFactory implements ResourcePackHostFactory { + public static final S3HostFactory INSTANCE = new S3HostFactory(); + + @Override + public ResourcePackHost create(Map arguments) { + CraftEngine.instance().dependencyManager().loadDependencies( + List.of( + Dependencies.NETTY_HTTP, + Dependencies.NETTY_HTTP2, + Dependencies.REACTIVE_STREAMS, + Dependencies.AMAZON_AWSSDK_S3, + Dependencies.AMAZON_AWSSDK_NETTY_NIO_CLIENT, + Dependencies.AMAZON_AWSSDK_SDK_CORE, + Dependencies.AMAZON_AWSSDK_AUTH, + Dependencies.AMAZON_AWSSDK_REGIONS, + Dependencies.AMAZON_AWSSDK_IDENTITY_SPI, + Dependencies.AMAZON_AWSSDK_HTTP_CLIENT_SPI, + Dependencies.AMAZON_AWSSDK_PROTOCOL_CORE, + Dependencies.AMAZON_AWSSDK_AWS_XML_PROTOCOL, + Dependencies.AMAZON_AWSSDK_JSON_UTILS, + Dependencies.AMAZON_AWSSDK_AWS_CORE, + Dependencies.AMAZON_AWSSDK_UTILS, + Dependencies.AMAZON_AWSSDK_ANNOTATIONS, + Dependencies.AMAZON_AWSSDK_CRT_CORE, + Dependencies.AMAZON_AWSSDK_CHECKSUMS, + Dependencies.AMAZON_EVENTSTREAM, + Dependencies.AMAZON_AWSSDK_PROFILES, + Dependencies.AMAZON_AWSSDK_RETRIES, + Dependencies.AMAZON_AWSSDK_ENDPOINTS_SPI, + Dependencies.AMAZON_AWSSDK_ARNS, + Dependencies.AMAZON_AWSSDK_AWS_QUERY_PROTOCOL, + Dependencies.AMAZON_AWSSDK_HTTP_AUTH_AWS, + Dependencies.AMAZON_AWSSDK_HTTP_AUTH_SPI, + Dependencies.AMAZON_AWSSDK_HTTP_AUTH, + Dependencies.AMAZON_AWSSDK_HTTP_AUTH_AWS_EVENTSTREAM, + Dependencies.AMAZON_AWSSDK_CHECKSUMS_SPI, + Dependencies.AMAZON_AWSSDK_RETRIES_SPI, + Dependencies.AMAZON_AWSSDK_METRICS_SPI, + Dependencies.AMAZON_AWSSDK_THIRD_PARTY_JACKSON_CORE + ) + ); + return S3Host.FACTORY.create(arguments); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHost.java b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHost.java index de38d7771..acfdd0800 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHost.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHost.java @@ -66,6 +66,13 @@ public class SelfHost implements ResourcePackHost { if (port <= 0 || port > 65535) { throw new LocalizedException("warning.config.host.self.invalid_port", String.valueOf(port)); } + String url = arguments.getOrDefault("url", "").toString(); + if (!url.isEmpty()) { + if (!url.startsWith("http://") && !url.startsWith("https://")) { + throw new LocalizedException("warning.config.host.self.invalid_url", url); + } + if (!url.endsWith("/")) url += "/"; + } boolean oneTimeToken = (boolean) arguments.getOrDefault("one-time-token", true); String protocol = arguments.getOrDefault("protocol", "http").toString(); boolean denyNonMinecraftRequest = (boolean) arguments.getOrDefault("deny-non-minecraft-request", true); @@ -76,7 +83,7 @@ public class SelfHost implements ResourcePackHost { maxRequests = ResourceConfigUtils.getAsInt(rateMap.getOrDefault("max-requests", 5), "max-requests"); resetInterval = ResourceConfigUtils.getAsInt(rateMap.getOrDefault("reset-interval", 20), "reset-interval") * 1000; } - selfHostHttpServer.updateProperties(ip, port, denyNonMinecraftRequest, protocol, maxRequests, resetInterval, oneTimeToken); + selfHostHttpServer.updateProperties(ip, port, url, denyNonMinecraftRequest, protocol, maxRequests, resetInterval, oneTimeToken); return INSTANCE; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHostHttpServer.java b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHostHttpServer.java index 6ce927583..785a00c6d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHostHttpServer.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHostHttpServer.java @@ -48,6 +48,7 @@ public class SelfHostHttpServer { private String ip = "localhost"; private int port = -1; private String protocol = "http"; + private String url; private boolean denyNonMinecraft = true; private boolean useToken; @@ -57,12 +58,14 @@ public class SelfHostHttpServer { public void updateProperties(String ip, int port, + String url, boolean denyNonMinecraft, String protocol, int maxRequests, int resetInternal, boolean token) { this.ip = ip; + this.url = url; this.denyNonMinecraft = denyNonMinecraft; this.protocol = protocol; this.rateLimit = maxRequests; @@ -112,6 +115,9 @@ public class SelfHostHttpServer { } public String url() { + if (this.url != null && !this.url.isEmpty()) { + return this.url; + } return this.protocol + "://" + this.ip + ":" + this.port + "/"; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java index a0c9669e2..64fa38f73 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java @@ -42,11 +42,11 @@ import java.util.function.Supplier; public abstract class CraftEngine implements Plugin { public static final String MOD_CLASS = "net.momirealms.craftengine.mod.CraftEnginePlugin"; - public static final String NAMESPACE = "craftengine"; private static CraftEngine instance; protected PluginLogger logger; protected Consumer> debugger = (s) -> {}; protected Config config; + protected Platform platform; protected ClassPathAppender classPathAppender; protected DependencyManager dependencyManager; protected SchedulerAdapter scheduler; @@ -288,49 +288,16 @@ public abstract class CraftEngine implements Plugin { Dependencies.GEANTY_REF, Dependencies.CLOUD_CORE, Dependencies.CLOUD_SERVICES, Dependencies.GSON, - Dependencies.SLF4J_API, Dependencies.SLF4J_SIMPLE, Dependencies.COMMONS_IO, Dependencies.ZSTD, Dependencies.BYTE_BUDDY, Dependencies.SNAKE_YAML, Dependencies.BOOSTED_YAML, Dependencies.MINIMESSAGE, - Dependencies.TEXT_SERIALIZER_GSON, Dependencies.TEXT_SERIALIZER_GSON_LEGACY, - Dependencies.TEXT_SERIALIZER_JSON, + Dependencies.TEXT_SERIALIZER_GSON, Dependencies.TEXT_SERIALIZER_GSON_LEGACY, Dependencies.TEXT_SERIALIZER_JSON, Dependencies.AHO_CORASICK, Dependencies.LZ4, - Dependencies.NETTY_HTTP, - Dependencies.NETTY_HTTP2, - Dependencies.REACTIVE_STREAMS, - Dependencies.AMAZON_AWSSDK_S3, - Dependencies.AMAZON_AWSSDK_NETTY_NIO_CLIENT, - Dependencies.AMAZON_AWSSDK_SDK_CORE, - Dependencies.AMAZON_AWSSDK_AUTH, - Dependencies.AMAZON_AWSSDK_REGIONS, - Dependencies.AMAZON_AWSSDK_IDENTITY_SPI, - Dependencies.AMAZON_AWSSDK_HTTP_CLIENT_SPI, - Dependencies.AMAZON_AWSSDK_PROTOCOL_CORE, - Dependencies.AMAZON_AWSSDK_AWS_XML_PROTOCOL, - Dependencies.AMAZON_AWSSDK_JSON_UTILS, - Dependencies.AMAZON_AWSSDK_AWS_CORE, - Dependencies.AMAZON_AWSSDK_UTILS, - Dependencies.AMAZON_AWSSDK_ANNOTATIONS, - Dependencies.AMAZON_AWSSDK_CRT_CORE, - Dependencies.AMAZON_AWSSDK_CHECKSUMS, - Dependencies.AMAZON_EVENTSTREAM, - Dependencies.AMAZON_AWSSDK_PROFILES, - Dependencies.AMAZON_AWSSDK_RETRIES, - Dependencies.AMAZON_AWSSDK_ENDPOINTS_SPI, - Dependencies.AMAZON_AWSSDK_ARNS, - Dependencies.AMAZON_AWSSDK_AWS_QUERY_PROTOCOL, - Dependencies.AMAZON_AWSSDK_HTTP_AUTH_AWS, - Dependencies.AMAZON_AWSSDK_HTTP_AUTH_SPI, - Dependencies.AMAZON_AWSSDK_HTTP_AUTH, - Dependencies.AMAZON_AWSSDK_HTTP_AUTH_AWS_EVENTSTREAM, - Dependencies.AMAZON_AWSSDK_CHECKSUMS_SPI, - Dependencies.AMAZON_AWSSDK_RETRIES_SPI, - Dependencies.AMAZON_AWSSDK_METRICS_SPI, - Dependencies.AMAZON_AWSSDK_THIRD_PARTY_JACKSON_CORE + Dependencies.EVALEX ); } @@ -462,4 +429,9 @@ public abstract class CraftEngine implements Plugin { public CompatibilityManager compatibilityManager() { return compatibilityManager; } + + @Override + public Platform platform() { + return platform; + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/Platform.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/Platform.java new file mode 100644 index 000000000..3c48cfb5e --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/Platform.java @@ -0,0 +1,6 @@ +package net.momirealms.craftengine.core.plugin; + +public interface Platform { + + void dispatchCommand(String command); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/Plugin.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/Plugin.java index d7d693264..37ef07865 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/Plugin.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/Plugin.java @@ -90,4 +90,6 @@ public interface Plugin { void debug(Supplier message); CompatibilityManager compatibilityManager(); + + Platform platform(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/command/FlagKeys.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/command/FlagKeys.java index 5cde8bd5c..a53e05dfa 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/command/FlagKeys.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/command/FlagKeys.java @@ -3,8 +3,10 @@ package net.momirealms.craftengine.core.plugin.command; import org.incendo.cloud.parser.flag.CommandFlag; public final class FlagKeys { + private FlagKeys() {} + public static final String SILENT = "silent"; - public static final CommandFlag SILENT_FLAG = CommandFlag.builder("silent").withAliases("s").build(); + public static final CommandFlag SILENT_FLAG = CommandFlag.builder(SILENT).withAliases("s").build(); public static final String TO_INVENTORY = "to-inventory"; - public static final CommandFlag TO_INVENTORY_FLAG = CommandFlag.builder("to-inventory").build(); + public static final CommandFlag TO_INVENTORY_FLAG = CommandFlag.builder(TO_INVENTORY).build(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java index e823d35e4..fde4746d5 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java @@ -13,7 +13,7 @@ import dev.dejvokep.boostedyaml.settings.updater.UpdaterSettings; import dev.dejvokep.boostedyaml.utils.format.NodeRole; import net.kyori.adventure.text.Component; import net.momirealms.craftengine.core.entity.furniture.ColliderType; -import net.momirealms.craftengine.core.pack.conflict.resolution.ConditionalResolution; +import net.momirealms.craftengine.core.pack.conflict.resolution.ResolutionConditional; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.PluginProperties; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; @@ -23,6 +23,7 @@ import net.momirealms.craftengine.core.util.AdventureHelper; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.ReflectionUtils; +import net.momirealms.craftengine.core.world.InjectionTarget; import net.momirealms.craftengine.core.world.chunk.storage.CompressionMethod; import java.io.File; @@ -46,6 +47,7 @@ public class Config { private final String configVersion; private YamlDocument config; + protected boolean firstTime = true; protected boolean debug; protected boolean checkUpdate; protected boolean metrics; @@ -54,7 +56,7 @@ public class Config { protected boolean resource_pack$remove_tinted_leaves_particle; protected boolean resource_pack$generate_mod_assets; protected boolean resource_pack$override_uniform_font; - protected List resource_pack$duplicated_files_handler; + protected List resource_pack$duplicated_files_handler; protected List resource_pack$merge_external_folders; protected boolean resource_pack$protection$crash_tools$method_1; @@ -99,8 +101,9 @@ public class Config { protected boolean chunk_system$restore_vanilla_blocks_on_chunk_unload; protected boolean chunk_system$restore_custom_blocks_on_chunk_load; protected boolean chunk_system$sync_custom_blocks_on_chunk_load; - protected int chunk_system$delay_serialization; - protected boolean chunk_system$fast_paletted_injection; + protected boolean chunk_system$cache_system; + protected boolean chunk_system$injection$use_fast_method; + protected boolean chunk_system$injection$target; protected boolean furniture$handle_invalid_furniture_on_chunk_load$enable; protected Map furniture$handle_invalid_furniture_on_chunk_load$mapping; @@ -245,7 +248,7 @@ public class Config { try { resource_pack$duplicated_files_handler = config.getMapList("resource-pack.duplicated-files-handler").stream().map(it -> { Map args = MiscUtils.castToMap(it, false); - return ConditionalResolution.FACTORY.create(args); + return ResolutionConditional.FACTORY.create(args); }).toList(); } catch (LocalizedResourceConfigException e) { TranslationManager.instance().log(e.node(), e.arguments()); @@ -271,8 +274,11 @@ public class Config { chunk_system$restore_vanilla_blocks_on_chunk_unload = config.getBoolean("chunk-system.restore-vanilla-blocks-on-chunk-unload", true); chunk_system$restore_custom_blocks_on_chunk_load = config.getBoolean("chunk-system.restore-custom-blocks-on-chunk-load", true); chunk_system$sync_custom_blocks_on_chunk_load = config.getBoolean("chunk-system.sync-custom-blocks-on-chunk-load", false); - chunk_system$delay_serialization = config.getInt("chunk-system.delay-serialization", 20); - chunk_system$fast_paletted_injection = config.getBoolean("chunk-system.fast-palette-injection", false); + chunk_system$cache_system = config.getBoolean("chunk-system.cache-system", true); + chunk_system$injection$use_fast_method = config.getBoolean("chunk-system.injection.use-fast-method", false); + if (firstTime) { + chunk_system$injection$target = config.getEnum("chunk-system.injection.target", InjectionTarget.class, InjectionTarget.PALETTE) == InjectionTarget.PALETTE; + } // furniture furniture$handle_invalid_furniture_on_chunk_load$enable = config.getBoolean("furniture.handle-invalid-furniture-on-chunk-load.enable", false); @@ -342,6 +348,8 @@ public class Config { plugin.logger().warn("Failed to set max chain update", e); } } + + firstTime = false; } private static float getVersion(String version) { @@ -479,7 +487,7 @@ public class Config { return instance.resource_pack$delivery$file_to_upload; } - public static List resolutions() { + public static List resolutions() { return instance.resource_pack$duplicated_files_handler; } @@ -691,12 +699,16 @@ public class Config { return instance.furniture$collision_entity_type; } - public static int delaySerialization() { - return instance.chunk_system$delay_serialization; + public static boolean enableChunkCache() { + return instance.chunk_system$cache_system; } - public static boolean fastPaletteInjection() { - return instance.chunk_system$fast_paletted_injection; + public static boolean fastInjection() { + return instance.chunk_system$injection$use_fast_method; + } + + public static boolean injectionTarget() { + return instance.chunk_system$injection$target; } public YamlDocument loadOrCreateYamlData(String fileName) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateArguments.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateArguments.java index a49348a04..f437a7493 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateArguments.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateArguments.java @@ -36,7 +36,7 @@ public class TemplateArguments { if (type == null) { return MapTemplateArgument.FACTORY.create(map); } else { - Key key = Key.withDefaultNamespace(type, "craftengine"); + Key key = Key.withDefaultNamespace(type, Key.DEFAULT_NAMESPACE); TemplateArgumentFactory factory = BuiltInRegistries.TEMPLATE_ARGUMENT_FACTORY.getValue(key); if (factory == null) { throw new IllegalArgumentException("Unknown argument type: " + type); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/AbstractAdditionalParameterContext.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/AbstractAdditionalParameterContext.java new file mode 100644 index 000000000..97a3ff9b9 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/AbstractAdditionalParameterContext.java @@ -0,0 +1,42 @@ +package net.momirealms.craftengine.core.plugin.context; + +import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameterProvider; + +import java.util.List; +import java.util.Optional; + +public abstract class AbstractAdditionalParameterContext extends AbstractCommonContext { + private final List providers; + + public AbstractAdditionalParameterContext(ContextHolder contexts, List providers) { + super(contexts); + this.providers = providers; + } + + public AbstractAdditionalParameterContext(ContextHolder contexts) { + super(contexts); + this.providers = List.of(new CommonParameterProvider()); + } + + @Override + public Optional getOptionalParameter(ContextKey parameter) { + for (LazyContextParameterProvider provider : providers) { + Optional result = provider.getOptionalParameter(parameter); + if (result.isPresent()) { + return result; + } + } + return super.getOptionalParameter(parameter); + } + + @Override + public T getParameterOrThrow(ContextKey parameter) { + for (LazyContextParameterProvider provider : providers) { + Optional result = provider.getOptionalParameter(parameter); + if (result.isPresent()) { + return result.get(); + } + } + return super.getParameterOrThrow(parameter); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/AbstractCommonContext.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/AbstractCommonContext.java new file mode 100644 index 000000000..4717ae0e0 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/AbstractCommonContext.java @@ -0,0 +1,48 @@ +package net.momirealms.craftengine.core.plugin.context; + +import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; +import net.momirealms.craftengine.core.plugin.text.minimessage.*; +import org.jetbrains.annotations.NotNull; + +import java.util.Optional; + +public abstract class AbstractCommonContext implements Context { + protected final ContextHolder contexts; + protected TagResolver[] tagResolvers; + + public AbstractCommonContext(ContextHolder contexts) { + this.contexts = contexts; + } + + @Override + public ContextHolder contexts() { + return this.contexts; + } + + @Override + @NotNull + public TagResolver[] tagResolvers() { + if (this.tagResolvers == null) { + this.tagResolvers = new TagResolver[]{ShiftTag.INSTANCE, ImageTag.INSTANCE, new I18NTag(this), new NamedArgumentTag(this), + new PlaceholderTag(null), new ExpressionTag(this)}; + } + return this.tagResolvers; + } + + @Override + public Optional getOptionalParameter(ContextKey parameter) { + return this.contexts.getOptional(parameter); + } + + @Override + public T getParameterOrThrow(ContextKey parameter) { + return this.contexts.getOrThrow(parameter); + } + + // It's not designed as mutable +// @Override +// public AbstractCommonContext withParameter(ContextKey parameter, T value) { +// this.contexts.withParameter(parameter, value); +// return this; +// } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/Condition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/Condition.java new file mode 100644 index 000000000..d2b05a7fa --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/Condition.java @@ -0,0 +1,15 @@ +package net.momirealms.craftengine.core.plugin.context; + +import net.momirealms.craftengine.core.util.Key; + +import java.util.function.Predicate; + +public interface Condition extends Predicate { + + @Override + default boolean test(CTX ctx) { + return false; + } + + Key type(); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/Context.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/Context.java new file mode 100644 index 000000000..989def892 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/Context.java @@ -0,0 +1,16 @@ +package net.momirealms.craftengine.core.plugin.context; + +import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; + +import java.util.Optional; + +public interface Context { + + ContextHolder contexts(); + + TagResolver[] tagResolvers(); + + Optional getOptionalParameter(ContextKey parameter); + + T getParameterOrThrow(ContextKey parameter); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/ContextHolder.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/ContextHolder.java new file mode 100644 index 000000000..d184c694e --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/ContextHolder.java @@ -0,0 +1,136 @@ +package net.momirealms.craftengine.core.plugin.context; + +import com.google.common.collect.ImmutableMap; + +import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Optional; +import java.util.function.Supplier; + +public class ContextHolder { + public static final ContextHolder EMPTY = ContextHolder.builder().immutable(true).build(); + protected final Map, Supplier> params; + + public ContextHolder(Map, Supplier> params) { + this.params = params; + } + + public boolean has(ContextKey key) { + return this.params.containsKey(key); + } + + public ContextHolder withParameter(ContextKey parameter, T value) { + this.params.put(parameter, SimpleSupplier.of(value)); + return this; + } + + @SuppressWarnings("unchecked") + public ContextHolder withParameter(ContextKey parameter, Supplier value) { + this.params.put(parameter, (Supplier) value); + return this; + } + + public ContextHolder withOptionalParameter(ContextKey parameter, @Nullable T value) { + if (value == null) { + this.params.remove(parameter); + } else { + this.params.put(parameter, SimpleSupplier.of(value)); + } + return this; + } + + @SuppressWarnings("unchecked") + public T getOrThrow(ContextKey parameter) { + Supplier object = (Supplier) this.params.get(parameter); + if (object == null) { + throw new NoSuchElementException(parameter.id().toString()); + } else { + return object.get(); + } + } + + @SuppressWarnings("unchecked") + public Optional getOptional(ContextKey parameter) { + return (Optional) Optional.ofNullable(this.params.get(parameter)).map(Supplier::get); + } + + @SuppressWarnings("unchecked") + @Nullable + public T getOrDefault(ContextKey parameter, @Nullable T defaultValue) { + return (T) Optional.ofNullable(this.params.get(parameter)).map(Supplier::get).orElse(defaultValue); + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private final Map, Supplier> params = new HashMap<>(); + private boolean immutable = false; + + public Builder() {} + + public Builder withParameter(ContextKey parameter, T value) { + this.params.put(parameter, SimpleSupplier.of(value)); + return this; + } + + @SuppressWarnings("unchecked") + public Builder withParameter(ContextKey parameter, Supplier value) { + this.params.put(parameter, (Supplier) value); + return this; + } + + public Builder withOptionalParameter(ContextKey parameter, @Nullable T value) { + if (value == null) { + this.params.remove(parameter); + } else { + this.params.put(parameter, SimpleSupplier.of(value)); + } + return this; + } + + @SuppressWarnings("unchecked") + public T getParameterOrThrow(ContextKey parameter) { + Supplier object = (Supplier) this.params.get(parameter); + if (object == null) { + throw new NoSuchElementException(parameter.id()); + } else { + return object.get(); + } + } + + public Builder immutable(boolean immutable) { + this.immutable = immutable; + return this; + } + + @SuppressWarnings("unchecked") + public Optional getOptionalParameter(ContextKey parameter) { + return Optional.ofNullable((Supplier) this.params.get(parameter)).map(Supplier::get); + } + + public ContextHolder build() { + return new ContextHolder(this.immutable ? ImmutableMap.copyOf(this.params) : this.params); + } + } + + public static class SimpleSupplier implements Supplier { + private final T object; + + public SimpleSupplier(T object) { + this.object = object; + } + + @Override + public T get() { + return this.object; + } + + public static SimpleSupplier of(T object) { + return new SimpleSupplier<>(object); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/context/ContextKey.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/ContextKey.java similarity index 63% rename from core/src/main/java/net/momirealms/craftengine/core/util/context/ContextKey.java rename to core/src/main/java/net/momirealms/craftengine/core/plugin/context/ContextKey.java index 4ea446ffb..a33dffffd 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/context/ContextKey.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/ContextKey.java @@ -1,28 +1,22 @@ -package net.momirealms.craftengine.core.util.context; +package net.momirealms.craftengine.core.plugin.context; -import net.momirealms.craftengine.core.util.Key; import org.jetbrains.annotations.NotNull; public class ContextKey { - private final Key id; + private final String id; - public ContextKey(@NotNull Key id) { + public ContextKey(@NotNull String id) { this.id = id; } @NotNull - public Key id() { + public String id() { return id; } - @NotNull - public static ContextKey of(@NotNull Key id) { - return new ContextKey<>(id); - } - @NotNull public static ContextKey of(@NotNull String id) { - return new ContextKey<>(Key.of(id)); + return new ContextKey<>(id); } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/LazyContextParameterProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/LazyContextParameterProvider.java new file mode 100644 index 000000000..0758f7770 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/LazyContextParameterProvider.java @@ -0,0 +1,21 @@ +package net.momirealms.craftengine.core.plugin.context; + +import java.util.Optional; + +public interface LazyContextParameterProvider { + + Optional getOptionalParameter(ContextKey parameter); + + static LazyContextParameterProvider dummy() { + return DummyContextParameterProvider.INSTANCE; + } + + class DummyContextParameterProvider implements LazyContextParameterProvider { + static final DummyContextParameterProvider INSTANCE = new DummyContextParameterProvider(); + + @Override + public Optional getOptionalParameter(ContextKey parameter) { + return Optional.empty(); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/PlayerBlockActionContext.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/PlayerBlockActionContext.java new file mode 100644 index 000000000..bbabeb79a --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/PlayerBlockActionContext.java @@ -0,0 +1,21 @@ +package net.momirealms.craftengine.core.plugin.context; + +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.plugin.context.parameter.BlockParameterProvider; +import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameterProvider; +import net.momirealms.craftengine.core.plugin.context.parameter.PlayerParameterProvider; +import net.momirealms.craftengine.core.world.BlockInWorld; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public class PlayerBlockActionContext extends PlayerOptionalContext { + + public PlayerBlockActionContext(@NotNull Player player, @NotNull BlockInWorld block, @NotNull ContextHolder contexts) { + super(player, contexts, List.of(new CommonParameterProvider(), new PlayerParameterProvider(player), new BlockParameterProvider(block))); + } + + public static PlayerBlockActionContext of(@NotNull Player player, @NotNull BlockInWorld block, @NotNull ContextHolder contexts) { + return new PlayerBlockActionContext(player, block, contexts); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/PlayerFurnitureActionContext.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/PlayerFurnitureActionContext.java new file mode 100644 index 000000000..4066c0405 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/PlayerFurnitureActionContext.java @@ -0,0 +1,20 @@ +package net.momirealms.craftengine.core.plugin.context; + +import net.momirealms.craftengine.core.entity.furniture.Furniture; +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameterProvider; +import net.momirealms.craftengine.core.plugin.context.parameter.PlayerParameterProvider; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public class PlayerFurnitureActionContext extends PlayerOptionalContext { + + public PlayerFurnitureActionContext(@NotNull Player player, @NotNull Furniture furniture, @NotNull ContextHolder contexts) { + super(player, contexts, List.of(new CommonParameterProvider(), new PlayerParameterProvider(player))); + } + + public static PlayerFurnitureActionContext of(@NotNull Player player, @NotNull Furniture furniture, @NotNull ContextHolder contexts) { + return new PlayerFurnitureActionContext(player, furniture, contexts); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/PlayerOptionalContext.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/PlayerOptionalContext.java new file mode 100644 index 000000000..e471cc51a --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/PlayerOptionalContext.java @@ -0,0 +1,59 @@ +package net.momirealms.craftengine.core.plugin.context; + +import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameterProvider; +import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; +import net.momirealms.craftengine.core.plugin.context.parameter.PlayerParameterProvider; +import net.momirealms.craftengine.core.plugin.text.minimessage.*; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Map; + +public class PlayerOptionalContext extends AbstractAdditionalParameterContext implements Context { + public static final PlayerOptionalContext EMPTY = new PlayerOptionalContext(null, ContextHolder.EMPTY); + protected final Player player; + + public PlayerOptionalContext(@Nullable Player player, @NotNull ContextHolder contexts) { + super(contexts, player == null ? List.of(new CommonParameterProvider()) : List.of(new CommonParameterProvider(), new PlayerParameterProvider(player))); + this.player = player; + } + + public PlayerOptionalContext(@Nullable Player player, @NotNull ContextHolder contexts, @NotNull List providers) { + super(contexts, providers); + this.player = player; + } + + @NotNull + public static PlayerOptionalContext of(@Nullable Player player, @NotNull ContextHolder contexts) { + return new PlayerOptionalContext(player, contexts); + } + + @NotNull + public static PlayerOptionalContext of(@Nullable Player player, @NotNull ContextHolder.Builder contexts) { + if (player != null) contexts.withParameter(CommonParameters.PLAYER, player); + return new PlayerOptionalContext(player, contexts.build()); + } + + @NotNull + public static PlayerOptionalContext of(@Nullable Player player) { + if (player == null) return EMPTY; + return new PlayerOptionalContext(player, new ContextHolder(Map.of(CommonParameters.PLAYER, () -> player))); + } + + @Nullable + public Player player() { + return this.player; + } + + @Override + @NotNull + public TagResolver[] tagResolvers() { + if (this.tagResolvers == null) { + this.tagResolvers = new TagResolver[]{ShiftTag.INSTANCE, ImageTag.INSTANCE, new PlaceholderTag(this.player), new I18NTag(this), new NamedArgumentTag(this), new ExpressionTag(this)}; + } + return this.tagResolvers; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/RelationalContext.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/RelationalContext.java new file mode 100644 index 000000000..7879b155b --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/RelationalContext.java @@ -0,0 +1,12 @@ +package net.momirealms.craftengine.core.plugin.context; + +import java.util.Optional; + +public interface RelationalContext extends Context { + + ContextHolder viewerContexts(); + + Optional getViewerOptionalParameter(ContextKey parameter); + + T getViewerParameterOrThrow(ContextKey parameter); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/SimpleContext.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/SimpleContext.java new file mode 100644 index 000000000..a6b92e94e --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/SimpleContext.java @@ -0,0 +1,12 @@ +package net.momirealms.craftengine.core.plugin.context; + +public class SimpleContext extends AbstractCommonContext { + + public SimpleContext(ContextHolder contexts) { + super(contexts); + } + + public static SimpleContext of(ContextHolder contexts) { + return new SimpleContext(contexts); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/ViewerContext.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/ViewerContext.java new file mode 100644 index 000000000..4591d242d --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/ViewerContext.java @@ -0,0 +1,67 @@ +package net.momirealms.craftengine.core.plugin.context; + +import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.plugin.text.minimessage.*; + +import java.util.Optional; + +public class ViewerContext implements RelationalContext { + private final Context owner; + private final PlayerOptionalContext viewer; + private TagResolver[] tagResolvers; + + public ViewerContext(Context owner, PlayerOptionalContext viewer) { + this.owner = owner; + this.viewer = viewer; + } + + public static ViewerContext of(Context owner, PlayerOptionalContext viewer) { + return new ViewerContext(owner, viewer); + } + + @Override + public Optional getViewerOptionalParameter(ContextKey parameter) { + return this.viewer.getOptionalParameter(parameter); + } + + @Override + public ContextHolder viewerContexts() { + return this.viewer.contexts(); + } + + @Override + public T getViewerParameterOrThrow(ContextKey parameter) { + return this.viewer.getParameterOrThrow(parameter); + } + + @Override + public ContextHolder contexts() { + return this.owner.contexts(); + } + + @Override + public Optional getOptionalParameter(ContextKey parameter) { + return this.owner.getOptionalParameter(parameter); + } + + @Override + public T getParameterOrThrow(ContextKey parameter) { + return this.owner.getParameterOrThrow(parameter); + } + + @Override + public TagResolver[] tagResolvers() { + if (this.tagResolvers == null) { + Player optionalOwner = null; + if (this.owner instanceof PlayerOptionalContext context) { + optionalOwner = context.player(); + } + this.tagResolvers = new TagResolver[]{ShiftTag.INSTANCE, ImageTag.INSTANCE, + new PlaceholderTag(optionalOwner), new ViewerPlaceholderTag(this.viewer.player()), + new NamedArgumentTag(this.owner), new ViewerNamedArgumentTag(this.viewer), + new I18NTag(this), new ExpressionTag(this)}; + } + return this.tagResolvers; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/AllOfCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/AllOfCondition.java new file mode 100644 index 000000000..c89b52606 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/AllOfCondition.java @@ -0,0 +1,64 @@ +package net.momirealms.craftengine.core.plugin.context.condition; + +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.MiscUtils; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +public class AllOfCondition implements Condition { + protected final List> conditions; + + public AllOfCondition(List> conditions) { + this.conditions = conditions; + } + + @Override + public boolean test(CTX ctx) { + for (Condition condition : conditions) { + if (!condition.test(ctx)) { + return false; + } + } + return true; + } + + @Override + public Key type() { + return CommonConditions.ALL_OF; + } + + public static class FactoryImpl implements ConditionFactory { + private final Function, Condition> factory; + + public FactoryImpl(Function, Condition> factory) { + this.factory = factory; + } + + @SuppressWarnings("unchecked") + @Override + public Condition create(Map arguments) { + Object termsArg = ResourceConfigUtils.requireNonNullOrThrow( + ResourceConfigUtils.get(arguments, "terms", "term"), + "warning.config.condition.all_of.missing_terms" + ); + if (termsArg instanceof Map map) { + return new AllOfCondition<>(List.of(factory.apply(MiscUtils.castToMap(map, false)))); + } else if (termsArg instanceof List list) { + List> conditions = new ArrayList<>(); + for (Map term : (List>) list) { + conditions.add(factory.apply(term)); + } + return new AllOfCondition<>(conditions); + } else { + throw new LocalizedResourceConfigException("warning.config.condition.all_of.invalid_terms_type", termsArg.getClass().getSimpleName()); + } + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/AnyOfCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/AnyOfCondition.java new file mode 100644 index 000000000..4151e9870 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/AnyOfCondition.java @@ -0,0 +1,64 @@ +package net.momirealms.craftengine.core.plugin.context.condition; + +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.MiscUtils; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +public class AnyOfCondition implements Condition { + protected final List> conditions; + + public AnyOfCondition(List> conditions) { + this.conditions = conditions; + } + + @Override + public boolean test(CTX ctx) { + for (Condition condition : conditions) { + if (condition.test(ctx)) { + return true; + } + } + return false; + } + + @Override + public Key type() { + return CommonConditions.ANY_OF; + } + + public static class FactoryImpl implements ConditionFactory { + private final Function, Condition> factory; + + public FactoryImpl(Function, Condition> factory) { + this.factory = factory; + } + + @SuppressWarnings("unchecked") + @Override + public Condition create(Map arguments) { + Object termsArg = ResourceConfigUtils.requireNonNullOrThrow( + ResourceConfigUtils.get(arguments, "terms", "term"), + "warning.config.condition.any_of.missing_terms" + ); + if (termsArg instanceof Map map) { + return new AnyOfCondition<>(List.of(factory.apply(MiscUtils.castToMap(map, false)))); + } else if (termsArg instanceof List list) { + List> conditions = new ArrayList<>(); + for (Map term : (List>) list) { + conditions.add(factory.apply(term)); + } + return new AnyOfCondition<>(conditions); + } else { + throw new LocalizedResourceConfigException("warning.config.condition.any_of.invalid_terms_type", termsArg.getClass().getSimpleName()); + } + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/CommonConditions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/CommonConditions.java new file mode 100644 index 000000000..1607f8013 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/CommonConditions.java @@ -0,0 +1,20 @@ +package net.momirealms.craftengine.core.plugin.context.condition; + +import net.momirealms.craftengine.core.util.Key; + +public final class CommonConditions { + private CommonConditions() {} + + public static final Key EMPTY = Key.of("craftengine:empty"); + public static final Key ALL_OF = Key.of("craftengine:all_of"); + public static final Key ANY_OF = Key.of("craftengine:any_of"); + public static final Key INVERTED = Key.of("craftengine:inverted"); + public static final Key MATCH_ITEM = Key.of("craftengine:match_item"); + public static final Key MATCH_BLOCK_PROPERTY = Key.from("craftengine:match_block_property"); + public static final Key TABLE_BONUS = Key.from("craftengine:table_bonus"); + public static final Key SURVIVES_EXPLOSION = Key.from("craftengine:survives_explosion"); + public static final Key RANDOM = Key.from("craftengine:random"); + public static final Key ENCHANTMENT = Key.from("craftengine:enchantment"); + public static final Key FALLING_BLOCK = Key.from("craftengine:falling_block"); + public static final Key DISTANCE = Key.from("craftengine:distance"); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/ConditionFactory.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/ConditionFactory.java new file mode 100644 index 000000000..06e595886 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/ConditionFactory.java @@ -0,0 +1,11 @@ +package net.momirealms.craftengine.core.plugin.context.condition; + +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.Context; + +import java.util.Map; + +public interface ConditionFactory { + + Condition create(Map args); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/DistanceCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/DistanceCondition.java new file mode 100644 index 000000000..52e22d6a6 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/DistanceCondition.java @@ -0,0 +1,65 @@ +package net.momirealms.craftengine.core.plugin.context.condition; + +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; +import net.momirealms.craftengine.core.plugin.context.number.NumberProviders; +import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.world.Vec3d; +import net.momirealms.craftengine.core.world.World; + +import java.util.Map; +import java.util.Optional; + +// TODO It's designed for players for the moment, better using entities +public class DistanceCondition implements Condition { + private final NumberProvider min; + private final NumberProvider max; + + public DistanceCondition(NumberProvider min, NumberProvider max) { + this.max = max; + this.min = min; + } + + @Override + public Key type() { + return CommonConditions.DISTANCE; + } + + @Override + public boolean test(CTX ctx) { + float min = this.min.getFloat(ctx); + float max = this.max.getFloat(ctx); + Optional optionalPlayer = ctx.getOptionalParameter(CommonParameters.PLAYER); + World world = ctx.getParameterOrThrow(CommonParameters.WORLD); + Vec3d location = ctx.getParameterOrThrow(CommonParameters.LOCATION); + if (optionalPlayer.isEmpty()) { + return false; + } + Player player = optionalPlayer.get(); + if (!player.world().uuid().equals(world.uuid())) { + return false; + } + + double dx = location.x() - player.x(); + double dy = location.y() - player.y(); + double dz = location.z() - player.z(); + double distanceSquared = dx * dx + dy * dy + dz * dz; + double minSquared = min * min; + double maxSquared = max * max; + + return distanceSquared >= minSquared && distanceSquared <= maxSquared; + } + + public static class FactoryImpl implements ConditionFactory { + + @Override + public Condition create(Map arguments) { + NumberProvider min = NumberProviders.fromObject(arguments.getOrDefault("min", 0)); + NumberProvider max = NumberProviders.fromObject(arguments.getOrDefault("max", 32)); + return new DistanceCondition<>(min, max); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/EmptyCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/EmptyCondition.java new file mode 100644 index 000000000..dda586d78 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/EmptyCondition.java @@ -0,0 +1,28 @@ +package net.momirealms.craftengine.core.plugin.context.condition; + +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.util.Key; + +import java.util.Map; + +public class EmptyCondition implements Condition { + + @Override + public Key type() { + return CommonConditions.EMPTY; + } + + @Override + public boolean test(CTX ctx) { + return true; + } + + public static class FactoryImpl implements ConditionFactory { + + @Override + public Condition create(Map arguments) { + return new EmptyCondition<>(); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/EnchantmentCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/EnchantmentCondition.java new file mode 100644 index 000000000..3523c9ae4 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/EnchantmentCondition.java @@ -0,0 +1,64 @@ +package net.momirealms.craftengine.core.plugin.context.condition; + +import net.momirealms.craftengine.core.item.Enchantment; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.context.parameter.PlayerParameters; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; + +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; + +public class EnchantmentCondition implements Condition { + private final Key id; + private final Function expression; + + public EnchantmentCondition(Key id, Function expression) { + this.expression = expression; + this.id = id; + } + + @Override + public Key type() { + return CommonConditions.ENCHANTMENT; + } + + @Override + public boolean test(CTX ctx) { + Optional> item = ctx.getOptionalParameter(PlayerParameters.MAIN_HAND_ITEM); + if (item.isEmpty()) return false; + Optional enchantment = item.get().getEnchantment(id); + int level = enchantment.map(Enchantment::level).orElse(0); + return this.expression.apply(level); + } + + public static class FactoryImpl implements ConditionFactory { + + @Override + public Condition create(Map arguments) { + String predicate = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("predicate"), "warning.config.condition.enchantment.missing_predicate"); + String[] split = predicate.split("(<=|>=|<|>|==|=)", 2); + int level; + try { + level = Integer.parseInt(split[1]); + } catch (NumberFormatException e) { + throw new LocalizedResourceConfigException("warning.config.condition.enchantment.invalid_predicate", e, predicate); + } + String operator = predicate.substring(split[0].length(), predicate.length() - split[1].length()); + Function expression; + switch (operator) { + case "<" -> expression = (i -> i < level); + case ">" -> expression = (i -> i > level); + case "==", "=" -> expression = (i -> i == level); + case "<=" -> expression = (i -> i <= level); + case ">=" -> expression = (i -> i >= level); + default -> throw new LocalizedResourceConfigException("warning.config.condition.enchantment.invalid_predicate", predicate); + } + return new EnchantmentCondition<>(Key.of(split[0]), expression); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/FallingBlockCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/FallingBlockCondition.java new file mode 100644 index 000000000..1ab5a31b2 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/FallingBlockCondition.java @@ -0,0 +1,29 @@ +package net.momirealms.craftengine.core.plugin.context.condition; + +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; +import net.momirealms.craftengine.core.util.Key; + +import java.util.Map; + +public class FallingBlockCondition implements Condition { + + @Override + public Key type() { + return CommonConditions.FALLING_BLOCK; + } + + @Override + public boolean test(CTX ctx) { + return ctx.getOptionalParameter(CommonParameters.FALLING_BLOCK).orElse(false); + } + + public static class FactoryImpl implements ConditionFactory { + + @Override + public Condition create(Map arguments) { + return new FallingBlockCondition<>(); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/InvertedCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/InvertedCondition.java new file mode 100644 index 000000000..059339456 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/InvertedCondition.java @@ -0,0 +1,59 @@ +package net.momirealms.craftengine.core.plugin.context.condition; + +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.MiscUtils; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +public class InvertedCondition implements Condition { + protected final Condition condition; + + public InvertedCondition(Condition condition) { + this.condition = condition; + } + + @Override + public boolean test(CTX ctx) { + return !this.condition.test(ctx); + } + + @Override + public Key type() { + return CommonConditions.INVERTED; + } + + public static class FactoryImpl implements ConditionFactory { + private final Function, Condition> factory; + + public FactoryImpl(Function, Condition> factory) { + this.factory = factory; + } + + @SuppressWarnings("unchecked") + @Override + public Condition create(Map arguments) { + Object termObj = ResourceConfigUtils.requireNonNullOrThrow( + ResourceConfigUtils.get(arguments, "term", "terms"), + "warning.config.condition.inverted.missing_term" + ); + if (termObj instanceof Map map) { + return new InvertedCondition<>(this.factory.apply(MiscUtils.castToMap(map, false))); + } else if (termObj instanceof List list) { + List> conditions = new ArrayList<>(); + for (Map term : (List>) list) { + conditions.add(factory.apply(term)); + } + return new InvertedCondition<>(new AllOfCondition<>(conditions)); + } else { + throw new LocalizedResourceConfigException("warning.config.condition.inverted.invalid_term_type", termObj.getClass().getSimpleName()); + } + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/condition/MatchBlockPropertyCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/MatchBlockPropertyCondition.java similarity index 52% rename from core/src/main/java/net/momirealms/craftengine/core/loot/condition/MatchBlockPropertyCondition.java rename to core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/MatchBlockPropertyCondition.java index 24c91cd6e..d33b75f8e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/condition/MatchBlockPropertyCondition.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/MatchBlockPropertyCondition.java @@ -1,19 +1,21 @@ -package net.momirealms.craftengine.core.loot.condition; +package net.momirealms.craftengine.core.plugin.context.condition; import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.properties.Property; -import net.momirealms.craftengine.core.loot.LootContext; -import net.momirealms.craftengine.core.loot.parameter.LootParameters; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.Pair; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.Map; -public class MatchBlockPropertyCondition implements LootCondition { - public static final Factory FACTORY = new Factory(); +public class MatchBlockPropertyCondition implements Condition { private final List> properties; public MatchBlockPropertyCondition(List> properties) { @@ -22,12 +24,12 @@ public class MatchBlockPropertyCondition implements LootCondition { @Override public Key type() { - return LootConditions.MATCH_BLOCK_PROPERTY; + return CommonConditions.MATCH_BLOCK_PROPERTY; } @Override - public boolean test(LootContext lootContext) { - return lootContext.getOptionalParameter(LootParameters.BLOCK_STATE).map(state -> { + public boolean test(CTX ctx) { + return ctx.getOptionalParameter(CommonParameters.BLOCK_STATE).map(state -> { CustomBlock block = state.owner().value(); for (Pair property : this.properties) { Property propertyIns = block.getProperty(property.left()); @@ -42,20 +44,16 @@ public class MatchBlockPropertyCondition implements LootCondition { }).orElse(false); } - public static class Factory implements LootConditionFactory { + public static class FactoryImpl implements ConditionFactory { - @SuppressWarnings("unchecked") @Override - public LootCondition create(Map arguments) { - Map properties = (Map) arguments.get("properties"); - if (properties == null) { - throw new IllegalArgumentException("Missing 'properties' argument for 'match_block_property'"); - } + public Condition create(Map arguments) { + Object propertyObj = ResourceConfigUtils.requireNonNullOrThrow(arguments.get("properties"), "warning.config.condition.match_block_property.missing_properties"); List> propertyList = new ArrayList<>(); - for (Map.Entry entry : properties.entrySet()) { + for (Map.Entry entry : MiscUtils.castToMap(propertyObj, false).entrySet()) { propertyList.add(new Pair<>(entry.getKey(), entry.getValue().toString())); } - return new MatchBlockPropertyCondition(propertyList); + return new MatchBlockPropertyCondition<>(propertyList); } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/condition/MatchItemCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/MatchItemCondition.java similarity index 51% rename from core/src/main/java/net/momirealms/craftengine/core/loot/condition/MatchItemCondition.java rename to core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/MatchItemCondition.java index 367ac6ec3..09951996a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/condition/MatchItemCondition.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/MatchItemCondition.java @@ -1,15 +1,16 @@ -package net.momirealms.craftengine.core.loot.condition; +package net.momirealms.craftengine.core.plugin.context.condition; import net.momirealms.craftengine.core.item.Item; -import net.momirealms.craftengine.core.loot.LootContext; -import net.momirealms.craftengine.core.loot.parameter.LootParameters; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.context.parameter.PlayerParameters; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; import java.util.*; -public class MatchItemCondition implements LootCondition { - public static final Factory FACTORY = new Factory(); +public class MatchItemCondition implements Condition { private final Set ids; private final boolean regexMatch; @@ -20,12 +21,12 @@ public class MatchItemCondition implements LootCondition { @Override public Key type() { - return LootConditions.MATCH_ITEM; + return CommonConditions.MATCH_ITEM; } @Override - public boolean test(LootContext lootContext) { - Optional> item = lootContext.getOptionalParameter(LootParameters.TOOL); + public boolean test(CTX ctx) { + Optional> item = ctx.getOptionalParameter(PlayerParameters.MAIN_HAND_ITEM); if (item.isEmpty()) return false; Key key = item.get().id(); String itemId = key.toString(); @@ -41,12 +42,16 @@ public class MatchItemCondition implements LootCondition { return false; } - public static class Factory implements LootConditionFactory { + public static class FactoryImpl implements ConditionFactory { + @Override - public LootCondition create(Map arguments) { + public Condition create(Map arguments) { List ids = MiscUtils.getAsStringList(arguments.get("id")); + if (ids.isEmpty()) { + throw new LocalizedResourceConfigException("warning.config.condition.match_item.missing_id"); + } boolean regex = (boolean) arguments.getOrDefault("regex", false); - return new MatchItemCondition(ids, regex); + return new MatchItemCondition<>(ids, regex); } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/RandomCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/RandomCondition.java new file mode 100644 index 000000000..a855b84f9 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/RandomCondition.java @@ -0,0 +1,51 @@ +package net.momirealms.craftengine.core.plugin.context.condition; + +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; +import net.momirealms.craftengine.core.plugin.context.number.NumberProviders; +import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.RandomUtils; + +import java.util.Map; +import java.util.Optional; + +public class RandomCondition implements Condition { + private final NumberProvider chance; + private final boolean previous; + + public RandomCondition(NumberProvider chance, boolean previous) { + this.chance = chance; + this.previous = previous; + } + + @Override + public Key type() { + return CommonConditions.RANDOM; + } + + @Override + public boolean test(CTX ctx) { + if (this.previous) { + // TODO This might produce bugs if the context doesn't use a common provider + Optional random = ctx.getOptionalParameter(CommonParameters.LAST_RANDOM); + return random.map(d -> d < this.chance.getFloat(ctx)) + .orElseGet(() -> RandomUtils.generateRandomFloat(0, 1) < this.chance.getFloat(ctx)); + } else { + Optional random = ctx.getOptionalParameter(CommonParameters.RANDOM); + return random.map(d -> d < this.chance.getFloat(ctx)) + .orElseGet(() -> RandomUtils.generateRandomFloat(0, 1) < this.chance.getFloat(ctx)); + } + } + + public static class FactoryImpl implements ConditionFactory { + + @Override + public Condition create(Map arguments) { + NumberProvider provider = NumberProviders.fromObject(arguments.getOrDefault("value", 0.5f)); + boolean useLastRandom = Boolean.parseBoolean(arguments.getOrDefault("use-last", "false").toString()); + return new RandomCondition<>(provider, useLastRandom); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/SurvivesExplosionCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/SurvivesExplosionCondition.java new file mode 100644 index 000000000..385bb708f --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/SurvivesExplosionCondition.java @@ -0,0 +1,36 @@ +package net.momirealms.craftengine.core.plugin.context.condition; + +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.RandomUtils; + +import java.util.Map; +import java.util.Optional; + +public class SurvivesExplosionCondition implements Condition { + + @Override + public Key type() { + return CommonConditions.SURVIVES_EXPLOSION; + } + + @Override + public boolean test(CTX ctx) { + Optional radius = ctx.getOptionalParameter(CommonParameters.EXPLOSION_RADIUS); + if (radius.isPresent()) { + float f = 1f / radius.get(); + return RandomUtils.generateRandomFloat(0, 1) < f; + } + return true; + } + + public static class FactoryImpl implements ConditionFactory { + + @Override + public Condition create(Map arguments) { + return new SurvivesExplosionCondition<>(); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/condition/TableBonusCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/TableBonusCondition.java similarity index 61% rename from core/src/main/java/net/momirealms/craftengine/core/loot/condition/TableBonusCondition.java rename to core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/TableBonusCondition.java index 125d5859d..fb0870344 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/condition/TableBonusCondition.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/TableBonusCondition.java @@ -1,11 +1,13 @@ -package net.momirealms.craftengine.core.loot.condition; +package net.momirealms.craftengine.core.plugin.context.condition; import net.momirealms.craftengine.core.item.Enchantment; import net.momirealms.craftengine.core.item.Item; -import net.momirealms.craftengine.core.loot.LootContext; -import net.momirealms.craftengine.core.loot.parameter.LootParameters; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.context.parameter.PlayerParameters; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.RandomUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import java.util.ArrayList; @@ -13,8 +15,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; -public class TableBonusCondition implements LootCondition { - public static final Factory FACTORY = new Factory(); +public class TableBonusCondition implements Condition { private final Key enchantmentType; private final List values; @@ -25,38 +26,39 @@ public class TableBonusCondition implements LootCondition { @Override public Key type() { - return LootConditions.TABLE_BONUS; + return CommonConditions.TABLE_BONUS; } @Override - public boolean test(LootContext lootContext) { - Optional> item = lootContext.getOptionalParameter(LootParameters.TOOL); + public boolean test(CTX ctx) { + Optional> item = ctx.getOptionalParameter(PlayerParameters.MAIN_HAND_ITEM); int level = item.map(value -> value.getEnchantment(this.enchantmentType).map(Enchantment::level).orElse(0)).orElse(0); float f = this.values.get(Math.min(level, this.values.size() - 1)); - return lootContext.randomSource().nextFloat() < f; + return RandomUtils.generateRandomFloat(0, 1) < f; } - public static class Factory implements LootConditionFactory { + public static class FactoryImpl implements ConditionFactory { + @Override - public LootCondition create(Map arguments) { + public Condition create(Map arguments) { Object enchantmentObj = arguments.get("enchantment"); if (enchantmentObj == null) { - throw new LocalizedResourceConfigException("warning.config.loot_table.condition.table_bonus.missing_enchantment"); + throw new LocalizedResourceConfigException("warning.config.condition.table_bonus.missing_enchantment"); } Key enchantmentType = Key.of(enchantmentObj.toString()); Object chances = arguments.get("chances"); if (chances != null) { if (chances instanceof Number number) { - return new TableBonusCondition(enchantmentType, List.of(number.floatValue())); + return new TableBonusCondition<>(enchantmentType, List.of(number.floatValue())); } else if (chances instanceof List list) { List values = new ArrayList<>(list.size()); for (Object o : list) { values.add(ResourceConfigUtils.getAsFloat(o, "chances")); } - return new TableBonusCondition(enchantmentType, values); + return new TableBonusCondition<>(enchantmentType, values); } } - throw new LocalizedResourceConfigException("warning.config.loot_table.condition.table_bonus.missing_chances"); + throw new LocalizedResourceConfigException("warning.config.condition.table_bonus.missing_chances"); } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/AbstractConditionalFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/AbstractConditionalFunction.java new file mode 100644 index 000000000..25d56a813 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/AbstractConditionalFunction.java @@ -0,0 +1,55 @@ +package net.momirealms.craftengine.core.plugin.context.function; + +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.util.Factory; +import net.momirealms.craftengine.core.util.MCUtils; +import net.momirealms.craftengine.core.util.MiscUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; + +// TODO 将loot functions迁移过来 +public abstract class AbstractConditionalFunction implements Function { + protected final List> predicates; + private final Predicate compositePredicates; + + public AbstractConditionalFunction(List> predicates) { + this.predicates = predicates; + this.compositePredicates = MCUtils.allOf(predicates); + } + + @Override + public void run(CTX ctx) { + if (this.compositePredicates.test(ctx)) { + this.runInternal(ctx); + } + } + + protected abstract void runInternal(CTX ctx); + + public static abstract class AbstractFactory implements Factory> { + private final java.util.function.Function, Condition> factory; + + public AbstractFactory(java.util.function.Function, Condition> factory) { + this.factory = factory; + } + + protected List> getPredicates(Map arguments) { + Object predicates = arguments.get("conditions"); + if (predicates == null) return List.of(); + if (predicates instanceof List list) { + List> conditions = new ArrayList<>(list.size()); + for (Object o : list) { + conditions.add(factory.apply(MiscUtils.castToMap(o, false))); + } + return conditions; + } else if (predicates instanceof Map map) { + return List.of(factory.apply(MiscUtils.castToMap(map, false))); + } + throw new IllegalArgumentException("Unsupported condition type: " + predicates.getClass().getSimpleName()); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommandFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommandFunction.java new file mode 100644 index 000000000..a6dd5254d --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommandFunction.java @@ -0,0 +1,78 @@ +package net.momirealms.craftengine.core.plugin.context.function; + +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.Platform; +import net.momirealms.craftengine.core.plugin.context.*; +import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; +import net.momirealms.craftengine.core.plugin.context.selector.PlayerSelector; +import net.momirealms.craftengine.core.plugin.context.selector.PlayerSelectors; +import net.momirealms.craftengine.core.plugin.context.text.TextProvider; +import net.momirealms.craftengine.core.plugin.context.text.TextProviders; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.MiscUtils; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; + +import javax.annotation.Nullable; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class CommandFunction extends AbstractConditionalFunction { + private final List command; + private final boolean asPlayer; + private final PlayerSelector selector; + + public CommandFunction(List> predicates, List command, boolean asPlayer, @Nullable PlayerSelector selector) { + super(predicates); + this.asPlayer = asPlayer; + this.command = command; + this.selector = selector; + } + + @Override + public void runInternal(CTX ctx) { + if (this.asPlayer) { + Optional owner = ctx.getOptionalParameter(CommonParameters.PLAYER); + if (this.selector == null) { + owner.ifPresent(it -> { + for (TextProvider c : this.command) { + it.performCommand(c.get(ctx)); + } + }); + } else { + for (Player viewer : this.selector.get(ctx)) { + RelationalContext relationalContext = ViewerContext.of(ctx, PlayerOptionalContext.of(viewer, ContextHolder.EMPTY)); + for (TextProvider c : this.command) { + viewer.performCommand(c.get(relationalContext)); + } + } + } + } else { + Platform platform = CraftEngine.instance().platform(); + for (TextProvider c : this.command) { + platform.dispatchCommand(c.get(ctx)); + } + } + } + + @Override + public Key type() { + return CommonFunctions.COMMAND; + } + + public static class FactoryImpl extends AbstractFactory { + + public FactoryImpl(java.util.function.Function, Condition> factory) { + super(factory); + } + + @Override + public Function create(Map arguments) { + Object command = ResourceConfigUtils.requireNonNullOrThrow(ResourceConfigUtils.get(arguments, "command", "commands"), "warning.config.function.command.missing_command"); + List commands = MiscUtils.getAsStringList(command).stream().map(TextProviders::fromString).toList(); + boolean asPlayer = (boolean) arguments.getOrDefault("as-player", false); + return new CommandFunction<>(getPredicates(arguments), commands, asPlayer, PlayerSelectors.fromObject(arguments.get("target"))); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java new file mode 100644 index 000000000..574ad1ba0 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java @@ -0,0 +1,8 @@ +package net.momirealms.craftengine.core.plugin.context.function; + +import net.momirealms.craftengine.core.util.Key; + +public class CommonFunctions { + public static final Key COMMAND = Key.of("craftengine:command"); + +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/Function.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/Function.java new file mode 100644 index 000000000..968feb369 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/Function.java @@ -0,0 +1,11 @@ +package net.momirealms.craftengine.core.plugin.context.function; + +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.util.Key; + +public interface Function { + + void run(CTX ctx); + + Key type(); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/ExpressionNumberProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/ExpressionNumberProvider.java new file mode 100644 index 000000000..21c2ccabf --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/ExpressionNumberProvider.java @@ -0,0 +1,52 @@ +package net.momirealms.craftengine.core.plugin.context.number; + +import com.ezylang.evalex.EvaluationException; +import com.ezylang.evalex.Expression; +import com.ezylang.evalex.parser.ParseException; +import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.util.AdventureHelper; +import net.momirealms.craftengine.core.util.Factory; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; + +import java.util.Map; + +public class ExpressionNumberProvider implements NumberProvider { + public static final FactoryImpl FACTORY = new FactoryImpl(); + private final String expr; + + public ExpressionNumberProvider(String expr) { + this.expr = expr; + } + + @Override + public float getFloat(Context context) { + Component resultComponent = AdventureHelper.customMiniMessage().deserialize(this.expr, context.tagResolvers()); + String resultString = AdventureHelper.plainTextContent(resultComponent); + Expression expression = new Expression(resultString); + try { + return expression.evaluate().getNumberValue().floatValue(); + } catch (EvaluationException | ParseException e) { + throw new RuntimeException("Invalid expression: " + this.expr + " -> " + resultString + " -> Cannot parse", e); + } + } + + @Override + public Key type() { + return NumberProviders.EXPRESSION; + } + + public String expression() { + return this.expr; + } + + public static class FactoryImpl implements Factory { + + @Override + public NumberProvider create(Map arguments) { + String value = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("expression"), "warning.config.number.expression.missing_expression"); + return new ExpressionNumberProvider(value); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/FixedNumberProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/FixedNumberProvider.java new file mode 100644 index 000000000..cfbd165f9 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/FixedNumberProvider.java @@ -0,0 +1,48 @@ +package net.momirealms.craftengine.core.plugin.context.number; + +import com.ezylang.evalex.Expression; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; +import net.momirealms.craftengine.core.util.Factory; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; + +import java.util.Map; + +public class FixedNumberProvider implements NumberProvider { + public static final FactoryImpl FACTORY = new FactoryImpl(); + private final float value; + + public FixedNumberProvider(float value) { + this.value = value; + } + + @Override + public float getFloat(Context context) { + return this.value; + } + + @Override + public Key type() { + return NumberProviders.FIXED; + } + + public static class FactoryImpl implements Factory { + + @Override + public NumberProvider create(Map arguments) { + String plainOrExpression = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("value"), "warning.config.number.fixed.missing_value"); + try { + float value = Float.parseFloat(plainOrExpression); + return new FixedNumberProvider(value); + } catch (NumberFormatException e) { + Expression expression = new Expression(plainOrExpression); + try { + return new FixedNumberProvider(expression.evaluate().getNumberValue().floatValue()); + } catch (Exception e1) { + throw new LocalizedResourceConfigException("warning.config.number.fixed.invalid_value", e1, plainOrExpression); + } + } + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/NumberProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/NumberProvider.java new file mode 100644 index 000000000..93cdd64a0 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/NumberProvider.java @@ -0,0 +1,15 @@ +package net.momirealms.craftengine.core.plugin.context.number; + +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.util.Key; + +public interface NumberProvider { + + float getFloat(Context context); + + default int getInt(Context context) { + return Math.round(this.getFloat(context)); + } + + Key type(); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/NumberProviders.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/NumberProviders.java new file mode 100644 index 000000000..5d5d609a4 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/NumberProviders.java @@ -0,0 +1,87 @@ +package net.momirealms.craftengine.core.plugin.context.number; + +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; +import net.momirealms.craftengine.core.registry.BuiltInRegistries; +import net.momirealms.craftengine.core.registry.Holder; +import net.momirealms.craftengine.core.registry.Registries; +import net.momirealms.craftengine.core.registry.WritableRegistry; +import net.momirealms.craftengine.core.util.Factory; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.core.util.ResourceKey; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class NumberProviders { + public static final Key FIXED = Key.of("craftengine:fixed"); + public static final Key CONSTANT = Key.of("craftengine:constant"); + public static final Key UNIFORM = Key.of("craftengine:uniform"); + public static final Key EXPRESSION = Key.of("craftengine:expression"); + + static { + register(FIXED, FixedNumberProvider.FACTORY); + register(CONSTANT, FixedNumberProvider.FACTORY); + register(UNIFORM, UniformNumberProvider.FACTORY); + register(EXPRESSION, ExpressionNumberProvider.FACTORY); + } + + public static void register(Key key, Factory factory) { + Holder.Reference> holder = ((WritableRegistry>) BuiltInRegistries.NUMBER_PROVIDER_FACTORY) + .registerForHolder(new ResourceKey<>(Registries.NUMBER_PROVIDER_FACTORY.location(), key)); + holder.bindValue(factory); + } + + public static List fromMapList(List> mapList) { + if (mapList == null || mapList.isEmpty()) return List.of(); + List functions = new ArrayList<>(); + for (Map map : mapList) { + functions.add(fromMap(map)); + } + return functions; + } + + public static NumberProvider fromMap(Map map) { + String type = ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("type"), "warning.config.number.missing_type"); + Key key = Key.withDefaultNamespace(type, Key.DEFAULT_NAMESPACE); + Factory factory = BuiltInRegistries.NUMBER_PROVIDER_FACTORY.getValue(key); + if (factory == null) { + throw new LocalizedResourceConfigException("warning.config.number.invalid_type", type); + } + return factory.create(map); + } + + @SuppressWarnings("unchecked") + public static NumberProvider fromObject(Object object) { + if (object == null) { + throw new LocalizedResourceConfigException("warning.config.number.missing_argument"); + } + if (object instanceof Number number) { + return new FixedNumberProvider(number.floatValue()); + } else if (object instanceof Map map) { + return fromMap((Map) map); + } else { + String string = object.toString(); + if (string.contains("~")) { + int first = string.indexOf('~'); + int second = string.indexOf('~', first + 1); + if (second == -1) { + NumberProvider min = fromObject(string.substring(0, first)); + NumberProvider max = fromObject(string.substring(first + 1)); + return new UniformNumberProvider(min, max); + } else { + throw new LocalizedResourceConfigException("warning.config.number.invalid_format", string); + } + } else if (string.contains("<") && string.contains(">") && string.contains(":")) { + return new ExpressionNumberProvider(string); + } else { + try { + return new FixedNumberProvider(Float.parseFloat(string)); + } catch (NumberFormatException e) { + throw new LocalizedResourceConfigException("warning.config.number.invalid_format", e, string); + } + } + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/UniformNumberProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/UniformNumberProvider.java new file mode 100644 index 000000000..38cbf80ae --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/UniformNumberProvider.java @@ -0,0 +1,53 @@ +package net.momirealms.craftengine.core.plugin.context.number; + +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.util.Factory; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.RandomUtils; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; + +import java.util.Map; + +public class UniformNumberProvider implements NumberProvider { + public static final FactoryImpl FACTORY = new FactoryImpl(); + private final NumberProvider min; + private final NumberProvider max; + + public UniformNumberProvider(NumberProvider min, NumberProvider max) { + this.min = min; + this.max = max; + } + + public NumberProvider max() { + return max; + } + + public NumberProvider min() { + return min; + } + + @Override + public int getInt(Context context) { + return RandomUtils.generateRandomInt(this.min.getInt(context), this.max.getInt(context) + 1); + } + + @Override + public float getFloat(Context context) { + return RandomUtils.generateRandomFloat(this.min.getFloat(context), this.max.getFloat(context)); + } + + @Override + public Key type() { + return NumberProviders.UNIFORM; + } + + public static class FactoryImpl implements Factory { + + @Override + public NumberProvider create(Map arguments) { + Object min = ResourceConfigUtils.requireNonNullOrThrow(arguments.get("min"), "warning.config.number.uniform.missing_min"); + Object max = ResourceConfigUtils.requireNonNullOrThrow(arguments.get("max"), "warning.config.number.uniform.missing_max"); + return new UniformNumberProvider(NumberProviders.fromObject(min), NumberProviders.fromObject(max)); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/BlockParameterProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/BlockParameterProvider.java new file mode 100644 index 000000000..50107633d --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/BlockParameterProvider.java @@ -0,0 +1,39 @@ +package net.momirealms.craftengine.core.plugin.context.parameter; + +import net.momirealms.craftengine.core.plugin.context.ContextKey; +import net.momirealms.craftengine.core.plugin.context.LazyContextParameterProvider; +import net.momirealms.craftengine.core.world.BlockInWorld; +import org.jetbrains.annotations.NotNull; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Function; + +public class BlockParameterProvider implements LazyContextParameterProvider { + private static final Map, Function> CONTEXT_FUNCTIONS = new HashMap<>(); + static { + CONTEXT_FUNCTIONS.put(BlockParameters.X, BlockInWorld::x); + CONTEXT_FUNCTIONS.put(BlockParameters.Y, BlockInWorld::y); + CONTEXT_FUNCTIONS.put(BlockParameters.Z, BlockInWorld::z); + CONTEXT_FUNCTIONS.put(BlockParameters.BLOCK_X, BlockInWorld::x); + CONTEXT_FUNCTIONS.put(BlockParameters.BLOCK_Y, BlockInWorld::y); + CONTEXT_FUNCTIONS.put(BlockParameters.BLOCK_Z, BlockInWorld::z); + CONTEXT_FUNCTIONS.put(BlockParameters.BLOCK_OWNER, BlockInWorld::owner); + CONTEXT_FUNCTIONS.put(BlockParameters.BLOCK_STATE, BlockInWorld::getAsString); + CONTEXT_FUNCTIONS.put(BlockParameters.WORLD_NAME, b -> b.world().name()); + } + + private final BlockInWorld block; + + public BlockParameterProvider(@NotNull BlockInWorld block) { + this.block = Objects.requireNonNull(block); + } + + @SuppressWarnings("unchecked") + @Override + public Optional getOptionalParameter(ContextKey parameter) { + return (Optional) Optional.ofNullable(CONTEXT_FUNCTIONS.get(parameter)).map(f -> f.apply(this.block)); + } +} \ No newline at end of file diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/BlockParameters.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/BlockParameters.java new file mode 100644 index 000000000..68d2988b8 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/BlockParameters.java @@ -0,0 +1,19 @@ +package net.momirealms.craftengine.core.plugin.context.parameter; + +import net.momirealms.craftengine.core.block.ImmutableBlockState; +import net.momirealms.craftengine.core.plugin.context.ContextKey; +import net.momirealms.craftengine.core.util.Key; + +public final class BlockParameters { + private BlockParameters() {} + + public static final ContextKey X = ContextKey.of("block.x"); + public static final ContextKey Y = ContextKey.of("block.y"); + public static final ContextKey Z = ContextKey.of("block.z"); + public static final ContextKey BLOCK_X = ContextKey.of("block.block_x"); + public static final ContextKey BLOCK_Y = ContextKey.of("block.block_y"); + public static final ContextKey BLOCK_Z = ContextKey.of("block.block_z"); + public static final ContextKey BLOCK_STATE = ContextKey.of("block.state"); + public static final ContextKey BLOCK_OWNER = ContextKey.of("block.owner.id"); + public static final ContextKey WORLD_NAME = ContextKey.of("block.world.name"); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/CommonParameterProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/CommonParameterProvider.java new file mode 100644 index 000000000..de5df90c1 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/CommonParameterProvider.java @@ -0,0 +1,34 @@ +package net.momirealms.craftengine.core.plugin.context.parameter; + +import net.momirealms.craftengine.core.plugin.context.ContextKey; +import net.momirealms.craftengine.core.plugin.context.LazyContextParameterProvider; +import net.momirealms.craftengine.core.util.RandomUtils; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; + +public class CommonParameterProvider implements LazyContextParameterProvider { + private double lastRandom = -1; + + private static final Map, Function> CONTEXT_FUNCTIONS = new HashMap<>(); + static { + CONTEXT_FUNCTIONS.put(CommonParameters.RANDOM, (f) -> { + f.lastRandom = RandomUtils.generateRandomDouble(0,1); + return f.lastRandom; + }); + CONTEXT_FUNCTIONS.put(CommonParameters.LAST_RANDOM, (f) -> { + if (f.lastRandom == -1) { + f.lastRandom = RandomUtils.generateRandomDouble(0, 1); + } + return f.lastRandom; + }); + } + + @SuppressWarnings("unchecked") + @Override + public Optional getOptionalParameter(ContextKey parameter) { + return (Optional) Optional.ofNullable(CONTEXT_FUNCTIONS.get(parameter)).map(f -> f.apply(this)); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/CommonParameters.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/CommonParameters.java new file mode 100644 index 000000000..e84c45315 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/CommonParameters.java @@ -0,0 +1,20 @@ +package net.momirealms.craftengine.core.plugin.context.parameter; + +import net.momirealms.craftengine.core.block.ImmutableBlockState; +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.plugin.context.ContextKey; +import net.momirealms.craftengine.core.world.Vec3d; +import net.momirealms.craftengine.core.world.World; + +public final class CommonParameters { + private CommonParameters() {} + + public static final ContextKey RANDOM = ContextKey.of("random"); + public static final ContextKey LAST_RANDOM = ContextKey.of("last_random"); + public static final ContextKey LOCATION = ContextKey.of("location"); + public static final ContextKey WORLD = ContextKey.of("world"); + public static final ContextKey FALLING_BLOCK = ContextKey.of("falling_block"); + public static final ContextKey EXPLOSION_RADIUS = ContextKey.of("explosion_radius"); + public static final ContextKey PLAYER = ContextKey.of("player"); + public static final ContextKey BLOCK_STATE = ContextKey.of("block_state"); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/PlayerParameterProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/PlayerParameterProvider.java new file mode 100644 index 000000000..c3a17484f --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/PlayerParameterProvider.java @@ -0,0 +1,45 @@ +package net.momirealms.craftengine.core.plugin.context.parameter; + +import net.momirealms.craftengine.core.entity.Entity; +import net.momirealms.craftengine.core.entity.player.InteractionHand; +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.plugin.context.ContextKey; +import net.momirealms.craftengine.core.plugin.context.LazyContextParameterProvider; +import net.momirealms.craftengine.core.util.MCUtils; +import org.jetbrains.annotations.NotNull; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Function; + +public class PlayerParameterProvider implements LazyContextParameterProvider { + private static final Map, Function> CONTEXT_FUNCTIONS = new HashMap<>(); + static { + CONTEXT_FUNCTIONS.put(PlayerParameters.X, Entity::x); + CONTEXT_FUNCTIONS.put(PlayerParameters.Y, Entity::y); + CONTEXT_FUNCTIONS.put(PlayerParameters.Z, Entity::z); + CONTEXT_FUNCTIONS.put(PlayerParameters.POS, Entity::position); + CONTEXT_FUNCTIONS.put(PlayerParameters.BLOCK_X, p -> MCUtils.fastFloor(p.x())); + CONTEXT_FUNCTIONS.put(PlayerParameters.BLOCK_Y, p -> MCUtils.fastFloor(p.y())); + CONTEXT_FUNCTIONS.put(PlayerParameters.BLOCK_Z, p -> MCUtils.fastFloor(p.z())); + CONTEXT_FUNCTIONS.put(PlayerParameters.NAME, Player::name); + CONTEXT_FUNCTIONS.put(PlayerParameters.UUID, Player::uuid); + CONTEXT_FUNCTIONS.put(PlayerParameters.WORLD_NAME, p -> p.world().name()); + CONTEXT_FUNCTIONS.put(PlayerParameters.MAIN_HAND_ITEM, p -> p.getItemInHand(InteractionHand.MAIN_HAND)); + CONTEXT_FUNCTIONS.put(PlayerParameters.OFF_HAND_ITEM, p -> p.getItemInHand(InteractionHand.OFF_HAND)); + } + + private final Player player; + + public PlayerParameterProvider(@NotNull Player player) { + this.player = Objects.requireNonNull(player); + } + + @SuppressWarnings("unchecked") + @Override + public Optional getOptionalParameter(ContextKey parameter) { + return (Optional) Optional.ofNullable(CONTEXT_FUNCTIONS.get(parameter)).map(f -> f.apply(this.player)); + } +} \ No newline at end of file diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/PlayerParameters.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/PlayerParameters.java new file mode 100644 index 000000000..4d558ba1b --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/PlayerParameters.java @@ -0,0 +1,24 @@ +package net.momirealms.craftengine.core.plugin.context.parameter; + +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.plugin.context.ContextKey; +import net.momirealms.craftengine.core.world.Vec3d; + +import java.util.UUID; + +public final class PlayerParameters { + private PlayerParameters() {} + + public static final ContextKey X = ContextKey.of("player.x"); + public static final ContextKey Y = ContextKey.of("player.y"); + public static final ContextKey Z = ContextKey.of("player.z"); + public static final ContextKey POS = ContextKey.of("player.pos"); + public static final ContextKey BLOCK_X = ContextKey.of("player.block_x"); + public static final ContextKey BLOCK_Y = ContextKey.of("player.block_y"); + public static final ContextKey BLOCK_Z = ContextKey.of("player.block_z"); + public static final ContextKey NAME = ContextKey.of("player.name"); + public static final ContextKey WORLD_NAME = ContextKey.of("player.world.name"); + public static final ContextKey UUID = ContextKey.of("player.uuid"); + public static final ContextKey> MAIN_HAND_ITEM = ContextKey.of("player.main_hand"); + public static final ContextKey> OFF_HAND_ITEM = ContextKey.of("player.off_hand"); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/AllPlayerSelector.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/AllPlayerSelector.java new file mode 100644 index 000000000..77e431e1a --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/AllPlayerSelector.java @@ -0,0 +1,58 @@ +package net.momirealms.craftengine.core.plugin.context.selector; + +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.context.ContextHolder; +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; +import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; +import net.momirealms.craftengine.core.util.Key; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class AllPlayerSelector implements PlayerSelector { + private final List> predicates; + + public AllPlayerSelector(List> predicates) { + this.predicates = predicates; + } + + public AllPlayerSelector() { + this.predicates = List.of(); + } + + public List> predicates() { + return predicates; + } + + @SuppressWarnings("unchecked") + @Override + public List get(CTX context) { + if (this.predicates.isEmpty()) { + return Arrays.asList(CraftEngine.instance().networkManager().onlineUsers()); + } else { + List players = new ArrayList<>(); + outer: for (Player player : CraftEngine.instance().networkManager().onlineUsers()) { + PlayerOptionalContext newContext = PlayerOptionalContext.of(player, ContextHolder.builder() + .withOptionalParameter(CommonParameters.WORLD, context.getOptionalParameter(CommonParameters.WORLD).orElse(null)) + .withOptionalParameter(CommonParameters.LOCATION, context.getOptionalParameter(CommonParameters.LOCATION).orElse(null)) + ); + for (Condition predicate : this.predicates) { + if (!predicate.test((CTX) newContext)) { + continue outer; + } + } + players.add(player); + } + return players; + } + } + + @Override + public Key type() { + return PlayerSelectors.ALL; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/PlayerSelector.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/PlayerSelector.java new file mode 100644 index 000000000..1c70278d2 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/PlayerSelector.java @@ -0,0 +1,14 @@ +package net.momirealms.craftengine.core.plugin.context.selector; + +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.util.Key; + +import java.util.List; + +public interface PlayerSelector { + + List get(CTX context); + + Key type(); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/PlayerSelectors.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/PlayerSelectors.java new file mode 100644 index 000000000..ae5010c81 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/PlayerSelectors.java @@ -0,0 +1,21 @@ +package net.momirealms.craftengine.core.plugin.context.selector; + +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.util.Key; + +public class PlayerSelectors { + public static final Key ALL = Key.of("craftengine:all"); + public static final Key SELF = Key.of("craftengine:self"); + + public static PlayerSelector fromObject(Object object) { + if (object == null) return null; + if (object instanceof String string) { + if (string.equals("self") || string.equals("@self") || string.equals("@s")) { + return new SelfPlayerSelector<>(); + } else if (string.equals("all") || string.equals("@all") || string.equals("@a")) { + return new AllPlayerSelector<>(); + } + } + throw new UnsupportedOperationException("Not supported yet."); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/SelfPlayerSelector.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/SelfPlayerSelector.java new file mode 100644 index 000000000..ea749f3ba --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/SelfPlayerSelector.java @@ -0,0 +1,21 @@ +package net.momirealms.craftengine.core.plugin.context.selector; + +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; +import net.momirealms.craftengine.core.util.Key; + +import java.util.List; + +public class SelfPlayerSelector implements PlayerSelector { + + @Override + public List get(CTX context) { + return List.of(context.getParameterOrThrow(CommonParameters.PLAYER)); + } + + @Override + public Key type() { + return PlayerSelectors.SELF; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/text/PlainTextProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/text/PlainTextProvider.java new file mode 100644 index 000000000..44f481026 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/text/PlainTextProvider.java @@ -0,0 +1,26 @@ +package net.momirealms.craftengine.core.plugin.context.text; + +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.util.Key; + +public class PlainTextProvider implements TextProvider { + private final String text; + + public PlainTextProvider(String text) { + this.text = text; + } + + public static PlainTextProvider of(String text) { + return new PlainTextProvider(text); + } + + @Override + public String get(Context context) { + return this.text; + } + + @Override + public Key type() { + return TextProviders.PLAIN; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/text/TagTextProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/text/TagTextProvider.java new file mode 100644 index 000000000..11c63ac21 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/text/TagTextProvider.java @@ -0,0 +1,29 @@ +package net.momirealms.craftengine.core.plugin.context.text; + +import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.util.AdventureHelper; +import net.momirealms.craftengine.core.util.Key; + +public class TagTextProvider implements TextProvider { + private final String text; + + public TagTextProvider(String text) { + this.text = text; + } + + public static TagTextProvider of(String text) { + return new TagTextProvider(text); + } + + @Override + public String get(Context context) { + Component resultComponent = AdventureHelper.customMiniMessage().deserialize(this.text, context.tagResolvers()); + return AdventureHelper.plainTextContent(resultComponent); + } + + @Override + public Key type() { + return TextProviders.TAG; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/text/TextProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/text/TextProvider.java new file mode 100644 index 000000000..5bd2b1950 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/text/TextProvider.java @@ -0,0 +1,11 @@ +package net.momirealms.craftengine.core.plugin.context.text; + +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.util.Key; + +public interface TextProvider { + + String get(Context context); + + Key type(); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/text/TextProviders.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/text/TextProviders.java new file mode 100644 index 000000000..b55de1e34 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/text/TextProviders.java @@ -0,0 +1,15 @@ +package net.momirealms.craftengine.core.plugin.context.text; + +import net.momirealms.craftengine.core.util.Key; + +public class TextProviders { + public static final Key PLAIN = Key.of("craftengine:plain"); + public static final Key TAG = Key.of("craftengine:tag"); + + public static TextProvider fromString(String string) { + if (!string.contains("<") || !string.contains(">")) { + return PlainTextProvider.of(string); + } + return TagTextProvider.of(string); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/dependency/Dependencies.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/dependency/Dependencies.java index 1859a2847..285430f15 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/dependency/Dependencies.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/dependency/Dependencies.java @@ -248,6 +248,14 @@ public class Dependencies { List.of(Relocation.of("jpountz", "net{}jpountz")) ); + public static final Dependency EVALEX = new Dependency( + "evalex", + "com{}ezylang", + "EvalEx", + "evalex", + List.of(Relocation.of("evalex", "com{}ezylang{}evalex")) + ); + public static final Dependency NETTY_HTTP = new Dependency( "netty-codec-http", "io{}netty", diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/event/BlockEventConditions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/event/BlockEventConditions.java new file mode 100644 index 000000000..5cb58ed8a --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/event/BlockEventConditions.java @@ -0,0 +1,33 @@ +package net.momirealms.craftengine.core.plugin.event; + +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.PlayerBlockActionContext; +import net.momirealms.craftengine.core.plugin.context.condition.InvertedCondition; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; +import net.momirealms.craftengine.core.registry.BuiltInRegistries; +import net.momirealms.craftengine.core.util.Factory; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; + +import java.util.Map; + +public class BlockEventConditions { + + public static Condition fromMap(Map map) { + String type = ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("type"), "warning.config.block.event.condition.missing_type"); + Key key = Key.withDefaultNamespace(type, Key.DEFAULT_NAMESPACE); + if (key.value().charAt(0) == '!') { + Factory> factory = BuiltInRegistries.PLAYER_BLOCK_CONDITION_FACTORY.getValue(new Key(key.namespace(), key.value().substring(1))); + if (factory == null) { + throw new LocalizedResourceConfigException("warning.config.block.event.condition.invalid_type", type); + } + return new InvertedCondition<>(factory.create(map)); + } else { + Factory> factory = BuiltInRegistries.PLAYER_BLOCK_CONDITION_FACTORY.getValue(key); + if (factory == null) { + throw new LocalizedResourceConfigException("warning.config.block.event.condition.invalid_type", type); + } + return factory.create(map); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/event/BlockEventFunctions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/event/BlockEventFunctions.java new file mode 100644 index 000000000..885e7fec2 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/event/BlockEventFunctions.java @@ -0,0 +1,40 @@ +package net.momirealms.craftengine.core.plugin.event; + +import net.momirealms.craftengine.core.plugin.context.PlayerBlockActionContext; +import net.momirealms.craftengine.core.plugin.context.function.CommandFunction; +import net.momirealms.craftengine.core.plugin.context.function.CommonFunctions; +import net.momirealms.craftengine.core.plugin.context.function.Function; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; +import net.momirealms.craftengine.core.registry.BuiltInRegistries; +import net.momirealms.craftengine.core.registry.Holder; +import net.momirealms.craftengine.core.registry.Registries; +import net.momirealms.craftengine.core.registry.WritableRegistry; +import net.momirealms.craftengine.core.util.Factory; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.core.util.ResourceKey; + +import java.util.Map; + +public class BlockEventFunctions { + + static { + register(CommonFunctions.COMMAND, new CommandFunction.FactoryImpl<>(BlockEventConditions::fromMap)); + } + + public static void register(Key key, Factory> factory) { + Holder.Reference>> holder = ((WritableRegistry>>) BuiltInRegistries.PLAYER_BLOCK_FUNCTION_FACTORY) + .registerForHolder(new ResourceKey<>(Registries.PLAYER_BLOCK_FUNCTION_FACTORY.location(), key)); + holder.bindValue(factory); + } + + public static Function fromMap(Map map) { + String type = ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("type"), "TODO I18N"); + Key key = Key.withDefaultNamespace(type, Key.DEFAULT_NAMESPACE); + Factory> factory = BuiltInRegistries.PLAYER_BLOCK_FUNCTION_FACTORY.getValue(key); + if (factory == null) { + throw new LocalizedResourceConfigException("TODO I18N", type); + } + return factory.create(map); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventTrigger.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventTrigger.java new file mode 100644 index 000000000..2ea3421eb --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventTrigger.java @@ -0,0 +1,8 @@ +package net.momirealms.craftengine.core.plugin.event; + +public enum EventTrigger { + USE_ITEM, + USE_ITEM_ON, + CONSUME, + +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/event/Trigger.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/event/Trigger.java deleted file mode 100644 index 4eb301457..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/event/Trigger.java +++ /dev/null @@ -1,15 +0,0 @@ -package net.momirealms.craftengine.core.plugin.event; - -import net.momirealms.craftengine.core.util.Key; - -public class Trigger { - private final Key id; - - public Trigger(Key id) { - this.id = id; - } - - public Key id() { - return id; - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/event/Triggers.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/event/Triggers.java deleted file mode 100644 index 474bf48a6..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/event/Triggers.java +++ /dev/null @@ -1,21 +0,0 @@ -package net.momirealms.craftengine.core.plugin.event; - -import net.momirealms.craftengine.core.util.Key; - -import java.util.HashMap; -import java.util.Map; - -public class Triggers { - public static final Map TRIGGERS = new HashMap<>(); - - public static final Trigger USE_ITEM = create(Key.of("use_item")); - public static final Trigger INTERACT = create(Key.of("interact")); - public static final Trigger CONSUME = create(Key.of("consume")); - public static final Trigger BREAK = create(Key.of("break")); - - private static Trigger create(Key id) { - Trigger trigger = new Trigger(id); - TRIGGERS.put(id, trigger); - return trigger; - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/GuiParameters.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/GuiParameters.java index 283b42f9a..946cbf505 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/GuiParameters.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/GuiParameters.java @@ -1,6 +1,6 @@ package net.momirealms.craftengine.core.plugin.gui; -import net.momirealms.craftengine.core.util.context.ContextKey; +import net.momirealms.craftengine.core.plugin.context.ContextKey; public class GuiParameters { public static final ContextKey MAX_PAGE = ContextKey.of("max_page"); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java index 6bed70f13..9d6f17d16 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java @@ -9,6 +9,8 @@ import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; +import net.momirealms.craftengine.core.plugin.context.ContextHolder; +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.gui.*; import net.momirealms.craftengine.core.plugin.gui.Ingredient; import net.momirealms.craftengine.core.registry.Holder; @@ -16,8 +18,6 @@ import net.momirealms.craftengine.core.util.AdventureHelper; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils; -import net.momirealms.craftengine.core.util.context.ContextHolder; -import net.momirealms.craftengine.core.util.context.PlayerContext; import java.nio.file.Path; import java.util.*; @@ -137,7 +137,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { .map(it -> it.buildItem(ItemBuildContext.of(player, ContextHolder.builder() .withParameter(GuiParameters.CURRENT_PAGE, String.valueOf(element.gui().currentPage())) .withParameter(GuiParameters.MAX_PAGE, String.valueOf(element.gui().maxPages())) - .build()))) + ))) .orElseThrow(() -> new GuiElementMissingException("Can't find gui element " + next)); }, true) ) @@ -147,7 +147,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { .map(it -> it.buildItem(ItemBuildContext.of(player, ContextHolder.builder() .withParameter(GuiParameters.CURRENT_PAGE, String.valueOf(element.gui().currentPage())) .withParameter(GuiParameters.MAX_PAGE, String.valueOf(element.gui().maxPages())) - .build()))) + ))) .orElseThrow(() -> new GuiElementMissingException("Can't find gui element " + previous)); }, false) ); @@ -177,7 +177,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { } }) .build() - .title(AdventureHelper.miniMessage().deserialize(Constants.BROWSER_TITLE, PlayerContext.of(player, ContextHolder.EMPTY).tagResolvers())) + .title(AdventureHelper.miniMessage().deserialize(Constants.BROWSER_TITLE, PlayerOptionalContext.of(player).tagResolvers())) .refresh() .open(player); } @@ -193,7 +193,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { ) .addIngredient('A', Ingredient.paged()) .addIngredient('=', GuiElement.constant(this.plugin.itemManager().getCustomItem(parentGui != null ? Constants.CATEGORY_BACK : Constants.CATEGORY_EXIT) - .map(it -> it.buildItem(ItemBuildContext.of(player, ContextHolder.EMPTY))) + .map(it -> it.buildItem(ItemBuildContext.of(player))) .orElseThrow(() -> new GuiElementMissingException("Can't find gui element " + (parentGui != null ? Constants.CATEGORY_BACK : Constants.CATEGORY_EXIT))), ((element, click) -> { click.cancel(); @@ -211,7 +211,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { .map(it -> it.buildItem(ItemBuildContext.of(player, ContextHolder.builder() .withParameter(GuiParameters.CURRENT_PAGE, String.valueOf(element.gui().currentPage())) .withParameter(GuiParameters.MAX_PAGE, String.valueOf(element.gui().maxPages())) - .build()))) + ))) .orElseThrow(() -> new GuiElementMissingException("Can't find gui element " + next)); }, true) ) @@ -221,7 +221,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { .map(it -> it.buildItem(ItemBuildContext.of(player, ContextHolder.builder() .withParameter(GuiParameters.CURRENT_PAGE, String.valueOf(element.gui().currentPage())) .withParameter(GuiParameters.MAX_PAGE, String.valueOf(element.gui().maxPages())) - .build()))) + ))) .orElseThrow(() -> new GuiElementMissingException("Can't find gui element " + previous)); }, false) ); @@ -292,7 +292,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { } }) .build() - .title(AdventureHelper.miniMessage().deserialize(Constants.CATEGORY_TITLE, PlayerContext.of(player, ContextHolder.EMPTY).tagResolvers())) + .title(AdventureHelper.miniMessage().deserialize(Constants.CATEGORY_TITLE, PlayerOptionalContext.of(player).tagResolvers())) .refresh() .open(player); } @@ -332,7 +332,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { } }) : GuiElement.EMPTY) .addIngredient('=', GuiElement.constant(this.plugin.itemManager().getCustomItem(parentGui != null ? Constants.RECIPE_BACK : Constants.RECIPE_EXIT) - .map(it -> it.buildItem(ItemBuildContext.of(player, ContextHolder.EMPTY))) + .map(it -> it.buildItem(ItemBuildContext.of(player))) .orElseThrow(() -> new GuiElementMissingException("Can't find gui element " + (parentGui != null ? Constants.RECIPE_BACK : Constants.RECIPE_EXIT))), ((element, click) -> { click.cancel(); @@ -353,7 +353,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { } }) .build() - .title(AdventureHelper.miniMessage().deserialize(Constants.RECIPE_NONE_TITLE, PlayerContext.of(player, ContextHolder.EMPTY).tagResolvers())) + .title(AdventureHelper.miniMessage().deserialize(Constants.RECIPE_NONE_TITLE, PlayerOptionalContext.of(player).tagResolvers())) .refresh() .open(player); } @@ -431,7 +431,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { } }) : GuiElement.EMPTY) .addIngredient('=', GuiElement.constant(this.plugin.itemManager().getCustomItem(parentGui != null ? Constants.RECIPE_BACK : Constants.RECIPE_EXIT) - .map(it -> it.buildItem(ItemBuildContext.of(player, ContextHolder.EMPTY))) + .map(it -> it.buildItem(ItemBuildContext.of(player))) .orElseThrow(() -> new GuiElementMissingException("Can't find gui element " + (parentGui != null ? Constants.RECIPE_BACK : Constants.RECIPE_EXIT))), ((element, click) -> { click.cancel(); @@ -448,7 +448,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { .map(it -> it.buildItem(ItemBuildContext.of(player, ContextHolder.builder() .withParameter(GuiParameters.CURRENT_PAGE, String.valueOf(index + 1)) .withParameter(GuiParameters.MAX_PAGE, String.valueOf(recipes.size())) - .build()))) + ))) .orElseThrow(() -> new GuiElementMissingException("Can't find gui element " + next)), (e, c) -> { c.cancel(); if (index + 1 < recipes.size()) { @@ -461,7 +461,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { .map(it -> it.buildItem(ItemBuildContext.of(player, ContextHolder.builder() .withParameter(GuiParameters.CURRENT_PAGE, String.valueOf(index + 1)) .withParameter(GuiParameters.MAX_PAGE, String.valueOf(recipes.size())) - .build()))) + ))) .orElseThrow(() -> new GuiElementMissingException("Can't find gui element " + previous)), (e, c) -> { c.cancel(); if (index > 0) { @@ -578,7 +578,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { } }) .build() - .title(AdventureHelper.miniMessage().deserialize(Constants.RECIPE_SMITHING_TRANSFORM_TITLE, PlayerContext.of(player, ContextHolder.EMPTY).tagResolvers())) + .title(AdventureHelper.miniMessage().deserialize(Constants.RECIPE_SMITHING_TRANSFORM_TITLE, PlayerOptionalContext.of(player).tagResolvers())) .refresh() .open(player); } @@ -664,7 +664,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { } })) .addIngredient('=', GuiElement.constant(this.plugin.itemManager().getCustomItem(parentGui != null ? Constants.RECIPE_BACK : Constants.RECIPE_EXIT) - .map(it -> it.buildItem(ItemBuildContext.of(player, ContextHolder.EMPTY))) + .map(it -> it.buildItem(ItemBuildContext.of(player))) .orElseThrow(() -> new GuiElementMissingException("Can't find gui element " + (parentGui != null ? Constants.RECIPE_BACK : Constants.RECIPE_EXIT))), ((element, click) -> { click.cancel(); @@ -681,7 +681,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { .map(it -> it.buildItem(ItemBuildContext.of(player, ContextHolder.builder() .withParameter(GuiParameters.CURRENT_PAGE, String.valueOf(index + 1)) .withParameter(GuiParameters.MAX_PAGE, String.valueOf(recipes.size())) - .build()))) + ))) .orElseThrow(() -> new GuiElementMissingException("Can't find gui element " + next)), (e, c) -> { c.cancel(); if (index + 1 < recipes.size()) { @@ -694,7 +694,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { .map(it -> it.buildItem(ItemBuildContext.of(player, ContextHolder.builder() .withParameter(GuiParameters.CURRENT_PAGE, String.valueOf(index + 1)) .withParameter(GuiParameters.MAX_PAGE, String.valueOf(recipes.size())) - .build()))) + ))) .orElseThrow(() -> new GuiElementMissingException("Can't find gui element " + previous)), (e, c) -> { c.cancel(); if (index > 0) { @@ -711,7 +711,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { } }) .build() - .title(AdventureHelper.miniMessage().deserialize(Constants.RECIPE_STONECUTTING_TITLE, PlayerContext.of(player, ContextHolder.EMPTY).tagResolvers())) + .title(AdventureHelper.miniMessage().deserialize(Constants.RECIPE_STONECUTTING_TITLE, PlayerOptionalContext.of(player).tagResolvers())) .refresh() .open(player); } @@ -764,7 +764,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { .map(it -> it.buildItem(ItemBuildContext.of(player, ContextHolder.builder() .withParameter(GuiParameters.COOKING_TIME, String.valueOf(recipe.cookingTime())) .withParameter(GuiParameters.COOKING_EXPERIENCE, String.valueOf(recipe.experience())) - .build()))) + ))) .orElseThrow(() -> new GuiElementMissingException("Can't find gui element " + Constants.RECIPE_COOKING_INFO)), (e, c) -> c.cancel())) .addIngredient('^', player.hasPermission(GET_ITEM_PERMISSION) ? GuiElement.constant(this.plugin.itemManager().createWrappedItem(Constants.RECIPE_GET_ITEM, player), (e, c) -> { c.cancel(); @@ -803,7 +803,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { } })) .addIngredient('=', GuiElement.constant(this.plugin.itemManager().getCustomItem(parentGui != null ? Constants.RECIPE_BACK : Constants.RECIPE_EXIT) - .map(it -> it.buildItem(ItemBuildContext.of(player, ContextHolder.EMPTY))) + .map(it -> it.buildItem(ItemBuildContext.of(player))) .orElseThrow(() -> new GuiElementMissingException("Can't find gui element " + (parentGui != null ? Constants.RECIPE_BACK : Constants.RECIPE_EXIT))), ((element, click) -> { click.cancel(); @@ -820,7 +820,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { .map(it -> it.buildItem(ItemBuildContext.of(player, ContextHolder.builder() .withParameter(GuiParameters.CURRENT_PAGE, String.valueOf(index + 1)) .withParameter(GuiParameters.MAX_PAGE, String.valueOf(recipes.size())) - .build()))) + ))) .orElseThrow(() -> new GuiElementMissingException("Can't find gui element " + next)), (e, c) -> { c.cancel(); if (index + 1 < recipes.size()) { @@ -833,7 +833,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { .map(it -> it.buildItem(ItemBuildContext.of(player, ContextHolder.builder() .withParameter(GuiParameters.CURRENT_PAGE, String.valueOf(index + 1)) .withParameter(GuiParameters.MAX_PAGE, String.valueOf(recipes.size())) - .build()))) + ))) .orElseThrow(() -> new GuiElementMissingException("Can't find gui element " + previous)), (e, c) -> { c.cancel(); if (index > 0) { @@ -861,7 +861,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { } }) .build() - .title(AdventureHelper.miniMessage().deserialize(title, PlayerContext.of(player, ContextHolder.EMPTY).tagResolvers())) + .title(AdventureHelper.miniMessage().deserialize(title, PlayerOptionalContext.of(player).tagResolvers())) .refresh() .open(player); } @@ -916,7 +916,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { } }) : GuiElement.EMPTY) .addIngredient('=', GuiElement.constant(this.plugin.itemManager().getCustomItem(parentGui != null ? Constants.RECIPE_BACK : Constants.RECIPE_EXIT) - .map(it -> it.buildItem(ItemBuildContext.of(player, ContextHolder.EMPTY))) + .map(it -> it.buildItem(ItemBuildContext.of(player))) .orElseThrow(() -> new GuiElementMissingException("Can't find gui element " + (parentGui != null ? Constants.RECIPE_BACK : Constants.RECIPE_EXIT))), ((element, click) -> { click.cancel(); @@ -933,7 +933,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { .map(it -> it.buildItem(ItemBuildContext.of(player, ContextHolder.builder() .withParameter(GuiParameters.CURRENT_PAGE, String.valueOf(index + 1)) .withParameter(GuiParameters.MAX_PAGE, String.valueOf(recipes.size())) - .build()))) + ))) .orElseThrow(() -> new GuiElementMissingException("Can't find gui element " + next)), (e, c) -> { c.cancel(); if (index + 1 < recipes.size()) { @@ -946,7 +946,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { .map(it -> it.buildItem(ItemBuildContext.of(player, ContextHolder.builder() .withParameter(GuiParameters.CURRENT_PAGE, String.valueOf(index + 1)) .withParameter(GuiParameters.MAX_PAGE, String.valueOf(recipes.size())) - .build()))) + ))) .orElseThrow(() -> new GuiElementMissingException("Can't find gui element " + previous)), (e, c) -> { c.cancel(); if (index > 0) { @@ -1056,7 +1056,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { } }) .build() - .title(AdventureHelper.miniMessage().deserialize(Constants.RECIPE_CRAFTING_TITLE, PlayerContext.of(player, ContextHolder.EMPTY).tagResolvers())) + .title(AdventureHelper.miniMessage().deserialize(Constants.RECIPE_CRAFTING_TITLE, PlayerOptionalContext.of(player).tagResolvers())) .refresh() .open(player); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/MiniMessageTranslatorImpl.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/MiniMessageTranslatorImpl.java index d5da280c8..d096d47ca 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/MiniMessageTranslatorImpl.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/MiniMessageTranslatorImpl.java @@ -18,7 +18,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Stream; public class MiniMessageTranslatorImpl implements MiniMessageTranslator { - private static final Key NAME = Key.key("craftengine", "main"); + private static final Key NAME = Key.key(net.momirealms.craftengine.core.util.Key.DEFAULT_NAMESPACE, "main"); static final MiniMessageTranslatorImpl INSTANCE = new MiniMessageTranslatorImpl(); final TranslatableComponentRenderer renderer = TranslatableComponentRenderer.usingTranslationSource(this); private final Set sources = Collections.newSetFromMap(new ConcurrentHashMap<>()); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManagerImpl.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManagerImpl.java index 1d540278e..dbbcdd70c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManagerImpl.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManagerImpl.java @@ -93,7 +93,7 @@ public class TranslationManagerImpl implements TranslationManager { this.plugin.saveResource("translations/" + lang + ".yml"); } - this.registry = MiniMessageTranslationRegistry.create(Key.key("craftengine", "main"), AdventureHelper.miniMessage()); + this.registry = MiniMessageTranslationRegistry.create(Key.key(net.momirealms.craftengine.core.util.Key.DEFAULT_NAMESPACE, "main"), AdventureHelper.miniMessage()); this.registry.defaultLocale(DEFAULT_LOCALE); this.loadFromFileSystem(this.translationsDirectory, false); MiniMessageTranslator.translator().addSource(this.registry); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetworkManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetworkManager.java index facef471a..8d2b0c0ba 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetworkManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetworkManager.java @@ -19,7 +19,7 @@ public interface NetworkManager extends Manageable { Channel getChannel(Player player); - NetWorkUser[] onlineUsers(); + Player[] onlineUsers(); default void sendPacket(@NotNull NetWorkUser player, Object packet) { sendPacket(player, packet, false); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/ProtocolVersion.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/ProtocolVersion.java index c692c6da6..f9e3c4b05 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/ProtocolVersion.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/ProtocolVersion.java @@ -32,6 +32,10 @@ public enum ProtocolVersion { return name; } + public boolean isVersionNewerThan(ProtocolVersion targetVersion) { + return this.getId() >= targetVersion.getId(); + } + public static ProtocolVersion getByName(String name) { for (ProtocolVersion version : values()) { if (version.getName().equals(name)) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/scheduler/AbstractJavaScheduler.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/scheduler/AbstractJavaScheduler.java index 1198fa6ea..c728459ac 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/scheduler/AbstractJavaScheduler.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/scheduler/AbstractJavaScheduler.java @@ -19,7 +19,6 @@ public abstract class AbstractJavaScheduler implements SchedulerAdapter { public AbstractJavaScheduler(Plugin plugin) { this.plugin = plugin; - this.scheduler = new ScheduledThreadPoolExecutor(4, r -> { Thread thread = Executors.defaultThreadFactory().newThread(r); thread.setName("craft-engine-scheduler"); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/ExpressionTag.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/ExpressionTag.java new file mode 100644 index 000000000..a0f58cc91 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/ExpressionTag.java @@ -0,0 +1,59 @@ +package net.momirealms.craftengine.core.plugin.text.minimessage; + +import com.ezylang.evalex.EvaluationException; +import com.ezylang.evalex.Expression; +import com.ezylang.evalex.parser.ParseException; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.minimessage.Context; +import net.kyori.adventure.text.minimessage.ParsingException; +import net.kyori.adventure.text.minimessage.tag.Tag; +import net.kyori.adventure.text.minimessage.tag.resolver.ArgumentQueue; +import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; +import net.momirealms.craftengine.core.util.AdventureHelper; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.Locale; +import java.util.Objects; + +public class ExpressionTag implements TagResolver { + private final net.momirealms.craftengine.core.plugin.context.Context context; + + public ExpressionTag(@NotNull net.momirealms.craftengine.core.plugin.context.Context context) { + this.context = Objects.requireNonNull(context, "context"); + } + + @Override + public @Nullable Tag resolve(@NotNull String name, @NotNull ArgumentQueue arguments, @NotNull Context ctx) throws ParsingException { + if (!has(name)) { + return null; + } + + String format = arguments.popOr("No format provided").toString(); + String expr = arguments.popOr("No expression provided").toString(); + + Component resultComponent = AdventureHelper.customMiniMessage().deserialize(expr, context.tagResolvers()); + String resultString = AdventureHelper.plainTextContent(resultComponent); + Expression expression = new Expression(resultString); + + try { + Number numberValue = expression.evaluate().getNumberValue(); + DecimalFormat df = new DecimalFormat(format); + DecimalFormatSymbols symbols = new DecimalFormatSymbols(Locale.US); + df.setDecimalFormatSymbols(symbols); + String formatted = df.format(numberValue); + return Tag.selfClosingInserting(Component.text(formatted)); + } catch (IllegalArgumentException e) { + throw ctx.newException("Invalid number format: " + format, arguments); + } catch (EvaluationException | ParseException e) { + throw ctx.newException("Invalid expression: " + e.getMessage(), arguments); + } + } + + @Override + public boolean has(@NotNull String name) { + return "expr".equals(name); + } +} \ No newline at end of file diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/I18NTag.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/I18NTag.java index c805a98d6..b0fa17a5b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/I18NTag.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/I18NTag.java @@ -1,34 +1,34 @@ package net.momirealms.craftengine.core.plugin.text.minimessage; -import net.kyori.adventure.text.minimessage.Context; import net.kyori.adventure.text.minimessage.ParsingException; import net.kyori.adventure.text.minimessage.tag.Tag; import net.kyori.adventure.text.minimessage.tag.resolver.ArgumentQueue; import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; +import net.momirealms.craftengine.core.plugin.context.Context; import net.momirealms.craftengine.core.plugin.locale.TranslationManager; import net.momirealms.craftengine.core.util.AdventureHelper; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public class I18NTag implements TagResolver { - private final MiniMessageTextContext context; + private final Context context; - public I18NTag(MiniMessageTextContext context) { + public I18NTag(Context context) { this.context = context; } @Override - public @Nullable Tag resolve(@NotNull String name, @NotNull ArgumentQueue arguments, @NotNull Context ctx) throws ParsingException { + public @Nullable Tag resolve(@NotNull String name, @NotNull ArgumentQueue arguments, @NotNull net.kyori.adventure.text.minimessage.Context ctx) throws ParsingException { if (!this.has(name)) { return null; } String i18nKey = arguments.popOr("No argument i18n key provided").toString(); String translation = TranslationManager.instance().miniMessageTranslation(i18nKey); - return Tag.inserting(AdventureHelper.miniMessage().deserialize(translation, this.context.tagResolvers())); + return Tag.selfClosingInserting(AdventureHelper.miniMessage().deserialize(translation, this.context.tagResolvers())); } @Override public boolean has(@NotNull String name) { - return "i18n".equals(name) || "l10n".equals(name); + return "i18n".equals(name); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/ImageTag.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/ImageTag.java index a6d718aea..6ba90c439 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/ImageTag.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/ImageTag.java @@ -34,9 +34,9 @@ public class ImageTag implements TagResolver { if (arguments.hasNext()) { int row = arguments.popOr("No argument row provided").asInt().orElseThrow(() -> ctx.newException("Invalid argument number", arguments)); int column = arguments.popOr("No argument column provided").asInt().orElseThrow(() -> ctx.newException("Invalid argument number", arguments)); - return Tag.inserting(Component.empty().children(List.of(optional.get().componentAt(row,column)))); + return Tag.selfClosingInserting(Component.empty().children(List.of(optional.get().componentAt(row,column)))); } else { - return Tag.inserting(Component.empty().children(List.of(optional.get().componentAt(0,0)))); + return Tag.selfClosingInserting(Component.empty().children(List.of(optional.get().componentAt(0,0)))); } } else { throw ctx.newException("Invalid image id", arguments); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/IndexedArgumentTag.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/IndexedArgumentTag.java index 098b4f6e0..f8a4f6c0e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/IndexedArgumentTag.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/IndexedArgumentTag.java @@ -13,9 +13,6 @@ import java.util.List; import java.util.Objects; public class IndexedArgumentTag implements TagResolver { - private static final String NAME_0 = "argument"; - private static final String NAME_1 = "arg"; - private final List argumentComponents; public IndexedArgumentTag(@NotNull List argumentComponents) { @@ -39,6 +36,6 @@ public class IndexedArgumentTag implements TagResolver { @Override public boolean has(@NotNull String name) { - return name.equals(NAME_0) || name.equals(NAME_1); + return name.equals("arg"); } } \ No newline at end of file diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/MiniMessageTextContext.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/MiniMessageTextContext.java deleted file mode 100644 index e9ea34494..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/MiniMessageTextContext.java +++ /dev/null @@ -1,11 +0,0 @@ -package net.momirealms.craftengine.core.plugin.text.minimessage; - -import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; -import net.momirealms.craftengine.core.util.context.ContextHolder; - -public interface MiniMessageTextContext { - - ContextHolder contexts(); - - TagResolver[] tagResolvers(); -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/NamedArgumentTag.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/NamedArgumentTag.java index 67f2b335f..595be9c85 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/NamedArgumentTag.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/NamedArgumentTag.java @@ -1,43 +1,41 @@ package net.momirealms.craftengine.core.plugin.text.minimessage; -import net.kyori.adventure.text.minimessage.Context; import net.kyori.adventure.text.minimessage.ParsingException; import net.kyori.adventure.text.minimessage.tag.Tag; import net.kyori.adventure.text.minimessage.tag.resolver.ArgumentQueue; import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.context.ContextKey; import net.momirealms.craftengine.core.util.AdventureHelper; -import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.context.ContextKey; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Objects; +import java.util.Optional; public class NamedArgumentTag implements TagResolver { - private static final String NAME_0 = "argument"; - private static final String NAME_1 = "arg"; + private final Context context; - private final MiniMessageTextContext context; - - public NamedArgumentTag(@NotNull MiniMessageTextContext context) { + public NamedArgumentTag(@NotNull Context context) { this.context = Objects.requireNonNull(context, "context holder"); } @Override - public @Nullable Tag resolve(@NotNull String name, @NotNull ArgumentQueue arguments, @NotNull Context ctx) throws ParsingException { + public @Nullable Tag resolve(@NotNull String name, @NotNull ArgumentQueue arguments, @NotNull net.kyori.adventure.text.minimessage.Context ctx) throws ParsingException { if (!has(name)) { return null; } - String argumentKey = arguments.popOr("No argument key provided").toString(); - ContextKey key = ContextKey.of(Key.of(argumentKey)); - if (!this.context.contexts().has(key)) { - throw ctx.newException("Invalid argument key", arguments); + ContextKey key = ContextKey.of(arguments.popOr("No argument key provided").toString()); + Optional optional = this.context.getOptionalParameter(key); + Object value = optional.orElse(null); + if (value == null) { + value = arguments.popOr("No default value provided").toString(); } - return Tag.selfClosingInserting(AdventureHelper.miniMessage().deserialize(this.context.contexts().getOrThrow(key), this.context.tagResolvers())); + return Tag.selfClosingInserting(AdventureHelper.miniMessage().deserialize(String.valueOf(value), this.context.tagResolvers())); } @Override public boolean has(@NotNull String name) { - return name.equals(NAME_0) || name.equals(NAME_1); + return name.equals("arg"); } } \ No newline at end of file diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/PlaceholderTag.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/PlaceholderTag.java index 59b331975..c326b284b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/PlaceholderTag.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/PlaceholderTag.java @@ -23,9 +23,12 @@ public class PlaceholderTag implements TagResolver { if (!this.has(name) || !CraftEngine.instance().compatibilityManager().hasPlaceholderAPI()) { return null; } - String placeholder = arguments.popOr("No argument placeholder provided").toString(); - String parsed = CraftEngine.instance().compatibilityManager().parse(player, "%" + placeholder + "%"); - return Tag.inserting(AdventureHelper.miniMessage().deserialize(parsed)); + String placeholder = "%" + arguments.popOr("No argument placeholder provided") + "%"; + String parsed = CraftEngine.instance().compatibilityManager().parse(player, placeholder); + if (parsed.equals(placeholder)) { + parsed = arguments.popOr("No default papi value provided").toString(); + } + return Tag.selfClosingInserting(AdventureHelper.miniMessage().deserialize(parsed)); } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/ShiftTag.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/ShiftTag.java index e5ccf26ae..6ed7fdb3f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/ShiftTag.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/ShiftTag.java @@ -25,7 +25,7 @@ public class ShiftTag implements TagResolver { String shiftAmount = arguments.popOr("No argument shift provided").toString(); try { int shift = Integer.parseInt(shiftAmount); - return Tag.inserting(AdventureHelper.miniMessage().deserialize(CraftEngine.instance().fontManager().createMiniMessageOffsets(shift))); + return Tag.selfClosingInserting(AdventureHelper.miniMessage().deserialize(CraftEngine.instance().fontManager().createMiniMessageOffsets(shift))); } catch (NumberFormatException e) { throw ctx.newException("Invalid shift value", arguments); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/ViewerNamedArgumentTag.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/ViewerNamedArgumentTag.java new file mode 100644 index 000000000..e1c2d5e94 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/ViewerNamedArgumentTag.java @@ -0,0 +1,16 @@ +package net.momirealms.craftengine.core.plugin.text.minimessage; + +import net.momirealms.craftengine.core.plugin.context.Context; +import org.jetbrains.annotations.NotNull; + +public class ViewerNamedArgumentTag extends NamedArgumentTag { + + public ViewerNamedArgumentTag(@NotNull Context context) { + super(context); + } + + @Override + public boolean has(@NotNull String name) { + return name.equals("viewer_arg"); + } +} \ No newline at end of file diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/ViewerPlaceholderTag.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/ViewerPlaceholderTag.java new file mode 100644 index 000000000..397a891ff --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/ViewerPlaceholderTag.java @@ -0,0 +1,17 @@ +package net.momirealms.craftengine.core.plugin.text.minimessage; + +import net.momirealms.craftengine.core.entity.player.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class ViewerPlaceholderTag extends PlaceholderTag { + + public ViewerPlaceholderTag(@Nullable Player player) { + super(player); + } + + @Override + public boolean has(@NotNull String name) { + return "viewer_papi".equals(name); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java b/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java index 59d7b9711..a92d3db1d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java +++ b/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java @@ -7,12 +7,11 @@ import net.momirealms.craftengine.core.entity.furniture.HitBoxFactory; import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory; import net.momirealms.craftengine.core.item.recipe.CustomSmithingTransformRecipe; import net.momirealms.craftengine.core.item.recipe.RecipeFactory; -import net.momirealms.craftengine.core.loot.condition.LootConditionFactory; +import net.momirealms.craftengine.core.loot.LootContext; import net.momirealms.craftengine.core.loot.entry.LootEntryContainerFactory; import net.momirealms.craftengine.core.loot.function.ApplyBonusCountFunction; import net.momirealms.craftengine.core.loot.function.LootFunctionFactory; -import net.momirealms.craftengine.core.loot.number.NumberProviderFactory; -import net.momirealms.craftengine.core.pack.conflict.matcher.PathMatcherFactory; +import net.momirealms.craftengine.core.pack.conflict.PathContext; import net.momirealms.craftengine.core.pack.conflict.resolution.ResolutionFactory; import net.momirealms.craftengine.core.pack.host.ResourcePackHostFactory; import net.momirealms.craftengine.core.pack.model.ItemModelFactory; @@ -22,19 +21,25 @@ import net.momirealms.craftengine.core.pack.model.select.SelectPropertyFactory; import net.momirealms.craftengine.core.pack.model.special.SpecialModelFactory; import net.momirealms.craftengine.core.pack.model.tint.TintFactory; import net.momirealms.craftengine.core.plugin.config.template.TemplateArgumentFactory; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.PlayerBlockActionContext; +import net.momirealms.craftengine.core.plugin.context.condition.ConditionFactory; +import net.momirealms.craftengine.core.plugin.context.function.Function; +import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; +import net.momirealms.craftengine.core.util.Factory; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceKey; public class BuiltInRegistries { public static final Registry BLOCK = createRegistry(Registries.BLOCK); public static final Registry OPTIMIZED_ITEM_ID = createRegistry(Registries.OPTIMIZED_ITEM_ID); - public static final Registry PROPERTY_FACTORY = createRegistry(Registries.PROPERTY_FACTORY); public static final Registry BLOCK_BEHAVIOR_FACTORY = createRegistry(Registries.BLOCK_BEHAVIOR_FACTORY); - public static final Registry> LOOT_FUNCTION_FACTORY = createRegistry(Registries.LOOT_FUNCTION_FACTORY); - public static final Registry LOOT_CONDITION_FACTORY = createRegistry(Registries.LOOT_CONDITION_FACTORY); - public static final Registry> LOOT_ENTRY_CONTAINER_FACTORY = createRegistry(Registries.LOOT_ENTRY_CONTAINER_FACTORY); - public static final Registry NUMBER_PROVIDER_FACTORY = createRegistry(Registries.NUMBER_PROVIDER_FACTORY); public static final Registry ITEM_BEHAVIOR_FACTORY = createRegistry(Registries.ITEM_BEHAVIOR_FACTORY); + public static final Registry PROPERTY_FACTORY = createRegistry(Registries.PROPERTY_FACTORY); + public static final Registry> LOOT_FUNCTION_FACTORY = createRegistry(Registries.LOOT_FUNCTION_FACTORY); + public static final Registry> LOOT_CONDITION_FACTORY = createRegistry(Registries.LOOT_CONDITION_FACTORY); + public static final Registry> LOOT_ENTRY_CONTAINER_FACTORY = createRegistry(Registries.LOOT_ENTRY_CONTAINER_FACTORY); + public static final Registry> NUMBER_PROVIDER_FACTORY = createRegistry(Registries.NUMBER_PROVIDER_FACTORY); public static final Registry TEMPLATE_ARGUMENT_FACTORY = createRegistry(Registries.TEMPLATE_ARGUMENT_FACTORY); public static final Registry ITEM_MODEL_FACTORY = createRegistry(Registries.ITEM_MODEL_FACTORY); public static final Registry TINT_FACTORY = createRegistry(Registries.TINT_FACTORY); @@ -44,11 +49,13 @@ public class BuiltInRegistries { public static final Registry SELECT_PROPERTY_FACTORY = createRegistry(Registries.SELECT_PROPERTY_FACTORY); public static final Registry> RECIPE_FACTORY = createRegistry(Registries.RECIPE_FACTORY); public static final Registry FORMULA_FACTORY = createRegistry(Registries.FORMULA_FACTORY); - public static final Registry PATH_MATCHER_FACTORY = createRegistry(Registries.PATH_MATCHER_FACTORY); + public static final Registry> PATH_MATCHER_FACTORY = createRegistry(Registries.PATH_MATCHER_FACTORY); public static final Registry RESOLUTION_FACTORY = createRegistry(Registries.RESOLUTION_FACTORY); - public static final Registry SMITHING_RESULT_PROCESSOR_FACTORY = createRegistry(Registries.SMITHING_RESULT_PROCESSOR_FACTORY); + public static final Registry SMITHING_RESULT_PROCESSOR_FACTORY = createRegistry(Registries.SMITHING_RESULT_PROCESSOR_FACTORY); public static final Registry HITBOX_FACTORY = createRegistry(Registries.HITBOX_FACTORY); public static final Registry RESOURCE_PACK_HOST_FACTORY = createRegistry(Registries.RESOURCE_PACK_HOST_FACTORY); + public static final Registry>> PLAYER_BLOCK_FUNCTION_FACTORY = createRegistry(Registries.PLAYER_BLOCK_FUNCTION_FACTORY); + public static final Registry>> PLAYER_BLOCK_CONDITION_FACTORY = createRegistry(Registries.PLAYER_BLOCK_CONDITION_FACTORY); private static Registry createRegistry(ResourceKey> key) { return new MappedRegistry<>(key); diff --git a/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java b/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java index 07e1e4ef8..434302ba9 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java +++ b/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java @@ -7,12 +7,11 @@ import net.momirealms.craftengine.core.entity.furniture.HitBoxFactory; import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory; import net.momirealms.craftengine.core.item.recipe.CustomSmithingTransformRecipe; import net.momirealms.craftengine.core.item.recipe.RecipeFactory; -import net.momirealms.craftengine.core.loot.condition.LootConditionFactory; +import net.momirealms.craftengine.core.loot.LootContext; import net.momirealms.craftengine.core.loot.entry.LootEntryContainerFactory; import net.momirealms.craftengine.core.loot.function.ApplyBonusCountFunction; import net.momirealms.craftengine.core.loot.function.LootFunctionFactory; -import net.momirealms.craftengine.core.loot.number.NumberProviderFactory; -import net.momirealms.craftengine.core.pack.conflict.matcher.PathMatcherFactory; +import net.momirealms.craftengine.core.pack.conflict.PathContext; import net.momirealms.craftengine.core.pack.conflict.resolution.ResolutionFactory; import net.momirealms.craftengine.core.pack.host.ResourcePackHostFactory; import net.momirealms.craftengine.core.pack.model.ItemModelFactory; @@ -22,6 +21,12 @@ import net.momirealms.craftengine.core.pack.model.select.SelectPropertyFactory; import net.momirealms.craftengine.core.pack.model.special.SpecialModelFactory; import net.momirealms.craftengine.core.pack.model.tint.TintFactory; import net.momirealms.craftengine.core.plugin.config.template.TemplateArgumentFactory; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.PlayerBlockActionContext; +import net.momirealms.craftengine.core.plugin.context.condition.ConditionFactory; +import net.momirealms.craftengine.core.plugin.context.function.Function; +import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; +import net.momirealms.craftengine.core.util.Factory; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceKey; @@ -34,8 +39,8 @@ public class Registries { public static final ResourceKey> ITEM_BEHAVIOR_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("item_behavior_factory")); public static final ResourceKey>> LOOT_FUNCTION_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("loot_function_factory")); public static final ResourceKey>> LOOT_ENTRY_CONTAINER_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("loot_entry_container_factory")); - public static final ResourceKey> LOOT_CONDITION_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("loot_condition_factory")); - public static final ResourceKey> NUMBER_PROVIDER_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("number_provider_factory")); + public static final ResourceKey>> LOOT_CONDITION_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("loot_condition_factory")); + public static final ResourceKey>> NUMBER_PROVIDER_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("number_provider_factory")); public static final ResourceKey> TEMPLATE_ARGUMENT_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("template_argument_factory")); public static final ResourceKey> ITEM_MODEL_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("item_model_factory")); public static final ResourceKey> TINT_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("tint_factory")); @@ -45,9 +50,11 @@ public class Registries { public static final ResourceKey> SELECT_PROPERTY_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("select_property_factory")); public static final ResourceKey>> RECIPE_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("recipe_factory")); public static final ResourceKey> FORMULA_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("formula_factory")); - public static final ResourceKey> PATH_MATCHER_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("path_matcher_factory")); + public static final ResourceKey>> PATH_MATCHER_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("path_matcher_factory")); public static final ResourceKey> RESOLUTION_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("resolution_factory")); - public static final ResourceKey> SMITHING_RESULT_PROCESSOR_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("smithing_result_processor_factory")); + public static final ResourceKey> SMITHING_RESULT_PROCESSOR_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("smithing_result_processor_factory")); public static final ResourceKey> HITBOX_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("hitbox_factory")); public static final ResourceKey> RESOURCE_PACK_HOST_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("resource_pack_host_factory")); + public static final ResourceKey>>> PLAYER_BLOCK_FUNCTION_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("player_block_function_factory")); + public static final ResourceKey>>> PLAYER_BLOCK_CONDITION_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("player_block_condition_factory")); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java b/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java index 1cfa6f2d4..0062e5bd6 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java @@ -13,6 +13,7 @@ import net.kyori.adventure.text.serializer.json.JSONOptions; import net.kyori.adventure.text.serializer.json.legacyimpl.NBTLegacyHoverEventSerializer; import net.momirealms.sparrow.nbt.Tag; import net.momirealms.sparrow.nbt.serializer.NBTComponentSerializer; +import net.momirealms.sparrow.nbt.serializer.NBTSerializerOptions; /** * Helper class for handling Adventure components and related functionalities. @@ -34,8 +35,22 @@ public class AdventureHelper { builder.legacyHoverEventSerializer(NBTLegacyHoverEventSerializer.get()); builder.editOptions((b) -> b.value(JSONOptions.EMIT_HOVER_SHOW_ENTITY_ID_AS_INT_ARRAY, false)); } + if (!VersionHelper.isOrAbove1_21_5()) { + builder.editOptions((b) -> { + b.value(JSONOptions.EMIT_CLICK_EVENT_TYPE, JSONOptions.ClickEventValueMode.CAMEL_CASE); + b.value(JSONOptions.EMIT_HOVER_EVENT_TYPE, JSONOptions.HoverEventValueMode.CAMEL_CASE); + b.value(JSONOptions.EMIT_HOVER_SHOW_ENTITY_KEY_AS_TYPE_AND_UUID_AS_ID, true); + }); + } this.gsonComponentSerializer = builder.build(); - this.nbtComponentSerializer = NBTComponentSerializer.builder().build(); + this.nbtComponentSerializer = NBTComponentSerializer.builder() + .editOptions((b) -> { + if (!VersionHelper.isOrAbove1_21_5()) { + b.value(NBTSerializerOptions.EMIT_CLICK_EVENT_TYPE, false); + b.value(NBTSerializerOptions.EMIT_HOVER_EVENT_TYPE, false); + } + }) + .build(); } private static class SingletonHolder { diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/CharacterUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/CharacterUtils.java index 2d8693728..7e5e154da 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/CharacterUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/CharacterUtils.java @@ -2,9 +2,11 @@ package net.momirealms.craftengine.core.util; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; +import java.util.regex.Pattern; import java.util.stream.IntStream; public class CharacterUtils { + private static final Pattern PATTERN = Pattern.compile("[\\p{Mn}\\p{Me}\\p{Mc}\\p{Cf}]"); private CharacterUtils() {} @@ -72,4 +74,27 @@ public class CharacterUtils { } return builder.toString(); } + + public static boolean containsCombinedCharacter(String input) { + if (input == null || input.isEmpty() || input.length() == 1) return false; + for (int i = 0; i < input.length();) { + int codePoint = input.codePointAt(i); + i += Character.charCount(codePoint); + int type = Character.getType(codePoint); + if (type == Character.NON_SPACING_MARK || + type == Character.ENCLOSING_MARK || + type == Character.COMBINING_SPACING_MARK || + type == Character.FORMAT || + type == Character.CONTROL || + type == Character.SURROGATE || + type == Character.PRIVATE_USE || + PATTERN.matcher(new String(Character.toChars(codePoint))).find() + ) return true; + if (i < input.length()) { + int nextCodePoint = input.codePointAt(i); + if (Character.isSurrogatePair(Character.toChars(codePoint)[0], Character.toChars(nextCodePoint)[0])) return true; + } + } + return false; + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/Factory.java b/core/src/main/java/net/momirealms/craftengine/core/util/Factory.java new file mode 100644 index 000000000..ec3e37b2f --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/util/Factory.java @@ -0,0 +1,8 @@ +package net.momirealms.craftengine.core.util; + +import java.util.Map; + +public interface Factory { + + T create(Map args); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/Key.java b/core/src/main/java/net/momirealms/craftengine/core/util/Key.java index f536fa5ba..ed43ffe8c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/Key.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/Key.java @@ -1,7 +1,8 @@ package net.momirealms.craftengine.core.util; -public record Key(String namespace, String value) { +import org.jetbrains.annotations.NotNull; +public record Key(String namespace, String value) { public static final String DEFAULT_NAMESPACE = "craftengine"; public static Key withDefaultNamespace(String value) { @@ -28,6 +29,10 @@ public record Key(String namespace, String value) { return of(decompose(namespacedId, "minecraft")); } + public static Key fromNamespaceAndPath(String namespace, String path) { + return Key.of(namespace, path); + } + public String[] decompose() { return new String[] { namespace, value }; } @@ -48,7 +53,7 @@ public record Key(String namespace, String value) { } @Override - public String toString() { + public @NotNull String toString() { return namespace + ":" + value; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/ProtocolVersionUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/ProtocolVersionUtils.java deleted file mode 100644 index 8372e1117..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/util/ProtocolVersionUtils.java +++ /dev/null @@ -1,10 +0,0 @@ -package net.momirealms.craftengine.core.util; - -import net.momirealms.craftengine.core.plugin.network.ProtocolVersion; - -public class ProtocolVersionUtils { - - public static boolean isVersionNewerThan(ProtocolVersion version, ProtocolVersion targetVersion) { - return version.getId() >= targetVersion.getId(); - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/RandomUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/RandomUtils.java index 34c0b03e7..b659d4c28 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/RandomUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/RandomUtils.java @@ -1,37 +1,25 @@ package net.momirealms.craftengine.core.util; -import java.util.Random; import java.util.concurrent.ThreadLocalRandom; -public class RandomUtils { - private final Random random; +public final class RandomUtils { - private RandomUtils() { - random = ThreadLocalRandom.current(); - } - - private static class SingletonHolder { - private static final RandomUtils INSTANCE = new RandomUtils(); - } - - private static RandomUtils getInstance() { - return SingletonHolder.INSTANCE; - } + private RandomUtils() {} public static double generateRandomDouble(double min, double max) { - return min + (max - min) * getInstance().random.nextDouble(); + return min + (max - min) * ThreadLocalRandom.current().nextDouble(); } public static float generateRandomFloat(float min, float max) { - return min + (max - min) * getInstance().random.nextFloat(); + return min + (max - min) * ThreadLocalRandom.current().nextFloat(); } public static int generateRandomInt(int min, int max) { - return min >= max ? min : getInstance().random.nextInt(max - min + 1) + min; + return min >= max ? min : ThreadLocalRandom.current().nextInt(max - min) + min; } public static boolean generateRandomBoolean() { - return getInstance().random.nextBoolean(); + return ThreadLocalRandom.current().nextBoolean(); } public static double triangle(double mode, double deviation) { @@ -39,7 +27,7 @@ public class RandomUtils { } public static T getRandomElementFromArray(T[] array) { - int index = getInstance().random.nextInt(array.length); + int index = ThreadLocalRandom.current().nextInt(array.length); return array[index]; } @@ -50,7 +38,7 @@ public class RandomUtils { @SuppressWarnings("unchecked") T[] result = (T[]) new Object[count]; for (int i = 0; i < count; i++) { - int index = getInstance().random.nextInt(array.length - i); + int index = ThreadLocalRandom.current().nextInt(array.length - i); result[i] = array[index]; array[index] = array[array.length - i - 1]; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/ReflectionUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/ReflectionUtils.java index f83302bab..04a9d4baf 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/ReflectionUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/ReflectionUtils.java @@ -246,6 +246,27 @@ public class ReflectionUtils { return null; } + @Nullable + public static Method getInstanceMethod(final Class clazz, Class returnType, final Class... parameterTypes) { + outer: + for (Method method : clazz.getMethods()) { + if (method.getParameterCount() != parameterTypes.length) { + continue; + } + if (Modifier.isStatic(method.getModifiers())) { + continue; + } + Class[] types = method.getParameterTypes(); + for (int i = 0; i < types.length; i++) { + if (types[i] != parameterTypes[i]) { + continue outer; + } + } + if (returnType.isAssignableFrom(method.getReturnType())) return method; + } + return null; + } + @Nullable public static Method getDeclaredMethod(final Class clazz, Class returnType, final String[] possibleMethodNames, final Class... parameterTypes) { outer: diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/context/ContextHolder.java b/core/src/main/java/net/momirealms/craftengine/core/util/context/ContextHolder.java deleted file mode 100644 index 7939014e9..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/util/context/ContextHolder.java +++ /dev/null @@ -1,86 +0,0 @@ -package net.momirealms.craftengine.core.util.context; - -import javax.annotation.Nullable; -import java.util.HashMap; -import java.util.Map; -import java.util.NoSuchElementException; -import java.util.Optional; - -public class ContextHolder { - public static final ContextHolder EMPTY = ContextHolder.builder().build(); - - private final Map, Object> params; - - public ContextHolder(Map, Object> params) { - this.params = params; - } - - public boolean has(ContextKey key) { - return params.containsKey(key); - } - - @SuppressWarnings("unchecked") - public T getOrThrow(ContextKey parameter) { - T object = (T) this.params.get(parameter); - if (object == null) { - throw new NoSuchElementException(parameter.id().toString()); - } else { - return object; - } - } - - @SuppressWarnings("unchecked") - public Optional getOptional(ContextKey parameter) { - return Optional.ofNullable((T) this.params.get(parameter)); - } - - @SuppressWarnings("unchecked") - @Nullable - public T getOrDefault(ContextKey parameter, @Nullable T defaultValue) { - return (T) this.params.getOrDefault(parameter, defaultValue); - } - - public static Builder builder() { - return new Builder(); - } - - public static class Builder { - - private final Map, Object> params = new HashMap<>(); - - public Builder() {} - - public Builder withParameter(ContextKey parameter, T value) { - this.params.put(parameter, value); - return this; - } - - public Builder withOptionalParameter(ContextKey parameter, @Nullable T value) { - if (value == null) { - this.params.remove(parameter); - } else { - this.params.put(parameter, value); - } - return this; - } - - @SuppressWarnings("unchecked") - public T getParameterOrThrow(ContextKey parameter) { - T object = (T) this.params.get(parameter); - if (object == null) { - throw new NoSuchElementException(parameter.id().toString()); - } else { - return object; - } - } - - @SuppressWarnings("unchecked") - public Optional getOptionalParameter(ContextKey parameter) { - return Optional.ofNullable((T) this.params.get(parameter)); - } - - public ContextHolder build() { - return new ContextHolder(this.params); - } - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/context/PlayerContext.java b/core/src/main/java/net/momirealms/craftengine/core/util/context/PlayerContext.java deleted file mode 100644 index 1104abb65..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/util/context/PlayerContext.java +++ /dev/null @@ -1,42 +0,0 @@ -package net.momirealms.craftengine.core.util.context; - -import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; -import net.momirealms.craftengine.core.entity.player.Player; -import net.momirealms.craftengine.core.plugin.text.minimessage.*; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public class PlayerContext implements MiniMessageTextContext { - public static final PlayerContext EMPTY = new PlayerContext(null, ContextHolder.EMPTY); - private final Player player; - private final ContextHolder contexts; - private TagResolver[] tagResolvers; - - public PlayerContext(@Nullable Player player, @NotNull ContextHolder contexts) { - this.player = player; - this.contexts = contexts; - } - - @NotNull - public static PlayerContext of(@Nullable Player player, @NotNull ContextHolder contexts) { - return new PlayerContext(player, contexts); - } - - @Nullable - public Player player() { - return this.player; - } - - @NotNull - public ContextHolder contexts() { - return this.contexts; - } - - @NotNull - public TagResolver[] tagResolvers() { - if (this.tagResolvers == null) { - this.tagResolvers = new TagResolver[]{ShiftTag.INSTANCE, ImageTag.INSTANCE, new PlaceholderTag(this.player), new I18NTag(this), new NamedArgumentTag(this)}; - } - return this.tagResolvers; - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/os/Architecture.java b/core/src/main/java/net/momirealms/craftengine/core/util/os/Architecture.java deleted file mode 100644 index ab97a1da9..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/util/os/Architecture.java +++ /dev/null @@ -1,49 +0,0 @@ -package net.momirealms.craftengine.core.util.os; - -import java.util.Locale; - -public enum Architecture { - X64(true), - X86(false), - ARM64(true), - ARM32(false), - PPC64LE(true), - RISCV64(true); - - static final Architecture current; - final boolean is64Bit; - - Architecture(boolean is64Bit) { - this.is64Bit = is64Bit; - } - - public String getNativePath() { - return name().toLowerCase(Locale.ENGLISH); - } - - public static Architecture get() { - return current; - } - - static { - String osArch = System.getProperty("os.arch"); - boolean is64Bit = osArch.contains("64") || osArch.startsWith("armv8"); - if (!osArch.startsWith("arm") && !osArch.startsWith("aarch")) { - if (osArch.startsWith("ppc")) { - if (!"ppc64le".equals(osArch)) { - throw new UnsupportedOperationException("Only PowerPC 64 LE is supported."); - } - current = PPC64LE; - } else if (osArch.startsWith("riscv")) { - if (!"riscv64".equals(osArch)) { - throw new UnsupportedOperationException("Only RISC-V 64 is supported."); - } - current = RISCV64; - } else { - current = is64Bit ? X64 : X86; - } - } else { - current = is64Bit ? ARM64 : ARM32; - } - } -} \ No newline at end of file diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/os/Platform.java b/core/src/main/java/net/momirealms/craftengine/core/util/os/Platform.java deleted file mode 100644 index fd864193d..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/util/os/Platform.java +++ /dev/null @@ -1,45 +0,0 @@ -package net.momirealms.craftengine.core.util.os; - -public enum Platform { - FREEBSD("FreeBSD", "freebsd"), - LINUX("Linux", "linux"), - MACOS("macOS", "macos"), - WINDOWS("Windows", "windows"); - - private static final Platform current; - private final String name; - private final String nativePath; - - Platform(String name, String nativePath) { - this.name = name; - this.nativePath = nativePath; - } - - public String getName() { - return this.name; - } - - public String getNativePath() { - return nativePath; - } - - public static Platform get() { - return current; - } - - static { - String osName = System.getProperty("os.name"); - if (osName.startsWith("Windows")) { - current = WINDOWS; - } else if (osName.startsWith("FreeBSD")) { - current = FREEBSD; - } else if (!osName.startsWith("Linux") && !osName.startsWith("SunOS") && !osName.startsWith("Unix")) { - if (!osName.startsWith("Mac OS X") && !osName.startsWith("Darwin")) { - throw new LinkageError("Unknown platform: " + osName); - } - current = MACOS; - } else { - current = LINUX; - } - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/WorldBlock.java b/core/src/main/java/net/momirealms/craftengine/core/world/BlockInWorld.java similarity index 63% rename from core/src/main/java/net/momirealms/craftengine/core/world/WorldBlock.java rename to core/src/main/java/net/momirealms/craftengine/core/world/BlockInWorld.java index 4da8df826..461ef2699 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/WorldBlock.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/BlockInWorld.java @@ -1,8 +1,9 @@ package net.momirealms.craftengine.core.world; import net.momirealms.craftengine.core.item.context.BlockPlaceContext; +import net.momirealms.craftengine.core.util.Key; -public interface WorldBlock { +public interface BlockInWorld { default boolean canBeReplaced(BlockPlaceContext blockPlaceContext) { return false; @@ -11,4 +12,16 @@ public interface WorldBlock { default boolean isWaterSource(BlockPlaceContext blockPlaceContext) { return false; } + + Key owner(); + + String getAsString(); + + World world(); + + int x(); + + int y(); + + int z(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/CEWorld.java b/core/src/main/java/net/momirealms/craftengine/core/world/CEWorld.java index 51bc86577..e36abc7ce 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/CEWorld.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/CEWorld.java @@ -49,7 +49,7 @@ public abstract class CEWorld { for (Map.Entry entry : this.loadedChunkMap.entrySet()) { CEChunk chunk = entry.getValue(); if (chunk.dirty()) { - worldDataStorage.writeChunkAt(new ChunkPos(entry.getKey()), chunk, true); + worldDataStorage.writeChunkAt(new ChunkPos(entry.getKey()), chunk); chunk.setDirty(false); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/ChunkPos.java b/core/src/main/java/net/momirealms/craftengine/core/world/ChunkPos.java index d64ff68c0..115dd689a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/ChunkPos.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/ChunkPos.java @@ -12,6 +12,10 @@ public class ChunkPos { this.longKey = asLong(this.x, this.z); } + public static ChunkPos of(final int x, final int z) { + return new ChunkPos(x, z); + } + public ChunkPos(BlockPos pos) { this.x = SectionPos.blockToSectionCoord(pos.x()); this.z = SectionPos.blockToSectionCoord(pos.z()); @@ -64,4 +68,17 @@ public class ChunkPos { public static long asLong(int chunkX, int chunkZ) { return (long) chunkX & 4294967295L | ((long) chunkZ & 4294967295L) << 32; } + + @Override + public final boolean equals(Object o) { + if (!(o instanceof ChunkPos chunkPos)) return false; + return x == chunkPos.x && z == chunkPos.z; + } + + @Override + public int hashCode() { + int result = x; + result = 31 * result + z; + return result; + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/InjectionTarget.java b/core/src/main/java/net/momirealms/craftengine/core/world/InjectionTarget.java new file mode 100644 index 000000000..35149a464 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/world/InjectionTarget.java @@ -0,0 +1,6 @@ +package net.momirealms.craftengine.core.world; + +public enum InjectionTarget { + SECTION, + PALETTE +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/World.java b/core/src/main/java/net/momirealms/craftengine/core/world/World.java index 36979368c..5817a5e1f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/World.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/World.java @@ -15,9 +15,9 @@ public interface World { WorldHeight worldHeight(); - WorldBlock getBlockAt(int x, int y, int z); + BlockInWorld getBlockAt(int x, int y, int z); - default WorldBlock getBlockAt(final BlockPos pos) { + default BlockInWorld getBlockAt(final BlockPos pos) { return getBlockAt(pos.x(), pos.y(), pos.z()); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/CEChunk.java b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/CEChunk.java index 1ae57e38b..45b0a52b8 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/CEChunk.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/CEChunk.java @@ -47,11 +47,11 @@ public class CEChunk { } public Map blockEntities() { - return blockEntities; + return this.blockEntities; } public boolean dirty() { - return dirty; + return this.dirty; } public void setDirty(boolean dirty) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/InjectedPalettedContainerHolder.java b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/InjectedHolder.java similarity index 52% rename from core/src/main/java/net/momirealms/craftengine/core/world/chunk/InjectedPalettedContainerHolder.java rename to core/src/main/java/net/momirealms/craftengine/core/world/chunk/InjectedHolder.java index f8d67784d..4287019e6 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/InjectedPalettedContainerHolder.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/InjectedHolder.java @@ -1,11 +1,12 @@ package net.momirealms.craftengine.core.world.chunk; -import net.momirealms.craftengine.core.world.CEWorld; import net.momirealms.craftengine.core.world.SectionPos; -public interface InjectedPalettedContainerHolder { +public interface InjectedHolder { - Object target(); + boolean isActive(); + + void setActive(boolean active); CESection ceSection(); @@ -15,11 +16,17 @@ public interface InjectedPalettedContainerHolder { void ceChunk(CEChunk chunk); - CEWorld ceWorld(); - - void ceWorld(CEWorld world); - SectionPos cePos(); void cePos(SectionPos pos); + + interface Section extends InjectedHolder { + } + + interface Palette extends InjectedHolder { + + Object target(); + + void setTarget(Object target); + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/CachedStorage.java b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/CachedStorage.java new file mode 100644 index 000000000..9cc9d5d5e --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/CachedStorage.java @@ -0,0 +1,53 @@ +package net.momirealms.craftengine.core.world.chunk.storage; + +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; +import com.github.benmanes.caffeine.cache.Scheduler; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.world.CEWorld; +import net.momirealms.craftengine.core.world.ChunkPos; +import net.momirealms.craftengine.core.world.chunk.CEChunk; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; +import java.util.concurrent.TimeUnit; + +public class CachedStorage implements WorldDataStorage { + private final T storage; + private final Cache chunkCache; + + public CachedStorage(T storage) { + this.storage = storage; + this.chunkCache = Caffeine.newBuilder() + .executor(CraftEngine.instance().scheduler().async()) + .scheduler(Scheduler.systemScheduler()) + .expireAfterAccess(30, TimeUnit.SECONDS) + .build(); + } + + @Override + public @NotNull CEChunk readChunkAt(@NotNull CEWorld world, @NotNull ChunkPos pos) throws IOException { + CEChunk chunk = this.chunkCache.getIfPresent(pos); + if (chunk != null) { + return chunk; + } + chunk = this.storage.readChunkAt(world, pos); + this.chunkCache.put(pos, chunk); + return chunk; + } + + @Override + public void writeChunkAt(@NotNull ChunkPos pos, @NotNull CEChunk chunk) throws IOException { + this.storage.writeChunkAt(pos, chunk); + } + + @Override + public void close() throws IOException { + this.storage.close(); + } + + @Override + public void flush() throws IOException { + this.storage.flush(); + } +} \ No newline at end of file diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/DefaultRegionFileStorage.java b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/DefaultRegionFileStorage.java index 132bc699f..bfeef7a58 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/DefaultRegionFileStorage.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/DefaultRegionFileStorage.java @@ -147,7 +147,7 @@ public class DefaultRegionFileStorage implements WorldDataStorage { } @Override - public void writeChunkAt(@NotNull ChunkPos pos, @NotNull CEChunk chunk, boolean immediately) throws IOException { + public void writeChunkAt(@NotNull ChunkPos pos, @NotNull CEChunk chunk) throws IOException { CompoundTag nbt = DefaultChunkSerializer.serialize(chunk); writeChunkTagAt(pos, nbt); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/DefaultStorageAdaptor.java b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/DefaultStorageAdaptor.java index 401ed6880..6b669241f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/DefaultStorageAdaptor.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/DefaultStorageAdaptor.java @@ -9,8 +9,8 @@ public class DefaultStorageAdaptor implements StorageAdaptor { @Override public @NotNull WorldDataStorage adapt(@NotNull World world) { - if (Config.delaySerialization() > 0) { - return new DelayedDefaultRegionFileStorage(world.directory().resolve(CEWorld.REGION_DIRECTORY), Config.delaySerialization()); + if (Config.enableChunkCache()) { + return new CachedStorage<>(new DefaultRegionFileStorage(world.directory().resolve(CEWorld.REGION_DIRECTORY))); } else { return new DefaultRegionFileStorage(world.directory().resolve(CEWorld.REGION_DIRECTORY)); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/DelayedDefaultRegionFileStorage.java b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/DelayedDefaultRegionFileStorage.java deleted file mode 100644 index 04dceb3a0..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/DelayedDefaultRegionFileStorage.java +++ /dev/null @@ -1,76 +0,0 @@ -package net.momirealms.craftengine.core.world.chunk.storage; - -import com.github.benmanes.caffeine.cache.Cache; -import com.github.benmanes.caffeine.cache.Caffeine; -import com.github.benmanes.caffeine.cache.RemovalCause; -import net.momirealms.craftengine.core.plugin.CraftEngine; -import net.momirealms.craftengine.core.world.CEWorld; -import net.momirealms.craftengine.core.world.ChunkPos; -import net.momirealms.craftengine.core.world.chunk.CEChunk; -import org.jetbrains.annotations.NotNull; - -import java.io.IOException; -import java.nio.file.Path; -import java.util.concurrent.TimeUnit; - -public class DelayedDefaultRegionFileStorage extends DefaultRegionFileStorage { - private final Cache chunkCache; - - public DelayedDefaultRegionFileStorage(Path directory, int time) { - super(directory); - this.chunkCache = Caffeine.newBuilder() - .expireAfterWrite(time, TimeUnit.SECONDS) - .removalListener((ChunkPos key, CEChunk value, RemovalCause cause) -> { - if (key == null || value == null) { - return; - } - if (cause == RemovalCause.EXPIRED || cause == RemovalCause.SIZE) { - try { - super.writeChunkAt(key, value, true); - } catch (IOException e) { - CraftEngine.instance().logger().warn("Failed to write chunk at " + key, e); - } - } - }) - .build(); - } - - @Override - public @NotNull CEChunk readChunkAt(@NotNull CEWorld world, @NotNull ChunkPos pos) throws IOException { - CEChunk chunk = this.chunkCache.asMap().remove(pos); - if (chunk != null) { - return chunk; - } - return super.readChunkAt(world, pos); - } - - @Override - public void writeChunkAt(@NotNull ChunkPos pos, @NotNull CEChunk chunk, boolean immediately) throws IOException { - if (immediately) { - super.writeChunkAt(pos, chunk, true); - return; - } - if (chunk.isEmpty()) { - super.writeChunkTagAt(pos, null); - return; - } - this.chunkCache.put(pos, chunk); - } - - @Override - public synchronized void close() throws IOException { - this.saveCache(); - super.close(); - } - - private void saveCache() { - try { - for (var chunk : this.chunkCache.asMap().entrySet()) { - super.writeChunkAt(chunk.getKey(), chunk.getValue(), true); - } - } catch (IOException e) { - CraftEngine.instance().logger().warn("Failed to save chunks", e); - } - this.chunkCache.invalidateAll(); - } -} \ No newline at end of file diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/RegionFile.java b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/RegionFile.java index b2e8ad51b..0ee384791 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/RegionFile.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/RegionFile.java @@ -11,6 +11,7 @@ import java.io.*; import java.nio.Buffer; import java.nio.ByteBuffer; import java.nio.IntBuffer; +import java.nio.channels.ClosedChannelException; import java.nio.channels.FileChannel; import java.nio.file.Files; import java.nio.file.Path; diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/WorldDataStorage.java b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/WorldDataStorage.java index b3b4dd47d..bd44492a9 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/WorldDataStorage.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/WorldDataStorage.java @@ -12,7 +12,7 @@ public interface WorldDataStorage { @NotNull CEChunk readChunkAt(@NotNull CEWorld world, @NotNull ChunkPos pos) throws IOException; - void writeChunkAt(@NotNull ChunkPos pos, @NotNull CEChunk chunk, boolean immediately) throws IOException; + void writeChunkAt(@NotNull ChunkPos pos, @NotNull CEChunk chunk) throws IOException; void flush() throws IOException; diff --git a/gradle.properties b/gradle.properties index 97af92e9b..f57da2123 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,9 +2,9 @@ org.gradle.jvmargs=-Xmx1G # Project settings # Rule: [major update].[feature update].[bug fix] -project_version=0.0.52 -config_version=31 -lang_version=9 +project_version=0.0.53 +config_version=32 +lang_version=12 project_group=net.momirealms latest_supported_version=1.21.5 @@ -20,7 +20,7 @@ gson_version=2.11.0 asm_version=9.8 asm_commons_version=9.8 jar_relocator_version=1.7 -adventure_bundle_version=4.20.0 +adventure_bundle_version=4.21.0 adventure_platform_version=4.3.4 cloud_core_version=2.0.0 cloud_services_version=2.0.0 @@ -39,8 +39,8 @@ lz4_version=1.8.0 geantyref_version=1.3.16 zstd_version=1.5.7-2 commons_io_version=2.18.0 -sparrow_nbt_version=0.6.2 -sparrow_util_version=0.39 +sparrow_nbt_version=0.7.3 +sparrow_util_version=0.40 fastutil_version=8.5.15 netty_version=4.1.119.Final joml_version=1.10.8 @@ -50,7 +50,8 @@ byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.4 anti_grief_version=0.15 -nms_helper_version=0.64.3 +nms_helper_version=0.65.15 +evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.31.23 amazon_awssdk_eventstream_version=1.0.1 diff --git a/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/CraftEnginePlugin.java b/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/CraftEnginePlugin.java index 6cb356a90..c0b7d7bf1 100644 --- a/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/CraftEnginePlugin.java +++ b/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/CraftEnginePlugin.java @@ -1,5 +1,6 @@ package net.momirealms.craftengine.mod; +import net.minecraft.world.level.chunk.LevelChunkSection; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.objectweb.asm.tree.ClassNode;