9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-28 03:19:14 +00:00

Merge pull request #166 from Xiao-MoMi/dev

0.0.53
This commit is contained in:
XiaoMoMi
2025-05-07 21:17:52 +08:00
committed by GitHub
234 changed files with 3708 additions and 1952 deletions

View File

@@ -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")
}
}

View File

@@ -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 {

View File

@@ -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) {

View File

@@ -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<com.flowpowered.nbt.CompoundTag> 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);

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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<CEChunk> chunksToSave;
private final CEWorld ceWorld;
private final Set<ChunkPos> 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<BlockVector3> 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 <B extends BlockStateHolder<B>> 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 <B extends BlockStateHolder<B>> int replaceBlocks(final Region region, final Set<BaseBlock> filter, final B replacement) {
this.processBlocks(region, replacement);
return super.replaceBlocks(region, filter, replacement);
}
@Override
public int replaceBlocks(final Region region, final Set<BaseBlock> filter, final Pattern pattern) {
this.processBlocks(region, pattern);
return super.replaceBlocks(region, filter, pattern);
}
@Override
public <T extends BlockStateHolder<T>> 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 <T extends BlockStateHolder<T>> 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<ChunkPos> 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<BlockVector3> 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);
}
}
}

View File

@@ -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<String> getSuggestions(String input) {
Set<String> namespacesInUse = manager.namespacesInUse();

View File

@@ -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);
}
}

View File

@@ -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")

View File

@@ -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

View File

@@ -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):

View File

@@ -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}
amazon-sdk-eventstream=${amazon_awssdk_eventstream_version}
evalex=${evalex_version}

View File

@@ -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]

View File

@@ -1,7 +1,6 @@
# Don't change this
lang-version: "${lang_version}"
# Commands
exception.invalid_syntax: "<red>Invalid syntax. Correct syntax: <white><arg:0></white></red>"
exception.invalid_argument: "<red>Invalid argument. Reason: <white><arg:0></white></red>"
exception.invalid_sender: "<red><arg:0> is not allowed to execute that command. Must be of type <arg:1></red>"
@@ -70,6 +69,27 @@ warning.config.type.float: "<yellow>Issue found in file <arg:0> - Failed to load
warning.config.type.double: "<yellow>Issue found in file <arg:0> - Failed to load '<arg:1>': Cannot cast '<arg:2>' to double type for option '<arg:3>'.</yellow>"
warning.config.type.quaternionf: "<yellow>Issue found in file <arg:0> - Failed to load '<arg:1>': Cannot cast '<arg:2>' to Quaternionf type for option '<arg:3>'.</yellow>"
warning.config.type.vector3f: "<yellow>Issue found in file <arg:0> - Failed to load '<arg:1>': Cannot cast '<arg:2>' to Vector3f type for option '<arg:3>'.</yellow>"
warning.config.number.missing_type: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'type' argument for number argument.</yellow>"
warning.config.number.invalid_type: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is using an invalid number argument type '<arg:2>'.</yellow>"
warning.config.number.missing_argument: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the argument for 'number'.</yellow>"
warning.config.number.invalid_format: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is using an invalid number format '<arg:2>'.</yellow>"
warning.config.number.fixed.missing_value: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'value' argument for 'constant' number.</yellow>"
warning.config.number.fixed.invalid_value: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is using the invalid 'value' argument '<arg:2>' for 'constant' number.</yellow>"
warning.config.number.expression.missing_expression: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'expression' argument for 'expression' number.</yellow>"
warning.config.number.uniform.missing_min: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'min' argument for 'uniform' number.</yellow>"
warning.config.number.uniform.missing_max: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'max' argument for 'uniform' number.</yellow>"
warning.config.condition.all_of.missing_terms: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'terms' argument for 'all_of' condition.</yellow>"
warning.config.condition.all_of.invalid_terms_type: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' has a misconfigured 'all_of' condition, 'terms' should be a map list, current type: '<arg:2>'.</yellow>"
warning.config.condition.any_of.missing_terms: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'terms' argument for 'any_of' condition.</yellow>"
warning.config.condition.any_of.invalid_terms_type: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' has a misconfigured 'any_of' condition, 'terms' should be a map list, current type: '<arg:2>'.</yellow>"
warning.config.condition.inverted.missing_term: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'term' argument for 'inverted' condition.</yellow>"
warning.config.condition.inverted.invalid_term_type: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' has a misconfigured 'inverted' condition, 'term' should be a config section, current type: '<arg:2>'.</yellow>"
warning.config.condition.enchantment.missing_predicate: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'predicate' argument for 'enchantment' condition.</yellow>"
warning.config.condition.enchantment.invalid_predicate: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is using an invalid enchantment 'predicate' argument '<arg:2>'.</yellow>"
warning.config.condition.match_block_property.missing_properties: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'properties' argument for 'match_block_property' condition.</yellow>"
warning.config.condition.match_item.missing_id: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'id' argument for 'match_item' condition.</yellow>"
warning.config.condition.table_bonus.missing_enchantment: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'enchantment' argument for 'table_bonus' condition.</yellow>"
warning.config.condition.table_bonus.missing_chances: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'chances' argument for 'table_bonus' condition.</yellow>"
warning.config.structure.not_section: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is expected to be a config section while it's actually a(n) '<arg:2>'.</yellow>"
warning.config.image.duplicate: "<yellow>Issue found in file <arg:0> - Duplicated image '<arg:1>'. Please check if there is the same configuration in other files.</yellow>"
warning.config.image.missing_height: "<yellow>Issue found in file <arg:0> - The image '<arg:1>' is missing the required 'height' argument.</yellow>"
@@ -80,6 +100,7 @@ warning.config.image.invalid_font_chars: "<yellow>Issue found in file <arg:0> -
warning.config.image.missing_char: "<yellow>Issue found in file <arg:0> - The image '<arg:1>' is missing the required 'char' argument.</yellow>"
warning.config.image.codepoint_conflict: "<yellow>Issue found in file <arg:0> - The image '<arg:1>' is using a character '<arg:3>(<arg:4>)' in font <arg:2> that has been used by another image '<arg:5>'.</yellow>"
warning.config.image.invalid_codepoint_grid: "<yellow>Issue found in file <arg:0> - Image '<arg:1>' has an invalid 'chars' codepoint grid.</yellow>"
warning.config.image.invalid_char: "<yellow>Issue found in file <arg:0> - Image '<arg:1>' has a char parameter containing combining characters, which may result in image splitting.</yellow>"
warning.config.image.file_not_found: "<yellow>Issue found in file <arg:0> - PNG file '<arg:2>' not found for image '<arg:1>'.</yellow>"
warning.config.image.invalid_hex_value: "<yellow>Issue found in file <arg:0> - The image '<arg:1>' is using a unicode character '<arg:2>' that is not a valid hexadecimal (radix 16) value.</yellow>"
warning.config.recipe.duplicate: "<yellow>Issue found in file <arg:0> - Duplicated recipe '<arg:1>'. Please check if there is the same configuration in other files.</yellow>"
@@ -202,6 +223,8 @@ warning.config.block.behavior.leaves.missing_distance: "<yellow>Issue found in f
warning.config.block.behavior.sapling.missing_stage: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'stage' property for 'sapling_block' behavior.</yellow>"
warning.config.block.behavior.sapling.missing_feature: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'feature' argument for 'sapling_block' behavior.</yellow>"
warning.config.block.behavior.strippable.missing_stripped: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'stripped' argument for 'strippable_block' behavior.</yellow>"
warning.config.block.event.condition.missing_type: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'type' argument for event condition.</yellow>"
warning.config.block.event.condition.invalid_type: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is using an invalid 'type' argument '<arg:2>' for event condition.</yellow>"
warning.config.model.generation.missing_parent: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'parent' argument in 'generation' section.</yellow>"
warning.config.model.generation.conflict: "<yellow>Issue found in file <arg:0> - Failed to generate model for '<arg:1>' as two or more configurations attempt to generate different json models with the same path: '<arg:2>'.</yellow>"
warning.config.model.generation.texture.invalid: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' has a texture '<arg:2>' with path '<arg:3>' that contains illegal characters. Please read https://minecraft.wiki/w/Resource_location#Legal_characters.</yellow>"
@@ -227,10 +250,6 @@ warning.config.loot_table.entry.exp.missing_count: "<yellow>Issue found in file
warning.config.loot_table.entry.item.missing_item: "<yellow>Issue found in file <arg:0> - '<arg:1>' has a misconfigured loot table, entry 'item' is missing the required 'item' argument.</yellow>"
warning.config.loot_table.condition.missing_type: "<yellow>Issue found in file <arg:0> - '<arg:1>' has a misconfigured loot table, one of the conditions is missing the required 'type' argument.</yellow>"
warning.config.loot_table.condition.invalid_type: "<yellow>Issue found in file <arg:0> - '<arg:1>' has a misconfigured loot table, one of the conditions is using an invalid condition type '<arg:2>'.</yellow>"
warning.config.loot_table.condition.table_bonus.missing_enchantment: "<yellow>Issue found in file <arg:0> - '<arg:1>' has a misconfigured loot table, 'table_bonus' condition is missing the required 'enchantment' argument.</yellow>"
warning.config.loot_table.condition.table_bonus.missing_chances: "<yellow>Issue found in file <arg:0> - '<arg:1>' has a misconfigured loot table, 'table_bonus' condition is missing the required 'chances' argument.</yellow>"
warning.config.loot_table.number.missing_type: "<yellow>Issue found in file <arg:0> - '<arg:1>' has a misconfigured loot table, one of the numbers is missing the required 'type' argument.</yellow>"
warning.config.loot_table.number.invalid_type: "<yellow>Issue found in file <arg:0> - '<arg:1>' has a misconfigured loot table, one of the numbers is using an invalid number type '<arg:2>'.</yellow>"
warning.config.host.missing_type: "<yellow>Issue found in config.yml at 'resource-pack.delivery.hosting' - Missing required 'type' argument for host.</yellow>"
warning.config.host.invalid_type: "<yellow>Issue found in config.yml at 'resource-pack.delivery.hosting' - Host type '<arg:0>' is invalid. Please read https://mo-mi.gitbook.io/xiaomomi-plugins/craftengine/plugin-wiki/craftengine/resource-pack/host.</yellow>"
warning.config.host.external.missing_url: "<yellow>Issue found in config.yml at 'resource-pack.delivery.hosting' - Missing required 'url' argument for external host.</yellow>"
@@ -254,6 +273,7 @@ warning.config.host.s3.missing_secret: "<yellow>Issue found in config.yml at 're
warning.config.host.s3.missing_upload_path: "<yellow>Issue found in config.yml at 'resource-pack.delivery.hosting' - Missing required 'upload-path' argument for s3 host.</yellow>"
warning.config.host.self.missing_ip: "<yellow>Issue found in config.yml at 'resource-pack.delivery.hosting' - Missing required 'ip' argument for self host.</yellow>"
warning.config.host.self.invalid_port: "<yellow>Issue found in config.yml at 'resource-pack.delivery.hosting' - Invalid port '<arg:0>' for self host.</yellow>"
warning.config.host.self.invalid_url: "<yellow>Issue found in config.yml at 'resource-pack.delivery.hosting' - Invalid url '<arg:0>' for self host.</yellow>"
warning.config.host.gitlab.missing_url: "<yellow>Issue found in config.yml at 'resource-pack.delivery.hosting' - Missing required 'gitlab-url' argument for gitlab host.</yellow>"
warning.config.host.gitlab.missing_token: "<yellow>Issue found in config.yml at 'resource-pack.delivery.hosting' - Missing required 'access-token' argument for gitlab host.</yellow>"
warning.config.host.gitlab.missing_project: "<yellow>Issue found in config.yml at 'resource-pack.delivery.hosting' - Missing required 'project-id' argument for gitlab host.</yellow>"
@@ -273,4 +293,5 @@ warning.config.conflict_matcher.inverted.missing_term: "<yellow>Issue found in c
warning.config.conflict_matcher.all_of.missing_terms: "<yellow>Issue found in config.yml at 'resource-pack.duplicated-files-handler' - Missing required 'terms' argument for 'all_of' matcher.</yellow>"
warning.config.conflict_matcher.any_of.missing_terms: "<yellow>Issue found in config.yml at 'resource-pack.duplicated-files-handler' - Missing required 'terms' argument for 'any_of' matcher.</yellow>"
warning.config.conflict_resolution.missing_type: "<yellow>Issue found in config.yml at 'resource-pack.duplicated-files-handler' - Missing required 'type' argument for one of the resolutions.</yellow>"
warning.config.conflict_resolution.invalid_type: "<yellow>Issue found in config.yml at 'resource-pack.duplicated-files-handler' - One of the resolutions is using the invalid type '<arg:0>'.</yellow>"
warning.config.conflict_resolution.invalid_type: "<yellow>Issue found in config.yml at 'resource-pack.duplicated-files-handler' - One of the resolutions is using the invalid type '<arg:0>'.</yellow>"
warning.config.function.command.missing_command: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'command' argument for 'command' function.</yellow>"

View File

@@ -1,6 +1,6 @@
# Don't change this
lang-version: "${lang_version}"
# Commands
exception.invalid_syntax: "<red>Geçersiz sözdizimi. Doğru kullanım: <white><arg:0></white></red>"
exception.invalid_argument: "<red>Geçersiz argüman. Neden: <white><arg:0></white></red>"
exception.invalid_sender: "<red><arg:0> bu komutu çalıştırmaya yetkili değil. <arg:1> türünde olmalı</red>"
@@ -226,10 +226,6 @@ warning.config.loot_table.entry.exp.missing_count: "<yellow><arg:0> dosyasında
warning.config.loot_table.entry.item.missing_item: "<yellow><arg:0> dosyasında sorun bulundu - '<arg:1>', yanlış yapılandırılmış bir ganimet tablosuna sahip, 'item' girişi için gerekli 'item' argümanı eksik.</yellow>"
warning.config.loot_table.condition.missing_type: "<yellow><arg:0> dosyasında sorun bulundu - '<arg:1>', yanlış yapılandırılmış bir ganimet tablosuna sahip, koşullardan biri için gerekli 'type' argümanı eksik.</yellow>"
warning.config.loot_table.condition.invalid_type: "<yellow><arg:0> dosyasında sorun bulundu - '<arg:1>', yanlış yapılandırılmış bir ganimet tablosuna sahip, koşullardan biri geçersiz bir koşul türü '<arg:2>' kullanıyor.</yellow>"
warning.config.loot_table.condition.table_bonus.missing_enchantment: "<yellow><arg:0> dosyasında sorun bulundu - '<arg:1>', yanlış yapılandırılmış bir ganimet tablosuna sahip, 'table_bonus' koşulu için gerekli 'enchantment' argümanı eksik.</yellow>"
warning.config.loot_table.condition.table_bonus.missing_chances: "<yellow><arg:0> dosyasında sorun bulundu - '<arg:1>', yanlış yapılandırılmış bir ganimet tablosuna sahip, 'table_bonus' koşulu için gerekli 'chances' argümanı eksik.</yellow>"
warning.config.loot_table.number.missing_type: "<yellow><arg:0> dosyasında sorun bulundu - '<arg:1>', yanlış yapılandırılmış bir ganimet tablosuna sahip, sayılardan biri için gerekli 'type' argümanı eksik.</yellow>"
warning.config.loot_table.number.invalid_type: "<yellow><arg:0> dosyasında sorun bulundu - '<arg:1>', yanlış yapılandırılmış bir ganimet tablosuna sahip, sayılardan biri geçersiz bir sayı türü '<arg:2>' kullanıyor.</yellow>"
warning.config.host.missing_type: "<yellow>config.yml dosyasında 'resource-pack.delivery.hosting' bölümünde sorun bulundu - Host için gerekli 'type' argümanı eksik.</yellow>"
warning.config.host.invalid_type: "<yellow>config.yml dosyasında 'resource-pack.delivery.hosting' bölümünde sorun bulundu - Host türü '<arg:0>' geçersiz. Lütfen https://mo-mi.gitbook.io/xiaomomi-plugins/craftengine/plugin-wiki/craftengine/resource-pack/host sayfasını okuyun.</yellow>"
warning.config.host.external.missing_url: "<yellow>config.yml dosyasında 'resource-pack.delivery.hosting' bölümünde sorun bulundu - Harici host için gerekli 'url' argümanı eksik.</yellow>"
@@ -272,4 +268,4 @@ warning.config.conflict_matcher.inverted.missing_term: "<yellow>config.yml dosya
warning.config.conflict_matcher.all_of.missing_terms: "<yellow>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.</yellow>"
warning.config.conflict_matcher.any_of.missing_terms: "<yellow>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.</yellow>"
warning.config.conflict_resolution.missing_type: "<yellow>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.</yellow>"
warning.config.conflict_resolution.invalid_type: "<yellow>config.yml dosyasında 'resource-pack.duplicated-files-handler' bölümünde sorun bulundu - Çözümlerden biri geçersiz bir tür '<arg:0>' kullanıyor.</yellow>"
warning.config.conflict_resolution.invalid_type: "<yellow>config.yml dosyasında 'resource-pack.duplicated-files-handler' bölümünde sorun bulundu - Çözümlerden biri geçersiz bir tür '<arg:0>' kullanıyor.</yellow>"

View File

@@ -1,7 +1,6 @@
# 别动这个
lang-version: "${lang_version}"
# 命令
exception.invalid_syntax: "<red>无效语法. 正确语法: <white><arg:0></white></red>"
exception.invalid_argument: "<red>无效参数. 原因: <white><arg:0></white></red>"
exception.invalid_sender: "<red><arg:0> 不允许执行该命令. 执行者必须是 <arg:1></red>"
@@ -40,11 +39,11 @@ argument.parse.failure.aggregate.failure: "<red>无效的组件 '<arg:0>': <arg:
argument.parse.failure.either: "<red>无法从 '<arg:0>' 解析 <arg:1> 或 <arg:2></red>"
argument.parse.failure.namedtextcolor: "<red>'<arg:0>' 不是颜色代码</red>"
command.reload.config.success: "<white>重新加载配置完成. 耗时 <green><arg:0></green> 毫秒</white> <gray>(异步: <arg:1>ms | 同步: <arg:2>ms)</gray>"
command.reload.config.failure: "<red>重新加载配置失败请检查控制台日志</red>"
command.reload.config.failure: "<red>重新加载配置失败, 请检查控制台日志</red>"
command.reload.pack.success: "<white>资源包重新加载完成. 耗时 <green><arg:0></green> 毫秒</white>"
command.reload.pack.failure: "<red>重新加载资源包失败请检查控制台日志</red>"
command.reload.pack.failure: "<red>重新加载资源包失败, 请检查控制台日志</red>"
command.reload.all.success: "<white>全部重新加载完成. 耗时 <green><arg:0></green> 毫秒</white> <gray>(异步: <arg:1>ms | 同步: <arg:2>ms | 资源包: <arg:3>ms)</gray>"
command.reload.all.failure: "<red>重新加载失败请检查控制台日志</red>"
command.reload.all.failure: "<red>重新加载失败, 请检查控制台日志</red>"
command.item.get.success: "<white>获得<arg:0>个<arg:1></white>"
command.item.get.failure.not_exist: "<red><lang:argument.item.id.invalid:'<arg:0>'></red>"
command.item.give.success.single: "<lang:commands.give.success.single:'<arg:0>':'<arg:1>':'<arg:2>'>"
@@ -70,6 +69,27 @@ warning.config.type.float: "<yellow>在文件 <arg:0> 发现问题 - 无法加
warning.config.type.double: "<yellow>在文件 <arg:0> 发现问题 - 无法加载 '<arg:1>': 无法将 '<arg:2>' 转换为双精度类型 (选项 '<arg:3>')</yellow>"
warning.config.type.quaternionf: "<yellow>在文件 <arg:0> 发现问题 - 无法加载 '<arg:1>': 无法将 '<arg:2>' 转换为四元数类型 (选项 '<arg:3>')</yellow>"
warning.config.type.vector3f: "<yellow>在文件 <arg:0> 发现问题 - 无法加载 '<arg:1>': 无法将 '<arg:2>' 转换为三维向量类型 (选项 '<arg:3>')</yellow>"
warning.config.number.missing_type: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少数字类型所需的 'type' 参数</yellow>"
warning.config.number.invalid_type: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 使用了无效的数字类型 '<arg:2>'</yellow>"
warning.config.number.missing_argument: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少数字参数</yellow>"
warning.config.number.invalid_format: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 使用了无效的数字格式 '<arg:2>'</yellow>"
warning.config.number.fixed.missing_value: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少 'constant' 数字类型所需的 'value' 参数</yellow>"
warning.config.number.fixed.invalid_value: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 使用了无效的常量值参数 '<arg:2>'</yellow>"
warning.config.number.expression.missing_expression: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少 'expression' 数字类型所需的 'expression' 参数</yellow>"
warning.config.number.uniform.missing_min: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少 'uniform' 数字类型所需的 'min' 参数</yellow>"
warning.config.number.uniform.missing_max: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少 'uniform' 数字类型所需的 'max' 参数</yellow>"
warning.config.condition.all_of.missing_terms: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少 'all_of' 条件所需的 'terms' 参数</yellow>"
warning.config.condition.all_of.invalid_terms_type: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 的 'all_of' 条件配置错误, 'terms' 应为映射列表, 当前类型: '<arg:2>'</yellow>"
warning.config.condition.any_of.missing_terms: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少 'any_of' 条件所需的 'terms' 参数</yellow>"
warning.config.condition.any_of.invalid_terms_type: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 的 'any_of' 条件配置错误, 'terms' 应为映射列表, 当前类型: '<arg:2>'</yellow>"
warning.config.condition.inverted.missing_term: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少 'inverted' 条件所需的 'term' 参数</yellow>"
warning.config.condition.inverted.invalid_term_type: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 的 'inverted' 条件配置错误, 'term' 应为配置节点, 当前类型: '<arg:2>'</yellow>"
warning.config.condition.enchantment.missing_predicate: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少 'enchantment' 条件所需的 'predicate' 参数</yellow>"
warning.config.condition.enchantment.invalid_predicate: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 使用了无效的附魔 'predicate' 参数 '<arg:2>'</yellow>"
warning.config.condition.match_block_property.missing_properties: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少 'match_block_property' 条件所需的 'properties' 参数</yellow>"
warning.config.condition.match_item.missing_id: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少 'match_item' 条件所需的 'id' 参数</yellow>"
warning.config.condition.table_bonus.missing_enchantment: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少 'table_bonus' 条件所需的 'enchantment' 参数</yellow>"
warning.config.condition.table_bonus.missing_chances: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少 'table_bonus' 条件所需的 'chances' 参数</yellow>"
warning.config.structure.not_section: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 应为配置段落 但实际类型为 '<arg:2>'</yellow>"
warning.config.image.duplicate: "<yellow>在文件 <arg:0> 发现问题 - 重复的图片配置 '<arg:1>' 请检查其他文件中是否存在相同配置</yellow>"
warning.config.image.missing_height: "<yellow>在文件 <arg:0> 发现问题 - 图片 '<arg:1>' 缺少必需的 'height' 参数</yellow>"
@@ -80,6 +100,7 @@ warning.config.image.invalid_font_chars: "<yellow>在文件 <arg:0> 发现问题
warning.config.image.missing_char: "<yellow>在文件 <arg:0> 发现问题 - 图片 '<arg:1>' 缺少必需的 'char' 参数</yellow>"
warning.config.image.codepoint_conflict: "<yellow>在文件 <arg:0> 发现问题 - 图片 '<arg:1>' 在字体 <arg:2> 中使用的字符 '<arg:3>(<arg:4>)' 已被其他图片 '<arg:5>' 占用</yellow>"
warning.config.image.invalid_codepoint_grid: "<yellow>在文件 <arg:0> 发现问题 - 图片 '<arg:1>' 的 'chars' 码位网格无效</yellow>"
warning.config.image.invalid_char: "<yellow>在文件 <arg:0> 发现问题 - 图片 '<arg:1>' 的 'char' 参数包含组合字符可能导致图片分裂</yellow>"
warning.config.image.file_not_found: "<yellow>在文件 <arg:0> 发现问题 - 图片 '<arg:1>' 的 PNG 文件 '<arg:2>' 未找到</yellow>"
warning.config.image.invalid_hex_value: "<yellow>在文件 <arg:0> 发现问题 - 图片 '<arg:1>' 使用的 Unicode 字符 '<arg:2>' 不是有效的十六进制值</yellow>"
warning.config.recipe.duplicate: "<yellow>在文件 <arg:0> 发现问题 - 重复的配方 '<arg:1>' 请检查其他文件中是否存在相同配置</yellow>"
@@ -202,6 +223,8 @@ warning.config.block.behavior.leaves.missing_distance: "<yellow>在文件 <arg:0
warning.config.block.behavior.sapling.missing_stage: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 的 'sapling_block' 行为缺少必需的 'stage' 属性</yellow>"
warning.config.block.behavior.sapling.missing_feature: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 的 'sapling_block' 行为缺少必需的 'feature' 参数</yellow>"
warning.config.block.behavior.strippable.missing_stripped: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 的 'strippable_block' 行为缺少必需的 'stripped' 参数</yellow>"
warning.config.block.event.condition.missing_type: "<yellow>在文件 <arg:0> - 方块 '<arg:1>' 的事件条件缺少 'type' 参数</yellow>"
warning.config.block.event.condition.invalid_type: "<yellow>在文件 <arg:0> - 方块 '<arg:1>' 使用了无效的事件条件类型 '<arg:2>'</yellow>"
warning.config.model.generation.missing_parent: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 的 'generation' 段落缺少必需的 'parent' 参数</yellow>"
warning.config.model.generation.conflict: "<yellow>在文件 <arg:0> 发现问题 - 无法为 '<arg:1>' 生成模型 存在多个配置尝试使用相同路径 '<arg:2>' 生成不同的 JSON 模型</yellow>"
warning.config.model.generation.texture.invalid: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 的纹理 '<arg:2>' 路径 '<arg:3>' 包含非法字符 请参考 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</yellow>"
@@ -227,10 +250,6 @@ warning.config.loot_table.entry.exp.missing_count: "<yellow>在文件 <arg:0>
warning.config.loot_table.entry.item.missing_item: "<yellow>在文件 <arg:0> 发现问题 - '<arg:1>' 的战利品表配置错误 'item' 条目缺少必需的 'item' 参数</yellow>"
warning.config.loot_table.condition.missing_type: "<yellow>在文件 <arg:0> 发现问题 - '<arg:1>' 的战利品表配置错误 某个条件缺少必需的 'type' 参数</yellow>"
warning.config.loot_table.condition.invalid_type: "<yellow>在文件 <arg:0> 发现问题 - '<arg:1>' 的战利品表配置错误 某个条件使用了无效的条件类型 '<arg:2>'</yellow>"
warning.config.loot_table.condition.table_bonus.missing_enchantment: "<yellow>在文件 <arg:0> 发现问题 - '<arg:1>' 的战利品表配置错误 'table_bonus' 条件缺少必需的 'enchantment' 参数</yellow>"
warning.config.loot_table.condition.table_bonus.missing_chances: "<yellow>在文件 <arg:0> 发现问题 - '<arg:1>' 的战利品表配置错误 'table_bonus' 条件缺少必需的 'chances' 参数</yellow>"
warning.config.loot_table.number.missing_type: "<yellow>在文件 <arg:0> 发现问题 - '<arg:1>' 的战利品表配置错误 某个数值缺少必需的 'type' 参数</yellow>"
warning.config.loot_table.number.invalid_type: "<yellow>在文件 <arg:0> 发现问题 - '<arg:1>' 的战利品表配置错误 某个数值使用了无效的数值类型 '<arg:2>'</yellow>"
warning.config.host.missing_type: "<yellow>在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - 缺少必需的 'type' 参数</yellow>"
warning.config.host.invalid_type: "<yellow>在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - 无效的托管类型 '' 请参考 https://mo-mi.gitbook.io/xiaomomi-plugins/craftengine/plugin-wiki/craftengine/resource-pack/host</yellow>"
warning.config.host.external.missing_url: "<yellow>在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - 外部托管缺少必需的 'url' 参数</yellow>"
@@ -254,6 +273,7 @@ warning.config.host.s3.missing_secret: "<yellow>在 config.yml 的 'resource-pac
warning.config.host.s3.missing_upload_path: "<yellow>在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - S3 托管缺少必需的 'upload-path' 参数</yellow>"
warning.config.host.self.missing_ip: "<yellow>在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - 自托管托管缺少必需的 'ip' 参数</yellow>"
warning.config.host.self.invalid_port: "<yellow>在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - 自托管托管的端口 '<arg:0>' 无效</yellow>"
warning.config.host.self.invalid_url: "<yellow>在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - 自托管托管的 URL '<arg:0>' 无效</yellow>"
warning.config.host.gitlab.missing_url: "<yellow>在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - GitLab 托管缺少必需的 'gitlab-url' 参数</yellow>"
warning.config.host.gitlab.missing_token: "<yellow>在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - GitLab 托管缺少必需的 'access-token' 参数</yellow>"
warning.config.host.gitlab.missing_project: "<yellow>在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - GitLab 托管缺少必需的 'project-id' 参数</yellow>"

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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<Item<ItemStack>> items = lootTable.getRandomItems(builder.build(), world);
List<Item<ItemStack>> items = lootTable.getRandomItems(builder.build(), world, player);
for (Item<ItemStack> item : items) {
world.dropItemNaturally(vec3d, item);
}

View File

@@ -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<Object> 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<Object> 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<Object> item : state.getDrops(builder, world)) {
for (Item<Object> item : state.getDrops(builder, world, null)) {
world.dropItemNaturally(vec3d, item);
}
world.playBlockSound(vec3d, state.sounds().breakSound());

View File

@@ -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 {

View File

@@ -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<Object> item : immutableBlockState.getDrops(builder, world)) {
builder.withParameter(CommonParameters.LOCATION, vec3d);
builder.withParameter(CommonParameters.WORLD, world);
for (Item<Object> item : immutableBlockState.getDrops(builder, world, null)) {
world.dropItemNaturally(vec3d, item);
}
Object entityData = Reflections.field$Entity$entityData.get(fallingBlockEntity);

View File

@@ -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<Object> item : previousState.getDrops(builder, world)) {
builder.withParameter(CommonParameters.LOCATION, vec3d);
builder.withParameter(CommonParameters.WORLD, world);
for (Item<Object> item : previousState.getDrops(builder, world, null)) {
world.dropItemNaturally(vec3d, item);
}
world.playBlockSound(vec3d, previousState.sounds().breakSound());

View File

@@ -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);
}

View File

@@ -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<Object> item : immutableBlockState.getDrops(builder, world)) {
builder.withParameter(CommonParameters.LOCATION, vec3d);
builder.withParameter(CommonParameters.WORLD, world);
for (Item<Object> item : immutableBlockState.getDrops(builder, world, null)) {
world.dropItemNaturally(vec3d, item);
}
Object entityData = Reflections.field$Entity$entityData.get(fallingBlockEntity);

View File

@@ -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<Object> item : immutableBlockState.getDrops(builder, world)) {
.withParameter(CommonParameters.LOCATION, vec3d)
.withParameter(CommonParameters.WORLD, world);
for (Item<Object> item : immutableBlockState.getDrops(builder, world, null)) {
world.dropItemNaturally(vec3d, item);
}
}

View File

@@ -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<Object> item : currentState.getDrops(builder, world)) {
.withParameter(CommonParameters.LOCATION, vec3d)
.withParameter(CommonParameters.WORLD, world);
for (Item<Object> item : currentState.getDrops(builder, world, null)) {
world.dropItemNaturally(vec3d, item);
}
world.playBlockSound(vec3d, currentState.sounds().breakSound());

View File

@@ -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());
}
}

View File

@@ -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;

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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)) {

View File

@@ -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;

View File

@@ -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<ItemStack> newItem = customItem.buildItem(ItemBuildContext.of(plugin.adapt(player), ContextHolder.EMPTY));
Item<ItemStack> newItem = customItem.buildItem(ItemBuildContext.of(plugin.adapt(player)));
int remainingDurability = totalMaxDamage - totalDamage;
int newItemDamage = Math.max(0, newItem.maxDamage().get() - remainingDurability);
newItem.damage(newItemDamage);

View File

@@ -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);
}
}

View File

@@ -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) {

View File

@@ -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);
}
}

View File

@@ -46,6 +46,7 @@ public class BukkitCommandManager extends AbstractCommandManager<CommandSender>
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),

View File

@@ -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<BukkitCraftEngine, Comman
@Override
protected void sendMessage(CommandSender sender, Component message) {
// we can safely send async for players and the console - otherwise, send it sync
if (sender instanceof Player || sender instanceof ConsoleCommandSender || sender instanceof RemoteConsoleCommandSender) {
if (sender instanceof Player player) {
FastNMS.INSTANCE.sendPacket(FastNMS.INSTANCE.method$CraftPlayer$getHandle(player), FastNMS.INSTANCE.constructor$ClientboundSystemChatPacket(ComponentUtils.adventureToMinecraft(message), false));
} else if (sender instanceof ConsoleCommandSender || sender instanceof RemoteConsoleCommandSender) {
audience(sender).sendMessage(message);
} else {
plugin().scheduler().executeSync(() -> audience(sender).sendMessage(message));

View File

@@ -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<CommandSender> {
public DebugIsSectionInjectedCommand(CraftEngineCommandManager<CommandSender> commandManager, CraftEngine plugin) {
super(commandManager, plugin);
}
@Override
public Command.Builder<? extends CommandSender> assembleCommand(org.incendo.cloud.CommandManager<CommandSender> manager, Command.Builder<CommandSender> 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";
}
}

View File

@@ -68,7 +68,6 @@ public class ReloadCommand extends BukkitCommandFeature<CommandSender> {
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);

View File

@@ -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<CommandSender> {
@@ -19,9 +21,11 @@ public class TestCommand extends BukkitCommandFeature<CommandSender> {
public Command.Builder<? extends CommandSender> assembleCommand(org.incendo.cloud.CommandManager<CommandSender> manager, Command.Builder<CommandSender> 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 = "<red><arg:1:0912012><papi:player_name></red>";
PlayerOptionalContext context1 = PlayerOptionalContext.of(plugin().adapt(context.sender()), ContextHolder.builder());
plugin().senderFactory().wrap(context.sender()).sendMessage(AdventureHelper.customMiniMessage().deserialize(text, context1.tagResolvers()));
});
}

View File

@@ -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<Object> 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<Object> 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<SectionPos> 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<SectionPos> posSet = SectionPosUtils.calculateAffectedRegions((sectionPos.x() << 4) + x, (sectionPos.y() << 4) + y, (sectionPos.z() << 4) + z, Math.max(newLight, previousLight));
world.sectionLightUpdated(posSet);
}
}

View File

@@ -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<Integer, long[]> 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<String, Integer> eitherVisibility;
Either<String, Integer> 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<NetWorkUser, NMSPacketEvent, Object> 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<NetWorkUser, ByteBufPacketEvent> ADD_ENTITY_BYTEBUFFER = (user, event) -> {

View File

@@ -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());
}
}
}

View File

@@ -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);
};
}

View File

@@ -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
);

View File

@@ -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<ItemStack> item = (Item<ItemStack>) 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;
}
}

View File

@@ -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

View File

@@ -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")

View File

@@ -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")
}
}

View File

@@ -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<Item<Object>> getDrops(@NotNull ContextHolder.Builder builder, @NotNull World world) {
return this.getDrops(builder, world, null);
}
@SuppressWarnings("unchecked")
public List<Item<Object>> getDrops(ContextHolder.Builder builder, World world) {
public List<Item<Object>> getDrops(@NotNull ContextHolder.Builder builder, @NotNull World world, @Nullable Player player) {
CustomBlock block = owner.value();
if (block == null) return List.of();
LootTable<Object> lootTable = (LootTable<Object>) 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);
}
}

View File

@@ -14,6 +14,10 @@ public class UpdateOption {
return flags;
}
public static Builder builder() {
return new Builder();
}
public static class Builder {
private int flags;

View File

@@ -27,7 +27,7 @@ public class BlockBehaviors {
public static BlockBehavior fromMap(CustomBlock block, @Nullable Map<String, Object> 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());

View File

@@ -33,7 +33,7 @@ public class Properties {
public static Property<?> fromMap(String name, Map<String, Object> 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);

View File

@@ -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();

View File

@@ -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;
}
}

View File

@@ -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()));
}
}
}
}

View File

@@ -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<String> KEYWORD = new ContextKey<>(Key.of("keyword"));
public static final ContextKey<String> EMOJI = new ContextKey<>(Key.of("emoji"));
public final class EmojiParameters {
private EmojiParameters() {}
public static final ContextKey<String> KEYWORD = ContextKey.of("keyword");
public static final ContextKey<String> EMOJI = ContextKey.of("emoji");
}

View File

@@ -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<I> {

View File

@@ -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<I> extends BuildableItem<I> {
}
default Item<I> buildItem(Player player) {
return buildItem(ItemBuildContext.of(player, ContextHolder.EMPTY));
return buildItem(ItemBuildContext.of(player));
}
Item<I> buildItem(ItemBuildContext context);

View File

@@ -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)));
}
}

View File

@@ -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<ItemBehaviorFactory> holder = ((WritableRegistry<ItemBehaviorFactory>) BuiltInRegistries.ITEM_BEHAVIOR_FACTORY)
@@ -25,7 +25,7 @@ public class ItemBehaviors {
public static ItemBehavior fromMap(Pack pack, Path path, Key id, Map<String, Object> 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());

View File

@@ -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) {

View File

@@ -184,16 +184,16 @@ public class CustomSmithingTransformRecipe<T> implements Recipe<T> {
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<ItemDataProcessor.Factory> holder = ((WritableRegistry<ItemDataProcessor.Factory>) BuiltInRegistries.SMITHING_RESULT_PROCESSOR_FACTORY)
public static void register(Key key, ItemDataProcessor.ProcessorFactory factory) {
Holder.Reference<ItemDataProcessor.ProcessorFactory> holder = ((WritableRegistry<ItemDataProcessor.ProcessorFactory>) 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<T> implements Recipe<T> {
Key type();
interface Factory {
interface ProcessorFactory {
ItemDataProcessor create(Map<String, Object> arguments);
}
}
@@ -231,7 +231,7 @@ public class CustomSmithingTransformRecipe<T> implements Recipe<T> {
return ItemDataProcessors.KEEP_COMPONENTS;
}
public static class Factory implements ItemDataProcessor.Factory {
public static class Factory implements ProcessorFactory {
@Override
public ItemDataProcessor create(Map<String, Object> arguments) {
@@ -268,7 +268,7 @@ public class CustomSmithingTransformRecipe<T> implements Recipe<T> {
return ItemDataProcessors.KEEP_TAGS;
}
public static class Factory implements ItemDataProcessor.Factory {
public static class Factory implements ProcessorFactory {
@Override
public ItemDataProcessor create(Map<String, Object> arguments) {

View File

@@ -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<LootContext> factory) {
Holder.Reference<ConditionFactory<LootContext>> holder = ((WritableRegistry<ConditionFactory<LootContext>>) BuiltInRegistries.LOOT_CONDITION_FACTORY)
.registerForHolder(new ResourceKey<>(Registries.LOOT_CONDITION_FACTORY.location(), key));
holder.bindValue(factory);
}
public static <T> Predicate<T> andConditions(List<? extends Predicate<T>> predicates) {
List<Predicate<T>> 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<T> predicate : list) {
if (!predicate.test(ctx)) {
return false;
}
}
return true;
});
};
}
public static <T> Predicate<T> orConditions(List<? extends Predicate<T>> predicates) {
List<Predicate<T>> 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<T> predicate : list) {
if (predicate.test(ctx)) {
return true;
}
}
return false;
});
};
}
public static List<Condition<LootContext>> fromMapList(List<Map<String, Object>> mapList) {
if (mapList == null || mapList.isEmpty()) return List.of();
List<Condition<LootContext>> functions = new ArrayList<>();
for (Map<String, Object> map : mapList) {
functions.add(fromMap(map));
}
return functions;
}
public static Condition<LootContext> fromMap(Map<String, Object> 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<LootContext> 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<LootContext> 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);
}
}
}

View File

@@ -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 <T> Optional<T> getOptionalParameter(ContextKey<T> parameter) {
return this.contexts.getOptional(parameter);
}
public boolean hasParameter(ContextKey<?> parameter) {
return this.contexts.has(parameter);
}
public <T> T getParameterOrThrow(ContextKey<T> 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;
}
}

View File

@@ -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<T> {
private final List<LootEntryContainer<T>> entryContainers;
private final List<LootCondition> conditions;
private final List<Condition<LootContext>> conditions;
private final Predicate<LootContext> compositeCondition;
private final List<LootFunction<T>> functions;
private final BiFunction<Item<T>, LootContext, Item<T>> compositeFunction;
private final NumberProvider rolls;
private final NumberProvider bonusRolls;
public LootPool(List<LootEntryContainer<T>> entryContainers, List<LootCondition> conditions, List<LootFunction<T>> functions, NumberProvider rolls, NumberProvider bonusRolls) {
public LootPool(List<LootEntryContainer<T>> entryContainers, List<Condition<LootContext>> conditions, List<LootFunction<T>> functions, NumberProvider rolls, NumberProvider bonusRolls) {
this.entryContainers = entryContainers;
this.conditions = conditions;
this.functions = functions;
@@ -38,7 +37,7 @@ public class LootPool<T> {
}
public void addRandomItems(Consumer<Item<T>> lootConsumer, LootContext context) {
for (LootCondition condition : this.conditions) {
for (Condition<LootContext> condition : this.conditions) {
if (!condition.test(context)) {
return;
}
@@ -62,7 +61,6 @@ public class LootPool<T> {
}
private void addRandomItem(Consumer<Item<T>> lootConsumer, LootContext context) {
Random randomSource = context.randomSource();
List<LootEntry<T>> list = Lists.newArrayList();
MutableInt mutableInt = new MutableInt(0);
for (LootEntryContainer<T> lootPoolEntryContainer : this.entryContainers) {
@@ -79,7 +77,7 @@ public class LootPool<T> {
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<T> loot : list) {
j -= loot.getWeight(context.luck());
if (j < 0) {

View File

@@ -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<T> {
Map<String, Object> pool = MiscUtils.castToMap(rawPoolMap, false);
NumberProvider rolls = NumberProviders.fromObject(pool.getOrDefault("rolls", 1));
NumberProvider bonus_rolls = NumberProviders.fromObject(pool.getOrDefault("bonus_rolls", 0));
List<LootCondition> conditions = Optional.ofNullable(pool.get("conditions"))
List<Condition<LootContext>> 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<T> {
}
public ArrayList<Item<T>> getRandomItems(ContextHolder parameters, World world) {
return this.getRandomItems(new LootContext(world, parameters, ThreadLocalRandom.current(), 1));
return this.getRandomItems(parameters, world, null);
}
public ArrayList<Item<T>> getRandomItems(ContextHolder parameters, World world, @Nullable Player player) {
return this.getRandomItems(new LootContext(world, player, player == null ? 1f : (float) player.luck(), parameters));
}
private ArrayList<Item<T>> getRandomItems(LootContext context) {

View File

@@ -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<LootCondition> conditions;
public AllOfCondition(List<LootCondition> 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<String, Object> arguments) {
List<Map<String, Object>> terms = (List<Map<String, Object>>) arguments.get("terms");
return new AllOfCondition(LootConditions.fromMapList(terms));
}
}
}

View File

@@ -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<LootCondition> conditions;
public AnyOfCondition(List<LootCondition> 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<String, Object> arguments) {
List<Map<String, Object>> terms = (List<Map<String, Object>>) arguments.get("terms");
return new AnyOfCondition(LootConditions.fromMapList(terms));
}
}
}

View File

@@ -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<Integer, Boolean> expression;
public EnchantmentCondition(Key id, Function<Integer, Boolean> expression) {
this.id = id;
this.expression = expression;
}
@Override
public Key type() {
return LootConditions.ENCHANTMENT;
}
@Override
public boolean test(LootContext lootContext) {
Optional<Item<?>> item = lootContext.getOptionalParameter(LootParameters.TOOL);
if (item.isEmpty()) return false;
Optional<Enchantment> 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<String, Object> 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<Integer, Boolean> 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);
}
}
}

View File

@@ -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<String, Object> arguments) {
return INSTANCE;
}
}
}

View File

@@ -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<String, Object> arguments) {
Map<String, Object> term = (Map<String, Object>) arguments.get("term");
return new InvertedCondition(LootConditions.fromMap(term));
}
}
}

View File

@@ -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<LootContext> {
Key type();
}

View File

@@ -1,8 +0,0 @@
package net.momirealms.craftengine.core.loot.condition;
import java.util.Map;
public interface LootConditionFactory {
LootCondition create(Map<String, Object> arguments);
}

View File

@@ -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<LootConditionFactory> holder = ((WritableRegistry<LootConditionFactory>) BuiltInRegistries.LOOT_CONDITION_FACTORY)
.registerForHolder(new ResourceKey<>(Registries.LOOT_CONDITION_FACTORY.location(), key));
holder.bindValue(factory);
}
public static <T> Predicate<T> andConditions(List<? extends Predicate<T>> predicates) {
List<Predicate<T>> 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<T> predicate : list) {
if (!predicate.test(ctx)) {
return false;
}
}
return true;
});
};
}
public static <T> Predicate<T> orConditions(List<? extends Predicate<T>> predicates) {
List<Predicate<T>> 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<T> predicate : list) {
if (predicate.test(ctx)) {
return true;
}
}
return false;
});
};
}
public static List<LootCondition> fromMapList(List<Map<String, Object>> mapList) {
if (mapList == null || mapList.isEmpty()) return List.of();
List<LootCondition> functions = new ArrayList<>();
for (Map<String, Object> map : mapList) {
functions.add(fromMap(map));
}
return functions;
}
public static LootCondition fromMap(Map<String, Object> 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);
}
}

View File

@@ -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<String, Object> arguments) {
float chance = ResourceConfigUtils.getAsFloat(arguments.getOrDefault("value", 0.5f), "value");
return new RandomCondition(chance);
}
}
}

View File

@@ -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<Float> 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<String, Object> arguments) {
return INSTANCE;
}
}
}

View File

@@ -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<T> extends AbstractLoo
protected final List<LootEntryContainer<T>> children;
private final LootEntryContainer<T> composedChildren;
protected AbstractCompositeLootEntryContainer(List<LootCondition> conditions, List<LootEntryContainer<T>> children) {
protected AbstractCompositeLootEntryContainer(List<Condition<LootContext>> conditions, List<LootEntryContainer<T>> children) {
super(conditions);
this.children = children;
this.composedChildren = compose(children);

View File

@@ -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<T> implements LootEntryContainer<T>, Predicate<LootContext> {
protected final List<LootCondition> conditions;
protected final List<Condition<LootContext>> conditions;
private final Predicate<LootContext> compositeCondition;
protected AbstractLootEntryContainer(List<LootCondition> conditions) {
protected AbstractLootEntryContainer(List<Condition<LootContext>> conditions) {
this.conditions = conditions;
this.compositeCondition = MCUtils.allOf(conditions);
}

View File

@@ -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<T> extends AbstractLootEn
}
};
protected AbstractSingleLootEntryContainer(List<LootCondition> conditions, List<LootFunction<T>> functions, int weight, int quality) {
protected AbstractSingleLootEntryContainer(List<Condition<LootContext>> conditions, List<LootFunction<T>> functions, int weight, int quality) {
super(conditions);
this.weight = weight;
this.quality = quality;

View File

@@ -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<T> extends AbstractCompositeLootEntryContainer<T> {
public static final Factory<?> FACTORY = new Factory<>();
protected AlternativesLootEntryContainer(List<LootCondition> conditions, List<LootEntryContainer<T>> children) {
protected AlternativesLootEntryContainer(List<Condition<LootContext>> conditions, List<LootEntryContainer<T>> children) {
super(conditions, children);
}
@@ -42,7 +43,7 @@ public class AlternativesLootEntryContainer<T> extends AbstractCompositeLootEntr
List<LootEntryContainer<A>> containers = Optional.ofNullable(arguments.get("children"))
.map(it -> (List<LootEntryContainer<A>>) new ArrayList<LootEntryContainer<A>>(LootEntryContainers.fromMapList((List<Map<String, Object>>) it)))
.orElse(Collections.emptyList());
List<LootCondition> conditions = Optional.ofNullable(arguments.get("conditions"))
List<Condition<LootContext>> conditions = Optional.ofNullable(arguments.get("conditions"))
.map(it -> LootConditions.fromMapList((List<Map<String, Object>>) it))
.orElse(Collections.emptyList());
return new AlternativesLootEntryContainer<>(conditions, containers);

View File

@@ -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<T> extends AbstractLootEntryContainer<T> {
public static final Factory<?> FACTORY = new Factory<>();
private final NumberProvider value;
protected ExpLootEntryContainer(NumberProvider value, List<LootCondition> conditions) {
protected ExpLootEntryContainer(NumberProvider value, List<Condition<LootContext>> conditions) {
super(conditions);
this.value = value;
}
@@ -32,8 +32,8 @@ public class ExpLootEntryContainer<T> extends AbstractLootEntryContainer<T> {
@Override
public boolean expand(LootContext context, Consumer<LootEntry<T>> 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<T> extends AbstractLootEntryContainer<T> {
@Override
public LootEntryContainer<A> create(Map<String, Object> arguments) {
Object value = ResourceConfigUtils.requireNonNullOrThrow(arguments.get("count"), "warning.config.loot_table.entry.exp.missing_count");
List<LootCondition> conditions = Optional.ofNullable(arguments.get("conditions"))
List<Condition<LootContext>> conditions = Optional.ofNullable(arguments.get("conditions"))
.map(it -> LootConditions.fromMapList((List<Map<String, Object>>) it))
.orElse(Collections.emptyList());
return new ExpLootEntryContainer<>(NumberProviders.fromObject(value), conditions);

View File

@@ -42,7 +42,7 @@ public class LootEntryContainers {
@SuppressWarnings("unchecked")
public static <T> LootEntryContainer<T> fromMap(Map<String, Object> 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<T> factory = (LootEntryContainerFactory<T>) BuiltInRegistries.LOOT_ENTRY_CONTAINER_FACTORY.getValue(key);
if (factory == null) {
throw new LocalizedResourceConfigException("warning.config.loot_table.entry.invalid_type", type);

View File

@@ -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<T> extends AbstractSingleLootEntryCont
public static final Factory<?> FACTORY = new Factory<>();
private final Key item;
protected SingleItemLootEntryContainer(Key item, List<LootCondition> conditions, List<LootFunction<T>> lootFunctions, int weight, int quality) {
protected SingleItemLootEntryContainer(Key item, List<Condition<LootContext>> conditions, List<LootFunction<T>> lootFunctions, int weight, int quality) {
super(conditions, lootFunctions, weight, quality);
this.item = item;
}
@@ -31,7 +31,7 @@ public class SingleItemLootEntryContainer<T> extends AbstractSingleLootEntryCont
@SuppressWarnings("unchecked")
@Override
protected void createItem(Consumer<Item<T>> lootConsumer, LootContext context) {
Item<T> tItem = (Item<T>) CraftEngine.instance().itemManager().createWrappedItem(this.item, context.getOptionalParameter(LootParameters.PLAYER).orElse(null));
Item<T> tItem = (Item<T>) 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<T> 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<LootCondition> conditions = Optional.ofNullable(arguments.get("conditions"))
List<Condition<LootContext>> conditions = Optional.ofNullable(arguments.get("conditions"))
.map(it -> LootConditions.fromMapList((List<Map<String, Object>>) it))
.orElse(Collections.emptyList());
List<LootFunction<A>> functions = Optional.ofNullable(arguments.get("functions"))

View File

@@ -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<T> implements LootFunction<T> {
protected final List<LootCondition> predicates;
protected final List<Condition<LootContext>> predicates;
private final Predicate<LootContext> compositePredicates;
public AbstractLootConditionalFunction(List<LootCondition> predicates) {
public AbstractLootConditionalFunction(List<Condition<LootContext>> predicates) {
this.predicates = predicates;
this.compositePredicates = MCUtils.allOf(predicates);
}

View File

@@ -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<T> extends AbstractLootConditionalFunction<T> {
public static final Factory<?> FACTORY = new Factory<>();
private final Key enchantment;
private final Formula formula;
public ApplyBonusCountFunction(List<LootCondition> predicates, Key enchantment, Formula formula) {
public ApplyBonusCountFunction(List<Condition<LootContext>> predicates, Key enchantment, Formula formula) {
super(predicates);
this.enchantment = enchantment;
this.formula = formula;
@@ -32,7 +31,7 @@ public class ApplyBonusCountFunction<T> extends AbstractLootConditionalFunction<
@Override
protected Item<T> applyInternal(Item<T> item, LootContext context) {
Optional<Item<?>> itemInHand = context.getOptionalParameter(LootParameters.TOOL);
Optional<Item<?>> 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<T> extends AbstractLootConditionalFunction<
if (formulaMap == null) {
throw new LocalizedResourceConfigException("warning.config.loot_table.function.apply_bonus.missing_formula");
}
List<LootCondition> conditions = Optional.ofNullable(arguments.get("conditions"))
List<Condition<LootContext>> conditions = Optional.ofNullable(arguments.get("conditions"))
.map(it -> LootConditions.fromMapList((List<Map<String, Object>>) it))
.orElse(Collections.emptyList());
return new ApplyBonusCountFunction<>(conditions, Key.from(enchantment), Formulas.fromMap(formulaMap));
@@ -92,7 +91,7 @@ public class ApplyBonusCountFunction<T> 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<T> 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;
}

View File

@@ -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<T> extends AbstractLootConditionalFunction<T> {
public static final Factory<?> FACTORY = new Factory<>();
private final NumberProvider value;
public DropExpFunction(NumberProvider value, List<LootCondition> predicates) {
public DropExpFunction(NumberProvider value, List<Condition<LootContext>> predicates) {
super(predicates);
this.value = value;
}
@Override
protected Item<T> applyInternal(Item<T> 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<T> extends AbstractLootConditionalFunction<T> {
@Override
public LootFunction<T> create(Map<String, Object> arguments) {
Object value = ResourceConfigUtils.requireNonNullOrThrow(arguments.get("count"), "warning.config.loot_table.function.drop_exp.missing_count");
List<LootCondition> conditions = Optional.ofNullable(arguments.get("conditions"))
List<Condition<LootContext>> conditions = Optional.ofNullable(arguments.get("conditions"))
.map(it -> LootConditions.fromMapList((List<Map<String, Object>>) it))
.orElse(Collections.emptyList());
return new DropExpFunction<>(NumberProviders.fromObject(value), conditions);

View File

@@ -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<T> extends AbstractLootConditionalFunction<T> {
public static final Factory<?> FACTORY = new Factory<>();
public ExplosionDecayFunction(List<LootCondition> predicates) {
public ExplosionDecayFunction(List<Condition<LootContext>> predicates) {
super(predicates);
}
@Override
protected Item<T> applyInternal(Item<T> item, LootContext context) {
Optional<Float> radius = context.getOptionalParameter(LootParameters.EXPLOSION_RADIUS);
Optional<Float> 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<T> extends AbstractLootConditionalFunction<T
@SuppressWarnings("unchecked")
@Override
public LootFunction<T> create(Map<String, Object> arguments) {
List<LootCondition> conditions = Optional.ofNullable(arguments.get("conditions"))
List<Condition<LootContext>> conditions = Optional.ofNullable(arguments.get("conditions"))
.map(it -> LootConditions.fromMapList((List<Map<String, Object>>) it))
.orElse(Collections.emptyList());
return new ExplosionDecayFunction<>(conditions);

View File

@@ -70,7 +70,7 @@ public class LootFunctions {
@SuppressWarnings("unchecked")
public static <T> LootFunction<T> fromMap(Map<String, Object> 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<T> factory = (LootFunctionFactory<T>) BuiltInRegistries.LOOT_FUNCTION_FACTORY.getValue(key);
if (factory == null) {
throw new LocalizedResourceConfigException("warning.config.loot_table.function.invalid_type", type);

View File

@@ -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<T> extends AbstractLootConditionalFunction<T> {
private final NumberProvider value;
private final boolean add;
public SetCountFunction(List<LootCondition> conditions, NumberProvider value, boolean add) {
public SetCountFunction(List<Condition<LootContext>> conditions, NumberProvider value, boolean add) {
super(conditions);
this.value = value;
this.add = add;
@@ -44,7 +44,7 @@ public class SetCountFunction<T> extends AbstractLootConditionalFunction<T> {
public LootFunction<A> create(Map<String, Object> 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<LootCondition> conditions = Optional.ofNullable(arguments.get("conditions"))
List<Condition<LootContext>> conditions = Optional.ofNullable(arguments.get("conditions"))
.map(it -> LootConditions.fromMapList((List<Map<String, Object>>) it))
.orElse(Collections.emptyList());
return new SetCountFunction<>(conditions, NumberProviders.fromObject(value), add);

View File

@@ -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<String, Object> arguments) {
Number value = (Number) arguments.get("value");
return new FixedNumberProvider(value.floatValue());
}
}
}

View File

@@ -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();
}

View File

@@ -1,8 +0,0 @@
package net.momirealms.craftengine.core.loot.number;
import java.util.Map;
public interface NumberProviderFactory {
NumberProvider create(Map<String, Object> arguments);
}

View File

@@ -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<NumberProviderFactory> holder = ((WritableRegistry<NumberProviderFactory>) BuiltInRegistries.NUMBER_PROVIDER_FACTORY)
.registerForHolder(new ResourceKey<>(Registries.NUMBER_PROVIDER_FACTORY.location(), key));
holder.bindValue(factory);
}
public static List<NumberProvider> fromMapList(List<Map<String, Object>> mapList) {
if (mapList == null || mapList.isEmpty()) return List.of();
List<NumberProvider> functions = new ArrayList<>();
for (Map<String, Object> map : mapList) {
functions.add(fromMap(map));
}
return functions;
}
public static NumberProvider fromMap(Map<String, Object> 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<String, Object>) map);
}
throw new IllegalArgumentException("Can't convert " + object + " to " + NumberProvider.class.getSimpleName());
}
}

View File

@@ -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<String, Object> arguments) {
Object min = arguments.getOrDefault("min", 1);
Object max = arguments.getOrDefault("max", 1);
return new UniformNumberProvider(NumberProviders.fromObject(min), NumberProviders.fromObject(max));
}
}
}

Some files were not shown because too many files have changed in this diff Show More