9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-20 07:29:17 +00:00

Merge pull request #448 from Xiao-MoMi/dev

部分修复
This commit is contained in:
XiaoMoMi
2025-11-09 15:36:22 +08:00
committed by GitHub
92 changed files with 1210 additions and 347 deletions

3
.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "wiki"]
path = wiki
url = https://github.com/Xiao-MoMi/craft-engine-wiki.git

View File

@@ -75,7 +75,7 @@ repositories {
``` ```
```kotlin ```kotlin
dependencies { dependencies {
compileOnly("net.momirealms:craft-engine-core:0.0.64") compileOnly("net.momirealms:craft-engine-core:0.0.65")
compileOnly("net.momirealms:craft-engine-bukkit:0.0.64") compileOnly("net.momirealms:craft-engine-bukkit:0.0.65")
} }
``` ```

View File

@@ -37,8 +37,9 @@ dependencies {
compileOnly("com.infernalsuite.asp:api:4.0.0-SNAPSHOT") compileOnly("com.infernalsuite.asp:api:4.0.0-SNAPSHOT")
// ModelEngine // ModelEngine
compileOnly("com.ticxo.modelengine:ModelEngine:R4.0.8") compileOnly("com.ticxo.modelengine:ModelEngine:R4.0.8")
// BetterModels // BetterModel
compileOnly("io.github.toxicity188:BetterModel:1.7.0") compileOnly("io.github.toxicity188:bettermodel:1.14.0")
compileOnly("com.mojang:authlib:${rootProject.properties["authlib_version"]}")
// MMOItems // MMOItems
compileOnly("net.Indyuce:MMOItems-API:6.10-SNAPSHOT") compileOnly("net.Indyuce:MMOItems-API:6.10-SNAPSHOT")
compileOnly("io.lumine:MythicLib-dist:1.6.2-SNAPSHOT") compileOnly("io.lumine:MythicLib-dist:1.6.2-SNAPSHOT")

View File

@@ -26,6 +26,14 @@ public class LegacySlimeWorldDataStorage implements WorldDataStorage {
return slimeWorld.get(); return slimeWorld.get();
} }
@Override
public CEChunk readNewChunkAt(CEWorld world, ChunkPos pos) {
SlimeChunk slimeChunk = getWorld().getChunk(pos.x, pos.z);
if (slimeChunk == null) return new CEChunk(world, pos);
slimeChunk.getExtraData().getValue().remove("craftengine");
return new CEChunk(world, pos);
}
@Override @Override
public @NotNull CEChunk readChunkAt(@NotNull CEWorld world, @NotNull ChunkPos pos) { public @NotNull CEChunk readChunkAt(@NotNull CEWorld world, @NotNull ChunkPos pos) {
SlimeChunk slimeChunk = getWorld().getChunk(pos.x, pos.z); SlimeChunk slimeChunk = getWorld().getChunk(pos.x, pos.z);
@@ -57,6 +65,13 @@ public class LegacySlimeWorldDataStorage implements WorldDataStorage {
} }
} }
@Override
public void clearChunkAt(@NotNull ChunkPos pos) {
SlimeChunk slimeChunk = getWorld().getChunk(pos.x, pos.z);
if (slimeChunk == null) return;
slimeChunk.getExtraData().getValue().remove("craftengine");
}
@Override @Override
public void flush() { public void flush() {
} }

View File

@@ -3,6 +3,7 @@ package net.momirealms.craftengine.bukkit.compatibility.model.bettermodel;
import kr.toxicity.model.api.BetterModel; import kr.toxicity.model.api.BetterModel;
import kr.toxicity.model.api.data.renderer.ModelRenderer; import kr.toxicity.model.api.data.renderer.ModelRenderer;
import kr.toxicity.model.api.tracker.DummyTracker; import kr.toxicity.model.api.tracker.DummyTracker;
import kr.toxicity.model.api.tracker.TrackerModifier;
import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElement; import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElement;
import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.world.BlockPos; import net.momirealms.craftengine.core.world.BlockPos;
@@ -23,11 +24,13 @@ public class BetterModelBlockEntityElement implements BlockEntityElement {
} }
private DummyTracker createDummyTracker() { private DummyTracker createDummyTracker() {
ModelRenderer modelRenderer = BetterModel.plugin().modelManager().renderer(this.config.model()); ModelRenderer modelRenderer = BetterModel.plugin().modelManager().model(this.config.model());
if (modelRenderer == null) { if (modelRenderer == null) {
return null; return null;
} else { } else {
return modelRenderer.create(this.location); return modelRenderer.create(this.location, TrackerModifier.builder()
.sightTrace(this.config.sightTrace())
.build());
} }
} }

View File

@@ -15,28 +15,38 @@ public class BetterModelBlockEntityElementConfig implements BlockEntityElementCo
private final float yaw; private final float yaw;
private final float pitch; private final float pitch;
private final String model; private final String model;
private final boolean sightTrace;
public BetterModelBlockEntityElementConfig(String model, Vector3f position, float yaw, float pitch) { public BetterModelBlockEntityElementConfig(String model,
Vector3f position,
float yaw,
float pitch,
boolean sightTrace) {
this.pitch = pitch; this.pitch = pitch;
this.position = position; this.position = position;
this.yaw = yaw; this.yaw = yaw;
this.model = model; this.model = model;
this.sightTrace = sightTrace;
} }
public String model() { public String model() {
return model; return this.model;
} }
public float pitch() { public float pitch() {
return pitch; return this.pitch;
} }
public Vector3f position() { public Vector3f position() {
return position; return this.position;
} }
public float yaw() { public float yaw() {
return yaw; return this.yaw;
}
public boolean sightTrace() {
return this.sightTrace;
} }
@Override @Override
@@ -44,6 +54,11 @@ public class BetterModelBlockEntityElementConfig implements BlockEntityElementCo
return new BetterModelBlockEntityElement(world, pos, this); return new BetterModelBlockEntityElement(world, pos, this);
} }
@Override
public Class<BetterModelBlockEntityElement> elementClass() {
return BetterModelBlockEntityElement.class;
}
public static class Factory implements BlockEntityElementConfigFactory { public static class Factory implements BlockEntityElementConfigFactory {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@@ -54,7 +69,8 @@ public class BetterModelBlockEntityElementConfig implements BlockEntityElementCo
model, model,
ResourceConfigUtils.getAsVector3f(arguments.getOrDefault("position", 0.5f), "position"), ResourceConfigUtils.getAsVector3f(arguments.getOrDefault("position", 0.5f), "position"),
ResourceConfigUtils.getAsFloat(arguments.getOrDefault("yaw", 0f), "yaw"), ResourceConfigUtils.getAsFloat(arguments.getOrDefault("yaw", 0f), "yaw"),
ResourceConfigUtils.getAsFloat(arguments.getOrDefault("pitch", 0f), "pitch") ResourceConfigUtils.getAsFloat(arguments.getOrDefault("pitch", 0f), "pitch"),
ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("sight-trace", true), "sight-trace")
); );
} }
} }

View File

@@ -9,7 +9,7 @@ import org.bukkit.entity.Entity;
public class BetterModelUtils { public class BetterModelUtils {
public static void bindModel(Entity base, String id) { public static void bindModel(Entity base, String id) {
ModelRenderer renderer = BetterModel.plugin().modelManager().renderer(id); ModelRenderer renderer = BetterModel.plugin().modelManager().model(id);
if (renderer == null) { if (renderer == null) {
throw new NullPointerException("Could not find BetterModel blueprint " + id); throw new NullPointerException("Could not find BetterModel blueprint " + id);
} }

View File

@@ -44,6 +44,11 @@ public class ModelEngineBlockEntityElementConfig implements BlockEntityElementCo
return new ModelEngineBlockEntityElement(world, pos, this); return new ModelEngineBlockEntityElement(world, pos, this);
} }
@Override
public Class<ModelEngineBlockEntityElement> elementClass() {
return ModelEngineBlockEntityElement.class;
}
public static class Factory implements BlockEntityElementConfigFactory { public static class Factory implements BlockEntityElementConfigFactory {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")

View File

@@ -27,6 +27,14 @@ public class SlimeWorldDataStorage implements WorldDataStorage {
return slimeWorld.get(); return slimeWorld.get();
} }
@Override
public CEChunk readNewChunkAt(CEWorld world, ChunkPos pos) {
SlimeChunk slimeChunk = getWorld().getChunk(pos.x, pos.z);
if (slimeChunk == null) return new CEChunk(world, pos);
slimeChunk.getExtraData().remove("craftengine");
return new CEChunk(world, pos);
}
@Override @Override
public @NotNull CEChunk readChunkAt(@NotNull CEWorld world, @NotNull ChunkPos pos) { public @NotNull CEChunk readChunkAt(@NotNull CEWorld world, @NotNull ChunkPos pos) {
SlimeChunk slimeChunk = getWorld().getChunk(pos.x, pos.z); SlimeChunk slimeChunk = getWorld().getChunk(pos.x, pos.z);
@@ -42,7 +50,7 @@ public class SlimeWorldDataStorage implements WorldDataStorage {
} }
} }
@SuppressWarnings("unchecked") @SuppressWarnings({"unchecked", "rawtypes"})
@Override @Override
public void writeChunkAt(@NotNull ChunkPos pos, @NotNull CEChunk chunk) { public void writeChunkAt(@NotNull ChunkPos pos, @NotNull CEChunk chunk) {
SlimeChunk slimeChunk = getWorld().getChunk(pos.x, pos.z); SlimeChunk slimeChunk = getWorld().getChunk(pos.x, pos.z);
@@ -53,8 +61,7 @@ public class SlimeWorldDataStorage implements WorldDataStorage {
} else { } else {
try { try {
Object tag = adaptor.bytesToByteArrayTag(NBT.toBytes(nbt)); Object tag = adaptor.bytesToByteArrayTag(NBT.toBytes(nbt));
Map<String, ?> data1 = slimeChunk.getExtraData(); Map<String, Object> data2 = (Map) slimeChunk.getExtraData();
Map<String, Object> data2 = (Map<String, Object>) data1;
data2.put("craftengine", tag); data2.put("craftengine", tag);
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException("Failed to write chunk tag to slime world. " + pos, e); throw new RuntimeException("Failed to write chunk tag to slime world. " + pos, e);
@@ -62,6 +69,13 @@ public class SlimeWorldDataStorage implements WorldDataStorage {
} }
} }
@Override
public void clearChunkAt(@NotNull ChunkPos pos) {
SlimeChunk slimeChunk = getWorld().getChunk(pos.x, pos.z);
if (slimeChunk == null) return;
slimeChunk.getExtraData().remove("craftengine");
}
@Override @Override
public void flush() { public void flush() {
} }

View File

@@ -59,7 +59,7 @@ public final class BukkitBlockManager extends AbstractBlockManager {
private Map<Integer, List<String>> clientBoundTags = Map.of(); private Map<Integer, List<String>> clientBoundTags = Map.of();
private Map<Integer, List<String>> previousClientBoundTags = Map.of(); private Map<Integer, List<String>> previousClientBoundTags = Map.of();
// 缓存的原版方块tag包 // 缓存的原版方块tag包
private Object cachedUpdateTagsPacket; private List<TagUtils.TagEntry> cachedUpdateTags = List.of();
// 被移除声音的原版方块 // 被移除声音的原版方块
private Set<Object> missingPlaceSounds = Set.of(); private Set<Object> missingPlaceSounds = Set.of();
private Set<Object> missingBreakSounds = Set.of(); private Set<Object> missingBreakSounds = Set.of();
@@ -150,23 +150,14 @@ public final class BukkitBlockManager extends AbstractBlockManager {
} }
@Override @Override
protected void resendTags() { protected void updateTags() {
// if there's no change // if there's no change
if (this.clientBoundTags.equals(this.previousClientBoundTags)) return; if (this.clientBoundTags.equals(this.previousClientBoundTags)) return;
List<TagUtils.TagEntry> list = new ArrayList<>(); List<TagUtils.TagEntry> list = new ArrayList<>();
for (Map.Entry<Integer, List<String>> entry : this.clientBoundTags.entrySet()) { for (Map.Entry<Integer, List<String>> entry : this.clientBoundTags.entrySet()) {
list.add(new TagUtils.TagEntry(entry.getKey(), entry.getValue())); list.add(new TagUtils.TagEntry(entry.getKey(), entry.getValue()));
} }
Object packet = TagUtils.createUpdateTagsPacket(Map.of(MRegistries.BLOCK, list)); this.cachedUpdateTags = list;
for (BukkitServerPlayer player : this.plugin.networkManager().onlineUsers()) {
player.sendPacket(packet, false);
}
// 如果空,那么新来的玩家就没必要收到更新包了
if (list.isEmpty()) {
this.cachedUpdateTagsPacket = null;
} else {
this.cachedUpdateTagsPacket = packet;
}
} }
@Nullable @Nullable
@@ -299,6 +290,10 @@ public final class BukkitBlockManager extends AbstractBlockManager {
this.burnOdds.put(nmsBlock, settings.fireSpreadChance()); this.burnOdds.put(nmsBlock, settings.fireSpreadChance());
this.burnableBlocks.add(nmsBlock); this.burnableBlocks.add(nmsBlock);
} }
Key vanillaBlockId = state.vanillaBlockState().ownerId();
BlockGenerator.field$CraftEngineBlock$isNoteBlock().set(nmsBlock, vanillaBlockId.equals(BlockKeys.NOTE_BLOCK));
BlockGenerator.field$CraftEngineBlock$isTripwire().set(nmsBlock, vanillaBlockId.equals(BlockKeys.TRIPWIRE));
} catch (ReflectiveOperationException e) { } catch (ReflectiveOperationException e) {
this.plugin.logger().warn("Failed to apply platform block settings for block state " + state, e); this.plugin.logger().warn("Failed to apply platform block settings for block state " + state, e);
} }
@@ -364,8 +359,8 @@ public final class BukkitBlockManager extends AbstractBlockManager {
} }
} }
public Object cachedUpdateTagsPacket() { public List<TagUtils.TagEntry> cachedUpdateTags() {
return this.cachedUpdateTagsPacket; return this.cachedUpdateTags;
} }
public VisualBlockStatePacket cachedVisualBlockStatePacket() { public VisualBlockStatePacket cachedVisualBlockStatePacket() {

View File

@@ -1,6 +1,5 @@
package net.momirealms.craftengine.bukkit.block.entity; package net.momirealms.craftengine.bukkit.block.entity;
import net.momirealms.craftengine.bukkit.block.behavior.SeatBlockBehavior;
import net.momirealms.craftengine.bukkit.entity.seat.BukkitSeat; import net.momirealms.craftengine.bukkit.entity.seat.BukkitSeat;
import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.block.entity.BlockEntity; import net.momirealms.craftengine.core.block.entity.BlockEntity;
@@ -14,8 +13,6 @@ import net.momirealms.craftengine.core.world.BlockPos;
import net.momirealms.craftengine.core.world.WorldPosition; import net.momirealms.craftengine.core.world.WorldPosition;
import net.momirealms.sparrow.nbt.CompoundTag; import net.momirealms.sparrow.nbt.CompoundTag;
import java.util.Optional;
public class SeatBlockEntity extends BlockEntity implements SeatOwner { public class SeatBlockEntity extends BlockEntity implements SeatOwner {
private final Seat<SeatBlockEntity>[] seats; private final Seat<SeatBlockEntity>[] seats;
@@ -41,25 +38,20 @@ public class SeatBlockEntity extends BlockEntity implements SeatOwner {
} }
public boolean spawnSeat(Player player) { public boolean spawnSeat(Player player) {
Optional<SeatBlockBehavior> seatBehavior = super.blockState.behavior().getAs(SeatBlockBehavior.class); Property<?> facing = super.blockState.owner().value().getProperty("facing");
if (seatBehavior.isEmpty()) { int yRot = 0;
return false; if (facing != null && facing.valueClass() == HorizontalDirection.class) {
} HorizontalDirection direction = (HorizontalDirection) super.blockState.get(facing);
float yRot = 0; yRot = switch (direction) {
Property<HorizontalDirection> directionProperty = seatBehavior.get().directionProperty(); case NORTH -> 0;
if (directionProperty != null) { case SOUTH -> 180;
HorizontalDirection direction = super.blockState.get(directionProperty); case WEST -> 270;
if (direction == HorizontalDirection.NORTH) { case EAST -> 90;
yRot = 180; };
} else if (direction == HorizontalDirection.EAST) {
yRot = -90;
} else if (direction == HorizontalDirection.WEST) {
yRot = 90;
}
} }
for (Seat<SeatBlockEntity> seat : this.seats) { for (Seat<SeatBlockEntity> seat : this.seats) {
if (!seat.isOccupied()) { if (!seat.isOccupied()) {
if (seat.spawnSeat(player, new WorldPosition(super.world.world(), super.pos.x() + 0.5, super.pos.y(), super.pos.z() + 0.5, 0, 180 - yRot))) { if (seat.spawnSeat(player, new WorldPosition(super.world.world(), super.pos.x() + 0.5, super.pos.y(), super.pos.z() + 0.5, 0, yRot))) {
return true; return true;
} }
} }

View File

@@ -7,6 +7,7 @@ public class BukkitBlockEntityElementConfigs extends BlockEntityElementConfigs {
static { static {
register(ITEM_DISPLAY, ItemDisplayBlockEntityElementConfig.FACTORY); register(ITEM_DISPLAY, ItemDisplayBlockEntityElementConfig.FACTORY);
register(TEXT_DISPLAY, TextDisplayBlockEntityElementConfig.FACTORY); register(TEXT_DISPLAY, TextDisplayBlockEntityElementConfig.FACTORY);
register(ITEM, ItemBlockEntityElementConfig.FACTORY);
} }
private BukkitBlockEntityElementConfigs() {} private BukkitBlockEntityElementConfigs() {}

View File

@@ -0,0 +1,65 @@
package net.momirealms.craftengine.bukkit.block.entity.renderer.element;
import it.unimi.dsi.fastutil.ints.IntList;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MEntityTypes;
import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElement;
import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.world.BlockPos;
import org.joml.Vector3f;
import java.util.List;
import java.util.UUID;
public class ItemBlockEntityElement implements BlockEntityElement {
public final ItemBlockEntityElementConfig config;
public final Object cachedSpawnPacket1;
public final Object cachedSpawnPacket2;
public final Object cachedRidePacket;
public final Object cachedDespawnPacket;
public final Object cachedUpdatePosPacket;
public final int entityId1;
public final int entityId2;
public ItemBlockEntityElement(ItemBlockEntityElementConfig config, BlockPos pos) {
this(config, pos, CoreReflections.instance$Entity$ENTITY_COUNTER.incrementAndGet(), CoreReflections.instance$Entity$ENTITY_COUNTER.incrementAndGet(), false);
}
public ItemBlockEntityElement(ItemBlockEntityElementConfig config, BlockPos pos, int entityId1, int entityId2, boolean posChanged) {
this.config = config;
Vector3f position = config.position();
this.cachedSpawnPacket1 = FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket(
entityId1, UUID.randomUUID(), pos.x() + position.x, pos.y() + position.y, pos.z() + position.z,
0, 0, MEntityTypes.ITEM_DISPLAY, 0, CoreReflections.instance$Vec3$Zero, 0
);
this.cachedSpawnPacket2 = FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket(
entityId2, UUID.randomUUID(), pos.x() + position.x, pos.y() + position.y, pos.z() + position.z,
0, 0, MEntityTypes.ITEM, 0, CoreReflections.instance$Vec3$Zero, 0
);
this.cachedRidePacket = FastNMS.INSTANCE.constructor$ClientboundSetPassengersPacket(entityId1, entityId2);
this.cachedDespawnPacket = FastNMS.INSTANCE.constructor$ClientboundRemoveEntitiesPacket(IntList.of(entityId1, entityId2));
this.entityId1 = entityId1;
this.entityId2 = entityId2;
this.cachedUpdatePosPacket = posChanged ? FastNMS.INSTANCE.constructor$ClientboundEntityPositionSyncPacket(this.entityId1, pos.x() + position.x, pos.y() + position.y, pos.z() + position.z, 0, 0, false) : null;
}
@Override
public void hide(Player player) {
player.sendPacket(this.cachedDespawnPacket, false);
}
@Override
public void show(Player player) {
player.sendPackets(List.of(this.cachedSpawnPacket1, this.cachedSpawnPacket2, this.cachedRidePacket, FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(this.entityId2, this.config.metadataValues(player))), false);
}
@Override
public void transform(Player player) {
if (this.cachedUpdatePosPacket != null) {
player.sendPackets(List.of(this.cachedUpdatePosPacket, FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(this.entityId2, this.config.metadataValues(player))), false);
} else {
player.sendPacket(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(this.entityId2, this.config.metadataValues(player)), false);
}
}
}

View File

@@ -0,0 +1,77 @@
package net.momirealms.craftengine.bukkit.block.entity.renderer.element;
import net.momirealms.craftengine.bukkit.entity.data.ItemEntityData;
import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElement;
import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElementConfig;
import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElementConfigFactory;
import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import net.momirealms.craftengine.core.world.BlockPos;
import net.momirealms.craftengine.core.world.World;
import org.joml.Vector3f;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
public class ItemBlockEntityElementConfig implements BlockEntityElementConfig<ItemBlockEntityElement> {
public static final Factory FACTORY = new Factory();
private final Function<Player, List<Object>> lazyMetadataPacket;
private final Function<Player, Item<?>> item;
private final Vector3f position;
public ItemBlockEntityElementConfig(Function<Player, Item<?>> item, Vector3f position) {
this.item = item;
this.position = position;
this.lazyMetadataPacket = player -> {
List<Object> dataValues = new ArrayList<>();
ItemEntityData.Item.addEntityDataIfNotDefaultValue(item.apply(player).getLiteralObject(), dataValues);
ItemEntityData.NoGravity.addEntityDataIfNotDefaultValue(true, dataValues);
return dataValues;
};
}
@Override
public ItemBlockEntityElement create(World world, BlockPos pos) {
return new ItemBlockEntityElement(this, pos);
}
@Override
public ItemBlockEntityElement create(World world, BlockPos pos, ItemBlockEntityElement previous) {
return new ItemBlockEntityElement(this, pos, previous.entityId1, previous.entityId2, !previous.config.position.equals(this.position));
}
@Override
public Class<ItemBlockEntityElement> elementClass() {
return ItemBlockEntityElement.class;
}
public Vector3f position() {
return position;
}
public Item<?> item(Player player) {
return this.item.apply(player);
}
public List<Object> metadataValues(Player player) {
return this.lazyMetadataPacket.apply(player);
}
public static class Factory implements BlockEntityElementConfigFactory {
@SuppressWarnings("unchecked")
@Override
public <E extends BlockEntityElement> BlockEntityElementConfig<E> create(Map<String, Object> arguments) {
Key itemId = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("item"), "warning.config.block.state.entity_renderer.item_display.missing_item"));
return (BlockEntityElementConfig<E>) new ItemBlockEntityElementConfig(
player -> BukkitItemManager.instance().createWrappedItem(itemId, player),
ResourceConfigUtils.getAsVector3f(arguments.getOrDefault("position", 0.5f), "position")
);
}
}
}

View File

@@ -13,13 +13,17 @@ import java.util.List;
import java.util.UUID; import java.util.UUID;
public class ItemDisplayBlockEntityElement implements BlockEntityElement { public class ItemDisplayBlockEntityElement implements BlockEntityElement {
private final ItemDisplayBlockEntityElementConfig config; public final ItemDisplayBlockEntityElementConfig config;
private final Object cachedSpawnPacket; public final Object cachedSpawnPacket;
private final Object cachedDespawnPacket; public final Object cachedDespawnPacket;
private final int entityId; public final Object cachedUpdatePosPacket;
public final int entityId;
public ItemDisplayBlockEntityElement(ItemDisplayBlockEntityElementConfig config, BlockPos pos) { public ItemDisplayBlockEntityElement(ItemDisplayBlockEntityElementConfig config, BlockPos pos) {
int entityId = CoreReflections.instance$Entity$ENTITY_COUNTER.incrementAndGet(); this(config, pos, CoreReflections.instance$Entity$ENTITY_COUNTER.incrementAndGet(), false);
}
public ItemDisplayBlockEntityElement(ItemDisplayBlockEntityElementConfig config, BlockPos pos, int entityId, boolean posChanged) {
Vector3f position = config.position(); Vector3f position = config.position();
this.cachedSpawnPacket = FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket( this.cachedSpawnPacket = FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket(
entityId, UUID.randomUUID(), pos.x() + position.x, pos.y() + position.y, pos.z() + position.z, entityId, UUID.randomUUID(), pos.x() + position.x, pos.y() + position.y, pos.z() + position.z,
@@ -28,6 +32,7 @@ public class ItemDisplayBlockEntityElement implements BlockEntityElement {
this.config = config; this.config = config;
this.cachedDespawnPacket = FastNMS.INSTANCE.constructor$ClientboundRemoveEntitiesPacket(IntList.of(entityId)); this.cachedDespawnPacket = FastNMS.INSTANCE.constructor$ClientboundRemoveEntitiesPacket(IntList.of(entityId));
this.entityId = entityId; this.entityId = entityId;
this.cachedUpdatePosPacket = posChanged ? FastNMS.INSTANCE.constructor$ClientboundEntityPositionSyncPacket(this.entityId, pos.x() + position.x, pos.y() + position.y, pos.z() + position.z, config.yRot(), config.xRot(), false) : null;
} }
@Override @Override
@@ -37,6 +42,15 @@ public class ItemDisplayBlockEntityElement implements BlockEntityElement {
@Override @Override
public void show(Player player) { public void show(Player player) {
player.sendPackets(List.of(this.cachedSpawnPacket, FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(this.entityId, this.config.metadataValues(player))), true); player.sendPackets(List.of(this.cachedSpawnPacket, FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(this.entityId, this.config.metadataValues(player))), false);
}
@Override
public void transform(Player player) {
if (this.cachedUpdatePosPacket != null) {
player.sendPackets(List.of(this.cachedUpdatePosPacket, FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(this.entityId, this.config.metadataValues(player))), false);
} else {
player.sendPacket(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(this.entityId, this.config.metadataValues(player)), false);
}
} }
} }

View File

@@ -78,6 +78,20 @@ public class ItemDisplayBlockEntityElementConfig implements BlockEntityElementCo
return new ItemDisplayBlockEntityElement(this, pos); return new ItemDisplayBlockEntityElement(this, pos);
} }
@Override
public ItemDisplayBlockEntityElement create(World world, BlockPos pos, ItemDisplayBlockEntityElement previous) {
Quaternionf previousRotation = previous.config.rotation;
if (previousRotation.x != 0 || previousRotation.y != 0 || previousRotation.z != 0 || previousRotation.w != 1) {
return null;
}
return new ItemDisplayBlockEntityElement(this, pos, previous.entityId, previous.config.yRot != this.yRot || previous.config.xRot != this.xRot || !previous.config.position.equals(this.position));
}
@Override
public Class<ItemDisplayBlockEntityElement> elementClass() {
return ItemDisplayBlockEntityElement.class;
}
public Item<?> item(Player player) { public Item<?> item(Player player) {
return this.item.apply(player); return this.item.apply(player);
} }

View File

@@ -13,13 +13,17 @@ import java.util.List;
import java.util.UUID; import java.util.UUID;
public class TextDisplayBlockEntityElement implements BlockEntityElement { public class TextDisplayBlockEntityElement implements BlockEntityElement {
private final TextDisplayBlockEntityElementConfig config; public final TextDisplayBlockEntityElementConfig config;
private final Object cachedSpawnPacket; public final Object cachedSpawnPacket;
private final Object cachedDespawnPacket; public final Object cachedDespawnPacket;
private final int entityId; public final Object cachedUpdatePosPacket;
public final int entityId;
public TextDisplayBlockEntityElement(TextDisplayBlockEntityElementConfig config, BlockPos pos) { public TextDisplayBlockEntityElement(TextDisplayBlockEntityElementConfig config, BlockPos pos) {
int entityId = CoreReflections.instance$Entity$ENTITY_COUNTER.incrementAndGet(); this(config, pos, CoreReflections.instance$Entity$ENTITY_COUNTER.incrementAndGet(), false);
}
public TextDisplayBlockEntityElement(TextDisplayBlockEntityElementConfig config, BlockPos pos, int entityId, boolean posChanged) {
Vector3f position = config.position(); Vector3f position = config.position();
this.cachedSpawnPacket = FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket( this.cachedSpawnPacket = FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket(
entityId, UUID.randomUUID(), pos.x() + position.x, pos.y() + position.y, pos.z() + position.z, entityId, UUID.randomUUID(), pos.x() + position.x, pos.y() + position.y, pos.z() + position.z,
@@ -28,6 +32,7 @@ public class TextDisplayBlockEntityElement implements BlockEntityElement {
this.config = config; this.config = config;
this.cachedDespawnPacket = FastNMS.INSTANCE.constructor$ClientboundRemoveEntitiesPacket(IntList.of(entityId)); this.cachedDespawnPacket = FastNMS.INSTANCE.constructor$ClientboundRemoveEntitiesPacket(IntList.of(entityId));
this.entityId = entityId; this.entityId = entityId;
this.cachedUpdatePosPacket = posChanged ? FastNMS.INSTANCE.constructor$ClientboundEntityPositionSyncPacket(this.entityId, pos.x() + position.x, pos.y() + position.y, pos.z() + position.z, config.yRot(), config.xRot(), false) : null;
} }
@Override @Override
@@ -37,6 +42,19 @@ public class TextDisplayBlockEntityElement implements BlockEntityElement {
@Override @Override
public void show(Player player) { public void show(Player player) {
player.sendPackets(List.of(this.cachedSpawnPacket, FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(this.entityId, this.config.metadataValues(player))), true); player.sendPackets(List.of(this.cachedSpawnPacket, FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(this.entityId, this.config.metadataValues(player))), false);
}
@Override
public void transform(Player player) {
if (this.cachedUpdatePosPacket != null) {
player.sendPackets(List.of(this.cachedUpdatePosPacket, FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(this.entityId, this.config.metadataValues(player))), false);
} else {
player.sendPacket(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(this.entityId, this.config.metadataValues(player)), false);
}
}
public int entityId() {
return entityId;
} }
} }

View File

@@ -66,6 +66,20 @@ public class TextDisplayBlockEntityElementConfig implements BlockEntityElementCo
return new TextDisplayBlockEntityElement(this, pos); return new TextDisplayBlockEntityElement(this, pos);
} }
@Override
public TextDisplayBlockEntityElement create(World world, BlockPos pos, TextDisplayBlockEntityElement previous) {
Quaternionf previousRotation = previous.config.rotation;
if (previousRotation.x != 0 || previousRotation.y != 0 || previousRotation.z != 0 || previousRotation.w != 1) {
return null;
}
return new TextDisplayBlockEntityElement(this, pos, previous.entityId, previous.config.yRot != this.yRot || previous.config.xRot != this.xRot || !previous.config.position.equals(this.position));
}
@Override
public Class<TextDisplayBlockEntityElement> elementClass() {
return TextDisplayBlockEntityElement.class;
}
public Component text(Player player) { public Component text(Player player) {
return AdventureHelper.miniMessage().deserialize(this.text, PlayerOptionalContext.of(player).tagResolvers()); return AdventureHelper.miniMessage().deserialize(this.text, PlayerOptionalContext.of(player).tagResolvers());
} }

View File

@@ -0,0 +1,11 @@
package net.momirealms.craftengine.bukkit.entity.data;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
public class ItemEntityData<T> extends BaseEntityData<T> {
public static final ItemEntityData<Object> Item = new ItemEntityData<>(ItemEntityData.class, EntityDataValue.Serializers$ITEM_STACK, CoreReflections.instance$ItemStack$EMPTY);
public ItemEntityData(Class<?> clazz, Object serializer, T defaultValue) {
super(clazz, serializer, defaultValue);
}
}

View File

@@ -28,7 +28,7 @@ import org.jetbrains.annotations.NotNull;
import java.io.IOException; import java.io.IOException;
public class BukkitSeatManager implements SeatManager { public class BukkitSeatManager implements SeatManager, Listener {
private static BukkitSeatManager instance; private static BukkitSeatManager instance;
public static final NamespacedKey SEAT_KEY = KeyUtils.toNamespacedKey(SeatManager.SEAT_KEY); public static final NamespacedKey SEAT_KEY = KeyUtils.toNamespacedKey(SeatManager.SEAT_KEY);
public static final NamespacedKey SEAT_EXTRA_DATA_KEY = KeyUtils.toNamespacedKey(SeatManager.SEAT_EXTRA_DATA_KEY); public static final NamespacedKey SEAT_EXTRA_DATA_KEY = KeyUtils.toNamespacedKey(SeatManager.SEAT_EXTRA_DATA_KEY);
@@ -113,9 +113,9 @@ public class BukkitSeatManager implements SeatManager {
if (!isSeat) return; if (!isSeat) return;
Location location = seat.getLocation(); Location location = seat.getLocation();
if (seat instanceof ArmorStand) { if (seat instanceof ArmorStand) {
location.add(0, 0.9875,0); location.add(0, 0.3875,0);
} else { } else {
location.add(0,0.25,0); location.add(0,-0.35,0);
} }
seat.remove(); seat.remove();
EntityUtils.safeDismount(player, location); EntityUtils.safeDismount(player, location);

View File

@@ -501,10 +501,17 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory<ComponentItemW
if (trim == null) { if (trim == null) {
item.resetComponent(DataComponentTypes.TRIM); item.resetComponent(DataComponentTypes.TRIM);
} else { } else {
try {
item.setJavaComponent(DataComponentTypes.TRIM, Map.of( item.setJavaComponent(DataComponentTypes.TRIM, Map.of(
"pattern", trim.pattern().asString(), "pattern", trim.pattern().asString(),
"material", trim.material().asString() "material", trim.material().asString()
)); ));
} catch (Exception e) {
// 预防未启用基于纹饰盔甲时,锁链甲可能产生的网络问题(由用户配置决定)
if (!trim.material().equals(Key.of("minecraft", "custom")) && !trim.pattern().equals(Key.of("minecraft", "chainmail"))) {
this.plugin.logger().warn("Failed to apply trim " + trim, e);
}
}
} }
} }

View File

@@ -201,6 +201,14 @@ public final class BlockGenerator {
field$CraftEngineBlock$isTripwire = clazz$CraftEngineBlock.getField("isClientSideTripwire"); field$CraftEngineBlock$isTripwire = clazz$CraftEngineBlock.getField("isClientSideTripwire");
} }
public static Field field$CraftEngineBlock$isNoteBlock() {
return field$CraftEngineBlock$isNoteBlock;
}
public static Field field$CraftEngineBlock$isTripwire() {
return field$CraftEngineBlock$isTripwire;
}
public static DelegatingBlock generateBlock(Key blockId) throws Throwable { public static DelegatingBlock generateBlock(Key blockId) throws Throwable {
ObjectHolder<BlockBehavior> behaviorHolder = new ObjectHolder<>(EmptyBlockBehavior.INSTANCE); ObjectHolder<BlockBehavior> behaviorHolder = new ObjectHolder<>(EmptyBlockBehavior.INSTANCE);
ObjectHolder<BlockShape> shapeHolder = new ObjectHolder<>(STONE_SHAPE); ObjectHolder<BlockShape> shapeHolder = new ObjectHolder<>(STONE_SHAPE);

View File

@@ -19,6 +19,7 @@ import net.momirealms.craftengine.core.block.DelegatingBlockState;
import net.momirealms.craftengine.core.block.EmptyBlock; import net.momirealms.craftengine.core.block.EmptyBlock;
import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.block.entity.BlockEntity; import net.momirealms.craftengine.core.block.entity.BlockEntity;
import net.momirealms.craftengine.core.block.entity.render.ConstantBlockEntityRenderer;
import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.config.Config;
import net.momirealms.craftengine.core.util.ReflectionUtils; import net.momirealms.craftengine.core.util.ReflectionUtils;
@@ -226,7 +227,10 @@ public final class WorldStorageInjector {
// 处理 自定义块到自定义块或原版块到自定义块 // 处理 自定义块到自定义块或原版块到自定义块
CEChunk chunk = holder.ceChunk(); CEChunk chunk = holder.ceChunk();
chunk.setDirty(true); chunk.setDirty(true);
ConstantBlockEntityRenderer previousRenderer = null;
// 如果两个方块没有相同的主人 且 旧方块有方块实体 // 如果两个方块没有相同的主人 且 旧方块有方块实体
if (!previousImmutableBlockState.isEmpty()) { if (!previousImmutableBlockState.isEmpty()) {
if (previousImmutableBlockState.owner() != newImmutableBlockState.owner() && previousImmutableBlockState.hasBlockEntity()) { if (previousImmutableBlockState.owner() != newImmutableBlockState.owner() && previousImmutableBlockState.hasBlockEntity()) {
BlockPos pos = new BlockPos(chunk.chunkPos.x * 16 + x, section.sectionY * 16 + y, chunk.chunkPos.z * 16 + z); BlockPos pos = new BlockPos(chunk.chunkPos.x * 16 + x, section.sectionY * 16 + y, chunk.chunkPos.z * 16 + z);
@@ -242,9 +246,11 @@ public final class WorldStorageInjector {
} }
if (previousImmutableBlockState.hasConstantBlockEntityRenderer()) { if (previousImmutableBlockState.hasConstantBlockEntityRenderer()) {
BlockPos pos = new BlockPos(chunk.chunkPos.x * 16 + x, section.sectionY * 16 + y, chunk.chunkPos.z * 16 + z); BlockPos pos = new BlockPos(chunk.chunkPos.x * 16 + x, section.sectionY * 16 + y, chunk.chunkPos.z * 16 + z);
chunk.removeConstantBlockEntityRenderer(pos); // 如果新状态没有entity renderer,那么直接移除,否则暂存
previousRenderer = chunk.removeConstantBlockEntityRenderer(pos, !newImmutableBlockState.hasConstantBlockEntityRenderer());
} }
} }
if (newImmutableBlockState.hasBlockEntity()) { if (newImmutableBlockState.hasBlockEntity()) {
BlockPos pos = new BlockPos(chunk.chunkPos.x * 16 + x, section.sectionY * 16 + y, chunk.chunkPos.z * 16 + z); BlockPos pos = new BlockPos(chunk.chunkPos.x * 16 + x, section.sectionY * 16 + y, chunk.chunkPos.z * 16 + z);
BlockEntity blockEntity = chunk.getBlockEntity(pos, false); BlockEntity blockEntity = chunk.getBlockEntity(pos, false);
@@ -264,10 +270,13 @@ public final class WorldStorageInjector {
chunk.createDynamicBlockEntityRenderer(blockEntity); chunk.createDynamicBlockEntityRenderer(blockEntity);
} }
} }
// 处理新老entity renderer更替
if (newImmutableBlockState.hasConstantBlockEntityRenderer()) { if (newImmutableBlockState.hasConstantBlockEntityRenderer()) {
BlockPos pos = new BlockPos(chunk.chunkPos.x * 16 + x, section.sectionY * 16 + y, chunk.chunkPos.z * 16 + z); BlockPos pos = new BlockPos(chunk.chunkPos.x * 16 + x, section.sectionY * 16 + y, chunk.chunkPos.z * 16 + z);
chunk.addConstantBlockEntityRenderer(pos, newImmutableBlockState); chunk.addConstantBlockEntityRenderer(pos, newImmutableBlockState, previousRenderer);
} }
// 如果新方块的光照属性和客户端认为的不同 // 如果新方块的光照属性和客户端认为的不同
if (Config.enableLightSystem()) { if (Config.enableLightSystem()) {
if (previousImmutableBlockState.isEmpty()) { if (previousImmutableBlockState.isEmpty()) {

View File

@@ -241,6 +241,19 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
this.c2sGamePacketListeners[id] = new ByteBufferPacketListenerHolder(name, listener); this.c2sGamePacketListeners[id] = new ByteBufferPacketListenerHolder(name, listener);
} }
@Override
public void delayedLoad() {
this.resendTags();
}
@SuppressWarnings("unchecked")
public void resendTags() {
Object packet = TagUtils.createUpdateTagsPacket(Map.of(MRegistries.BLOCK, BukkitBlockManager.instance().cachedUpdateTags()), FastNMS.INSTANCE.method$TagNetworkSerialization$serializeTagsToNetwork());
for (BukkitServerPlayer player : onlineUsers()) {
player.sendPacket(packet, false);
}
}
public void addFakePlayer(Player player) { public void addFakePlayer(Player player) {
FakeBukkitServerPlayer fakePlayer = new FakeBukkitServerPlayer(this.plugin); FakeBukkitServerPlayer fakePlayer = new FakeBukkitServerPlayer(this.plugin);
fakePlayer.setPlayer(player); fakePlayer.setPlayer(player);
@@ -1857,11 +1870,17 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
public static class UpdateTagsListener implements NMSPacketListener { public static class UpdateTagsListener implements NMSPacketListener {
@SuppressWarnings("unchecked")
@Override @Override
public void onPacketSend(NetWorkUser user, NMSPacketEvent event, Object packet) { public void onPacketSend(NetWorkUser user, NMSPacketEvent event, Object packet) {
Object modifiedPacket = BukkitBlockManager.instance().cachedUpdateTagsPacket(); List<TagUtils.TagEntry> cachedUpdateTags = BukkitBlockManager.instance().cachedUpdateTags();
if (packet.equals(modifiedPacket) || modifiedPacket == null) return; if (cachedUpdateTags.isEmpty()) return;
event.replacePacket(modifiedPacket); Map<Object, Object> tags = FastNMS.INSTANCE.field$ClientboundUpdateTagsPacket$tags(packet);
// 已经替换过了
if (tags instanceof MarkedHashMap<Object, Object>) return;
// 需要虚假的block
if (tags.get(MRegistries.BLOCK) == null) return;
event.replacePacket(TagUtils.createUpdateTagsPacket(Map.of(MRegistries.BLOCK, cachedUpdateTags), tags));
} }
} }
@@ -4132,16 +4151,22 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
CompoundTag tag = (CompoundTag) buf.readNbt(named); CompoundTag tag = (CompoundTag) buf.readNbt(named);
// todo 刷怪笼里的物品? // todo 刷怪笼里的物品?
// 展示架 // 通用方块实体存储的物品
if (VersionHelper.isOrAbove1_21_9() && tag != null && tag.containsKey("Items")) { if (tag != null && tag.containsKey("Items")) {
BukkitItemManager itemManager = BukkitItemManager.instance(); BukkitItemManager itemManager = BukkitItemManager.instance();
ListTag itemsTag = tag.getList("Items"); ListTag itemsTag = tag.getList("Items");
List<Pair<Byte, ItemStack>> items = new ArrayList<>(); List<Pair<Byte, ItemStack>> items = new ArrayList<>();
for (Tag itemTag : itemsTag) { for (Tag itemTag : itemsTag) {
if (itemTag instanceof CompoundTag itemCompoundTag) { if (itemTag instanceof CompoundTag itemCompoundTag) {
byte slot = itemCompoundTag.getByte("Slot"); byte slot = itemCompoundTag.getByte("Slot");
Object nmsStack = CoreReflections.instance$ItemStack$CODEC.parse(MRegistryOps.SPARROW_NBT, itemCompoundTag) Object nmsStack;
if (VersionHelper.isOrAbove1_20_5()) {
nmsStack = CoreReflections.instance$ItemStack$CODEC.parse(MRegistryOps.SPARROW_NBT, itemCompoundTag)
.resultOrPartial((error) -> CraftEngine.instance().logger().severe("Tried to parse invalid item: '" + error + "'")).orElse(null); .resultOrPartial((error) -> CraftEngine.instance().logger().severe("Tried to parse invalid item: '" + error + "'")).orElse(null);
} else {
Object nmsTag = MRegistryOps.SPARROW_NBT.convertTo(MRegistryOps.NBT, itemTag);
nmsStack = FastNMS.INSTANCE.method$ItemStack$of(nmsTag);
}
ItemStack bukkitStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(nmsStack); ItemStack bukkitStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(nmsStack);
Optional<ItemStack> optional = itemManager.s2c(bukkitStack, (BukkitServerPlayer) user); Optional<ItemStack> optional = itemManager.s2c(bukkitStack, (BukkitServerPlayer) user);
if (optional.isPresent()) { if (optional.isPresent()) {
@@ -4155,8 +4180,14 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
if (changed) { if (changed) {
ListTag newItemsTag = new ListTag(); ListTag newItemsTag = new ListTag();
for (Pair<Byte, ItemStack> pair : items) { for (Pair<Byte, ItemStack> pair : items) {
CompoundTag newItemCompoundTag = (CompoundTag) CoreReflections.instance$ItemStack$CODEC.encodeStart(MRegistryOps.SPARROW_NBT, FastNMS.INSTANCE.field$CraftItemStack$handle(pair.right())) CompoundTag newItemCompoundTag;
if (VersionHelper.isOrAbove1_20_5()) {
newItemCompoundTag = (CompoundTag) CoreReflections.instance$ItemStack$CODEC.encodeStart(MRegistryOps.SPARROW_NBT, FastNMS.INSTANCE.field$CraftItemStack$handle(pair.right()))
.resultOrPartial((error) -> CraftEngine.instance().logger().severe("Tried to encode invalid item: '" + error + "'")).orElse(null); .resultOrPartial((error) -> CraftEngine.instance().logger().severe("Tried to encode invalid item: '" + error + "'")).orElse(null);
} else {
Object nmsTag = FastNMS.INSTANCE.method$itemStack$save(FastNMS.INSTANCE.field$CraftItemStack$handle(pair.right()), FastNMS.INSTANCE.constructor$CompoundTag());
newItemCompoundTag = (CompoundTag) MRegistryOps.NBT.convertTo(MRegistryOps.SPARROW_NBT, nmsTag);
}
if (newItemCompoundTag != null) { if (newItemCompoundTag != null) {
newItemCompoundTag.putByte("Slot", pair.left()); newItemCompoundTag.putByte("Slot", pair.left());
newItemsTag.add(newItemCompoundTag); newItemsTag.add(newItemCompoundTag);

View File

@@ -56,7 +56,7 @@ public record ClientCustomBlockPacket(int vanillaSize, int currentSize) implemen
return; return;
} }
int serverBlockRegistrySize = RegistryUtils.currentBlockRegistrySize(); int serverBlockRegistrySize = RegistryUtils.currentBlockRegistrySize();
if (this.currentSize != serverBlockRegistrySize) { if (this.currentSize < serverBlockRegistrySize) {
user.kick(Component.translatable( user.kick(Component.translatable(
"disconnect.craftengine.current_block_registry_mismatch", "disconnect.craftengine.current_block_registry_mismatch",
TranslationArgument.numeric(this.currentSize), TranslationArgument.numeric(this.currentSize),

View File

@@ -1082,7 +1082,7 @@ public final class CoreReflections {
public static final Class<?> clazz$MobEffect = requireNonNull( public static final Class<?> clazz$MobEffect = requireNonNull(
ReflectionUtils.getClazz( ReflectionUtils.getClazz(
BukkitReflectionUtils.assembleMCClass("world.effect.MobEffectList"), // 这里paper会自动获取到NM.world.effect.MobEffect BukkitReflectionUtils.assembleMCClass("world.effect.MobEffectList"), // 这里paper会自动获取到NM.world.effect.MobEffect
BukkitReflectionUtils.assembleMCClass("world.effect.MobEffect") // 如果插件是mojmap就会走这个 BukkitReflectionUtils.assembleMCClass("world.effect.MobEffect") // paper柠檬酸了
) )
); );
@@ -1125,7 +1125,7 @@ public final class CoreReflections {
public static final Class<?> clazz$Fluid = requireNonNull( public static final Class<?> clazz$Fluid = requireNonNull(
ReflectionUtils.getClazz( ReflectionUtils.getClazz(
BukkitReflectionUtils.assembleMCClass("world.level.material.FluidType"), // 这里paper会自动获取到NM.world.level.material.Fluid BukkitReflectionUtils.assembleMCClass("world.level.material.FluidType"), // 这里paper会自动获取到NM.world.level.material.Fluid
BukkitReflectionUtils.assembleMCClass("world.level.material.Fluid") // 如果插件是mojmap就会走这个 BukkitReflectionUtils.assembleMCClass("world.level.material.Fluid") // paper柠檬酸了
) )
); );
@@ -3133,9 +3133,9 @@ public final class CoreReflections {
); );
public static final Class<?> clazz$ChunkMap = requireNonNull( public static final Class<?> clazz$ChunkMap = requireNonNull(
BukkitReflectionUtils.findReobfOrMojmapClass( ReflectionUtils.getClazz(
"server.level.PlayerChunkMap", BukkitReflectionUtils.assembleMCClass("server.level.PlayerChunkMap"), // 这里paper会自动获取到NM.server.level.ChunkMap
"server.level.ChunkMap" BukkitReflectionUtils.assembleMCClass("server.level.ChunkMap") // paper柠檬酸了
) )
); );
@@ -3238,7 +3238,7 @@ public final class CoreReflections {
public static final Class<?> clazz$ResourceManager = requireNonNull( public static final Class<?> clazz$ResourceManager = requireNonNull(
ReflectionUtils.getClazz( ReflectionUtils.getClazz(
BukkitReflectionUtils.assembleMCClass("server.packs.resources.IResourceManager"), // 这里paper会自动获取到NM.server.packs.resources.ResourceManager BukkitReflectionUtils.assembleMCClass("server.packs.resources.IResourceManager"), // 这里paper会自动获取到NM.server.packs.resources.ResourceManager
BukkitReflectionUtils.assembleMCClass("server.packs.resources.ResourceManager") // 如果插件是mojmap就会走这个 BukkitReflectionUtils.assembleMCClass("server.packs.resources.ResourceManager") // paper柠檬酸了
) )
); );
@@ -4536,4 +4536,16 @@ public final class CoreReflections {
public static final Method method$DismountHelper$canDismountTo1 = requireNonNull( public static final Method method$DismountHelper$canDismountTo1 = requireNonNull(
ReflectionUtils.getStaticMethod(clazz$DismountHelper, boolean.class, clazz$CollisionGetter, clazz$Vec3, clazz$LivingEntity, clazz$Pose) ReflectionUtils.getStaticMethod(clazz$DismountHelper, boolean.class, clazz$CollisionGetter, clazz$Vec3, clazz$LivingEntity, clazz$Pose)
); );
public static final Class<?> clazz$WorldGenContext = MiscUtils.requireNonNullIf(
ReflectionUtils.getClazz(BukkitReflectionUtils.assembleMCClass("world.level.chunk.status.WorldGenContext")), VersionHelper.isOrAbove1_20_5()
);
public static final Field field$ChunkMap$worldGenContext = MiscUtils.requireNonNullIf(
ReflectionUtils.getDeclaredField(clazz$ChunkMap, clazz$WorldGenContext, 0), VersionHelper.isOrAbove1_20_5()
);
public static final Field field$ChunkMap$chunkGenerator = MiscUtils.requireNonNullIf(
ReflectionUtils.getDeclaredField(clazz$ChunkMap, clazz$ChunkGenerator, 0), !VersionHelper.isOrAbove1_20_5()
);
} }

View File

@@ -1720,4 +1720,10 @@ public final class NetworkReflections {
"network.protocol.game.ClientboundBlockEntityDataPacket" "network.protocol.game.ClientboundBlockEntityDataPacket"
) )
); );
public static final Field field$ClientboundUpdateTagsPacket$tags = requireNonNull(
ReflectionUtils.getDeclaredField(
clazz$ClientboundUpdateTagsPacket, Map.class, 0
)
);
} }

View File

@@ -63,10 +63,13 @@ public final class EntityUtils {
BlockPos pos = new BlockPos(MiscUtils.fastFloor(x), MiscUtils.fastFloor(y), MiscUtils.fastFloor(z)); BlockPos pos = new BlockPos(MiscUtils.fastFloor(x), MiscUtils.fastFloor(y), MiscUtils.fastFloor(z));
try { try {
double floorHeight = (double) CoreReflections.method$BlockGetter$getBlockFloorHeight.invoke(serverLevel, LocationUtils.toBlockPos(pos)); double floorHeight = (double) CoreReflections.method$BlockGetter$getBlockFloorHeight.invoke(serverLevel, LocationUtils.toBlockPos(pos));
if (pos.y() + floorHeight > y + 0.75) { if (pos.y() + floorHeight > y + 0.75 || !isBlockFloorValid(floorHeight)) {
floorHeight = (double) CoreReflections.method$BlockGetter$getBlockFloorHeight.invoke(serverLevel, LocationUtils.toBlockPos(pos.below()));
if (pos.y() + floorHeight - 1 < y - 0.75 || !isBlockFloorValid(floorHeight)) {
continue; continue;
} }
if (isBlockFloorValid(floorHeight)) { floorHeight -= 1;
}
Object aabb = CoreReflections.method$LivingEntity$getLocalBoundsForPose.invoke(serverPlayer, pose); Object aabb = CoreReflections.method$LivingEntity$getLocalBoundsForPose.invoke(serverPlayer, pose);
Object vec3 = FastNMS.INSTANCE.constructor$Vec3(x, pos.y() + floorHeight, z); Object vec3 = FastNMS.INSTANCE.constructor$Vec3(x, pos.y() + floorHeight, z);
Object newAABB = FastNMS.INSTANCE.method$AABB$move(aabb, vec3); Object newAABB = FastNMS.INSTANCE.method$AABB$move(aabb, vec3);
@@ -89,7 +92,6 @@ public final class EntityUtils {
} else if (pose == CoreReflections.instance$Pose$SWIMMING) { } else if (pose == CoreReflections.instance$Pose$SWIMMING) {
player.setPose(Pose.SWIMMING); player.setPose(Pose.SWIMMING);
} }
}
} catch (ReflectiveOperationException e) { } catch (ReflectiveOperationException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }

View File

@@ -34,6 +34,7 @@ import org.bukkit.attribute.AttributeInstance;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.BlockFace; import org.bukkit.block.BlockFace;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Directional;
import org.bukkit.block.data.Levelled; import org.bukkit.block.data.Levelled;
import org.bukkit.block.data.Lightable; import org.bukkit.block.data.Lightable;
import org.bukkit.block.data.type.*; import org.bukkit.block.data.type.*;
@@ -714,6 +715,37 @@ public final class InteractUtils {
registerInteraction(BlockKeys.BAMBOO_WALL_HANGING_SIGN, (player, item, blockState, result) -> true); registerInteraction(BlockKeys.BAMBOO_WALL_HANGING_SIGN, (player, item, blockState, result) -> true);
registerInteraction(BlockKeys.CRIMSON_WALL_HANGING_SIGN, (player, item, blockState, result) -> true); registerInteraction(BlockKeys.CRIMSON_WALL_HANGING_SIGN, (player, item, blockState, result) -> true);
registerInteraction(BlockKeys.WARPED_WALL_HANGING_SIGN, (player, item, blockState, result) -> true); registerInteraction(BlockKeys.WARPED_WALL_HANGING_SIGN, (player, item, blockState, result) -> true);
// 展示柜
registerInteraction(BlockKeys.OAK_SHELF, (player, item, blockState, result) -> blockState instanceof Directional directional && DirectionUtils.toBlockFace(result.getDirection()).equals(directional.getFacing()));
registerInteraction(BlockKeys.SPRUCE_SHELF, (player, item, blockState, result) -> blockState instanceof Directional directional && DirectionUtils.toBlockFace(result.getDirection()).equals(directional.getFacing()));
registerInteraction(BlockKeys.BIRCH_SHELF, (player, item, blockState, result) -> blockState instanceof Directional directional && DirectionUtils.toBlockFace(result.getDirection()).equals(directional.getFacing()));
registerInteraction(BlockKeys.JUNGLE_SHELF, (player, item, blockState, result) -> blockState instanceof Directional directional && DirectionUtils.toBlockFace(result.getDirection()).equals(directional.getFacing()));
registerInteraction(BlockKeys.ACACIA_SHELF, (player, item, blockState, result) -> blockState instanceof Directional directional && DirectionUtils.toBlockFace(result.getDirection()).equals(directional.getFacing()));
registerInteraction(BlockKeys.DARK_OAK_SHELF, (player, item, blockState, result) -> blockState instanceof Directional directional && DirectionUtils.toBlockFace(result.getDirection()).equals(directional.getFacing()));
registerInteraction(BlockKeys.MANGROVE_SHELF, (player, item, blockState, result) -> blockState instanceof Directional directional && DirectionUtils.toBlockFace(result.getDirection()).equals(directional.getFacing()));
registerInteraction(BlockKeys.CHERRY_SHELF, (player, item, blockState, result) -> blockState instanceof Directional directional && DirectionUtils.toBlockFace(result.getDirection()).equals(directional.getFacing()));
registerInteraction(BlockKeys.PALE_OAK_SHELF, (player, item, blockState, result) -> blockState instanceof Directional directional && DirectionUtils.toBlockFace(result.getDirection()).equals(directional.getFacing()));
registerInteraction(BlockKeys.BAMBOO_SHELF, (player, item, blockState, result) -> blockState instanceof Directional directional && DirectionUtils.toBlockFace(result.getDirection()).equals(directional.getFacing()));
registerInteraction(BlockKeys.CRIMSON_SHELF, (player, item, blockState, result) -> blockState instanceof Directional directional && DirectionUtils.toBlockFace(result.getDirection()).equals(directional.getFacing()));
registerInteraction(BlockKeys.WARPED_SHELF, (player, item, blockState, result) -> blockState instanceof Directional directional && DirectionUtils.toBlockFace(result.getDirection()).equals(directional.getFacing()));
// 铜傀儡雕像
registerInteraction(BlockKeys.COPPER_GOLEM_STATUE, ((player, item, blockData, result) -> true));
registerInteraction(BlockKeys.EXPOSED_COPPER_GOLEM_STATUE, ((player, item, blockData, result) -> true));
registerInteraction(BlockKeys.WEATHERED_COPPER_GOLEM_STATUE, ((player, item, blockData, result) -> true));
registerInteraction(BlockKeys.OXIDIZED_COPPER_GOLEM_STATUE, ((player, item, blockData, result) -> true));
registerInteraction(BlockKeys.WAXED_COPPER_GOLEM_STATUE, ((player, item, blockData, result) -> true));
registerInteraction(BlockKeys.WAXED_EXPOSED_COPPER_GOLEM_STATUE, ((player, item, blockData, result) -> true));
registerInteraction(BlockKeys.WAXED_WEATHERED_COPPER_GOLEM_STATUE, ((player, item, blockData, result) -> true));
registerInteraction(BlockKeys.WAXED_OXIDIZED_COPPER_GOLEM_STATUE, ((player, item, blockData, result) -> true));
// 铜箱子
registerInteraction(BlockKeys.COPPER_CHEST, ((player, item, blockData, result) -> true));
registerInteraction(BlockKeys.EXPOSED_COPPER_CHEST, ((player, item, blockData, result) -> true));
registerInteraction(BlockKeys.WEATHERED_COPPER_CHEST, ((player, item, blockData, result) -> true));
registerInteraction(BlockKeys.OXIDIZED_COPPER_CHEST, ((player, item, blockData, result) -> true));
registerInteraction(BlockKeys.WAXED_COPPER_CHEST, ((player, item, blockData, result) -> true));
registerInteraction(BlockKeys.WAXED_EXPOSED_COPPER_CHEST, ((player, item, blockData, result) -> true));
registerInteraction(BlockKeys.WAXED_WEATHERED_COPPER_CHEST, ((player, item, blockData, result) -> true));
registerInteraction(BlockKeys.WAXED_OXIDIZED_COPPER_CHEST, ((player, item, blockData, result) -> true));
} }
static { static {

View File

@@ -5,6 +5,7 @@ import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList; import it.unimi.dsi.fastutil.ints.IntList;
import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.core.util.FriendlyByteBuf; import net.momirealms.craftengine.core.util.FriendlyByteBuf;
import net.momirealms.craftengine.core.util.MarkedHashMap;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
@@ -15,6 +16,9 @@ public final class TagUtils {
private TagUtils() {} private TagUtils() {}
public record TagEntry(int id, List<String> tags) {
}
/** /**
* 构建模拟标签更新数据包(用于向客户端添加虚拟标签) * 构建模拟标签更新数据包(用于向客户端添加虚拟标签)
* *
@@ -39,11 +43,9 @@ public final class TagUtils {
* *
* @return 可发送给客户端的 ClientboundUpdateTagsPacket 数据包对象 * @return 可发送给客户端的 ClientboundUpdateTagsPacket 数据包对象
*/ */
@SuppressWarnings("unchecked") public static Object createUpdateTagsPacket(Map<Object, List<TagEntry>> tags, Map<Object, Object> existingTags) {
public static Object createUpdateTagsPacket(Map<Object, List<TagEntry>> tags) { Map<Object, Object> modified = new MarkedHashMap<>();
Map<Object, Object> registriesNetworkPayload = (Map<Object, Object>) FastNMS.INSTANCE.method$TagNetworkSerialization$serializeTagsToNetwork(); for (Map.Entry<Object, Object> payload : existingTags.entrySet()) {
Map<Object, Object> modified = new HashMap<>();
for (Map.Entry<Object, Object> payload : registriesNetworkPayload.entrySet()) {
List<TagEntry> overrides = tags.get(payload.getKey()); List<TagEntry> overrides = tags.get(payload.getKey());
if (overrides == null || overrides.isEmpty()) { if (overrides == null || overrides.isEmpty()) {
modified.put(payload.getKey(), payload.getValue()); modified.put(payload.getKey(), payload.getValue());
@@ -83,7 +85,4 @@ public final class TagUtils {
} }
return FastNMS.INSTANCE.constructor$ClientboundUpdateTagsPacket(modified); return FastNMS.INSTANCE.constructor$ClientboundUpdateTagsPacket(modified);
} }
public record TagEntry(int id, List<String> tags) {
}
} }

View File

@@ -92,10 +92,12 @@ public class BukkitWorldManager implements WorldManager, Listener {
public void delayedInit() { public void delayedInit() {
// load loaded chunks // load loaded chunks
for (World world : Bukkit.getWorlds()) { for (World world : Bukkit.getWorlds()) {
BukkitWorld wrappedWorld = new BukkitWorld(world);
try { try {
CEWorld ceWorld = this.worlds.computeIfAbsent(world.getUID(), k -> new BukkitCEWorld(new BukkitWorld(world), this.storageAdaptor)); CEWorld ceWorld = this.worlds.computeIfAbsent(world.getUID(), k -> new BukkitCEWorld(wrappedWorld, this.storageAdaptor));
injectChunkGenerator(ceWorld);
for (Chunk chunk : world.getLoadedChunks()) { for (Chunk chunk : world.getLoadedChunks()) {
handleChunkLoad(ceWorld, chunk); handleChunkLoad(ceWorld, chunk, false);
} }
ceWorld.setTicking(true); ceWorld.setTicking(true);
} catch (Exception e) { } catch (Exception e) {
@@ -142,8 +144,9 @@ public class BukkitWorldManager implements WorldManager, Listener {
CEWorld ceWorld = new BukkitCEWorld(world, this.storageAdaptor); CEWorld ceWorld = new BukkitCEWorld(world, this.storageAdaptor);
this.worlds.put(uuid, ceWorld); this.worlds.put(uuid, ceWorld);
this.resetWorldArray(); this.resetWorldArray();
this.injectChunkGenerator(ceWorld);
for (Chunk chunk : ((World) world.platformWorld()).getLoadedChunks()) { for (Chunk chunk : ((World) world.platformWorld()).getLoadedChunks()) {
handleChunkLoad(ceWorld, chunk); handleChunkLoad(ceWorld, chunk, false);
} }
ceWorld.setTicking(true); ceWorld.setTicking(true);
} }
@@ -154,12 +157,20 @@ public class BukkitWorldManager implements WorldManager, Listener {
if (this.worlds.containsKey(uuid)) return; if (this.worlds.containsKey(uuid)) return;
this.worlds.put(uuid, world); this.worlds.put(uuid, world);
this.resetWorldArray(); this.resetWorldArray();
this.injectChunkGenerator(world);
for (Chunk chunk : ((World) world.world().platformWorld()).getLoadedChunks()) { for (Chunk chunk : ((World) world.world().platformWorld()).getLoadedChunks()) {
handleChunkLoad(world, chunk); handleChunkLoad(world, chunk, false);
} }
world.setTicking(true); world.setTicking(true);
} }
private void injectChunkGenerator(CEWorld world) {
Object serverLevel = world.world.serverWorld();
Object serverChunkCache = FastNMS.INSTANCE.method$ServerLevel$getChunkSource(serverLevel);
Object chunkMap = FastNMS.INSTANCE.field$ServerChunkCache$chunkMap(serverChunkCache);
FastNMS.INSTANCE.injectedWorldGen(world, chunkMap);
}
@Override @Override
public CEWorld createWorld(net.momirealms.craftengine.core.world.World world, WorldDataStorage storage) { public CEWorld createWorld(net.momirealms.craftengine.core.world.World world, WorldDataStorage storage) {
return new BukkitCEWorld(world, storage); return new BukkitCEWorld(world, storage);
@@ -219,7 +230,7 @@ public class BukkitWorldManager implements WorldManager, Listener {
if (world == null) { if (world == null) {
return; return;
} }
handleChunkLoad(world, event.getChunk()); handleChunkLoad(world, event.getChunk(), event.isNewChunk());
} }
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
@@ -273,14 +284,42 @@ public class BukkitWorldManager implements WorldManager, Listener {
FastNMS.INSTANCE.method$LevelChunk$markUnsaved(levelChunk); FastNMS.INSTANCE.method$LevelChunk$markUnsaved(levelChunk);
} }
ceChunk.unload(); ceChunk.unload();
ceChunk.deactivateAllBlockEntities();
} }
} }
private void handleChunkLoad(CEWorld ceWorld, Chunk chunk) { public void handleChunkGenerate(CEWorld ceWorld, ChunkPos chunkPos, Object chunkAccess) {
Object[] sections = FastNMS.INSTANCE.method$ChunkAccess$getSections(chunkAccess);
CEChunk ceChunk;
try {
ceChunk = ceWorld.worldDataStorage().readNewChunkAt(ceWorld, chunkPos);
CESection[] ceSections = ceChunk.sections();
synchronized (sections) {
for (int i = 0; i < ceSections.length; i++) {
CESection ceSection = ceSections[i];
Object section = sections[i];
int finalI = i;
WorldStorageInjector.injectLevelChunkSection(section, ceSection, ceChunk, new SectionPos(chunkPos.x, ceChunk.sectionY(i), chunkPos.z),
(injected) -> sections[finalI] = injected);
}
}
ceChunk.load();
} catch (IOException e) {
this.plugin.logger().warn("Failed to read new chunk at " + chunkPos.x + " " + chunkPos.z, e);
}
}
private void handleChunkLoad(CEWorld ceWorld, Chunk chunk, boolean isNew) {
int chunkX = chunk.getX(); int chunkX = chunk.getX();
int chunkZ = chunk.getZ(); int chunkZ = chunk.getZ();
ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ);
if (ceWorld.isChunkLoaded(chunkPos.longKey)) return; CEChunk chunkAtIfLoaded = ceWorld.getChunkAtIfLoaded(chunkPos.longKey);
if (chunkAtIfLoaded != null) {
if (isNew) {
chunkAtIfLoaded.activateAllBlockEntities();
}
return;
}
CEChunk ceChunk; CEChunk ceChunk;
try { try {
ceChunk = ceWorld.worldDataStorage().readChunkAt(ceWorld, chunkPos); ceChunk = ceWorld.worldDataStorage().readChunkAt(ceWorld, chunkPos);
@@ -382,5 +421,6 @@ public class BukkitWorldManager implements WorldManager, Listener {
return; return;
} }
ceChunk.load(); ceChunk.load();
ceChunk.activateAllBlockEntities();
} }
} }

View File

@@ -81,6 +81,15 @@ resource-pack:
suffix: "minecraft/atlases" suffix: "minecraft/atlases"
resolution: resolution:
type: merge_atlas type: merge_atlas
- term:
type: any_of
terms:
- type: exact
path: "assets/minecraft/font/default.json"
- type: exact
path: "assets/minecraft/font/uniform.json"
resolution:
type: merge_font
# Validate if there is any error in the resource pack, such as missing textures or models # Validate if there is any error in the resource pack, such as missing textures or models
# If your resource pack is compliant with the standard, you can disable validation to improve the resource pack generation speed. # If your resource pack is compliant with the standard, you can disable validation to improve the resource pack generation speed.
validation: validation:

View File

@@ -2,7 +2,7 @@ items:
default:amethyst_torch: default:amethyst_torch:
material: nether_brick material: nether_brick
data: data:
item-name: <!i><i18n:item.amethyst_torch> item-name: <!i><l10n:item.amethyst_torch>
model: model:
type: minecraft:model type: minecraft:model
path: minecraft:item/custom/amethyst_torch path: minecraft:item/custom/amethyst_torch
@@ -20,7 +20,7 @@ items:
default:amethyst_standing_torch: default:amethyst_standing_torch:
material: nether_brick material: nether_brick
data: data:
item-name: <!i><i18n:item.amethyst_torch> item-name: <!i><l10n:item.amethyst_torch>
model: model:
type: minecraft:model type: minecraft:model
path: minecraft:block/custom/amethyst_torch path: minecraft:block/custom/amethyst_torch
@@ -31,7 +31,7 @@ items:
default:amethyst_wall_torch: default:amethyst_wall_torch:
material: nether_brick material: nether_brick
data: data:
item-name: <!i><i18n:item.amethyst_torch> item-name: <!i><l10n:item.amethyst_torch>
model: model:
type: minecraft:model type: minecraft:model
path: minecraft:block/custom/amethyst_wall_torch path: minecraft:block/custom/amethyst_wall_torch

View File

@@ -2,7 +2,7 @@ items:
default:chessboard_block: default:chessboard_block:
material: nether_brick material: nether_brick
data: data:
item-name: <!i><i18n:item.chessboard_block> item-name: <!i><l10n:item.chessboard_block>
model: model:
type: minecraft:model type: minecraft:model
path: minecraft:item/custom/chessboard_block path: minecraft:item/custom/chessboard_block

View File

@@ -2,7 +2,7 @@ items:
default:chinese_lantern: default:chinese_lantern:
material: nether_brick material: nether_brick
data: data:
item-name: <!i><i18n:item.chinese_lantern> item-name: <!i><l10n:item.chinese_lantern>
model: model:
type: minecraft:model type: minecraft:model
path: minecraft:item/custom/chinese_lantern path: minecraft:item/custom/chinese_lantern

View File

@@ -2,7 +2,7 @@ items:
default:copper_coil: default:copper_coil:
material: nether_brick material: nether_brick
data: data:
item-name: <!i><i18n:item.copper_coil> item-name: <!i><l10n:item.copper_coil>
model: model:
type: minecraft:model type: minecraft:model
path: minecraft:item/custom/copper_coil path: minecraft:item/custom/copper_coil

View File

@@ -2,7 +2,7 @@ items:
default:ender_pearl_flower_seeds: default:ender_pearl_flower_seeds:
material: nether_brick material: nether_brick
data: data:
item-name: <!i><i18n:item.ender_pearl_flower_seeds> item-name: <!i><l10n:item.ender_pearl_flower_seeds>
model: model:
template: default:model/simplified_generated template: default:model/simplified_generated
arguments: arguments:

View File

@@ -2,7 +2,7 @@ items:
default:fairy_flower: default:fairy_flower:
material: nether_brick material: nether_brick
data: data:
item-name: <!i><i18n:item.fairy_flower> item-name: <!i><l10n:item.fairy_flower>
model: model:
template: default:model/simplified_generated template: default:model/simplified_generated
arguments: arguments:

View File

@@ -2,7 +2,7 @@ items:
default:flame_cane: default:flame_cane:
material: nether_brick material: nether_brick
data: data:
item-name: <!i><i18n:item.flame_cane> item-name: <!i><l10n:item.flame_cane>
model: model:
template: default:model/simplified_generated template: default:model/simplified_generated
arguments: arguments:

View File

@@ -2,7 +2,7 @@ items:
default:gunpowder_block: default:gunpowder_block:
material: nether_brick material: nether_brick
data: data:
item-name: <!i><i18n:item.gunpowder_block> item-name: <!i><l10n:item.gunpowder_block>
model: model:
type: minecraft:model type: minecraft:model
path: minecraft:item/custom/gunpowder_block path: minecraft:item/custom/gunpowder_block
@@ -37,7 +37,7 @@ items:
default:solid_gunpowder_block: default:solid_gunpowder_block:
material: nether_brick material: nether_brick
data: data:
item-name: <!i><i18n:item.solid_gunpowder_block> item-name: <!i><l10n:item.solid_gunpowder_block>
model: model:
type: minecraft:model type: minecraft:model
path: minecraft:item/custom/solid_gunpowder_block path: minecraft:item/custom/solid_gunpowder_block

View File

@@ -2,7 +2,7 @@ items:
default:hami_melon_slice: default:hami_melon_slice:
material: melon_slice material: melon_slice
data: data:
item-name: <!i><i18n:item.hami_melon_slice> item-name: <!i><l10n:item.hami_melon_slice>
$$>=1.20.5: $$>=1.20.5:
food: food:
nutrition: 2 nutrition: 2
@@ -20,7 +20,7 @@ items:
default:hami_melon: default:hami_melon:
material: nether_brick material: nether_brick
data: data:
item-name: <!i><i18n:item.hami_melon> item-name: <!i><l10n:item.hami_melon>
model: model:
path: minecraft:item/custom/hami_melon path: minecraft:item/custom/hami_melon
generation: generation:
@@ -31,7 +31,7 @@ items:
default:hami_melon_seeds: default:hami_melon_seeds:
material: nether_brick material: nether_brick
data: data:
item-name: <!i><i18n:item.hami_melon_seeds> item-name: <!i><l10n:item.hami_melon_seeds>
model: model:
template: default:model/simplified_generated template: default:model/simplified_generated
arguments: arguments:

View File

@@ -6,7 +6,7 @@ items:
arguments: arguments:
path: minecraft:item/custom/magma_fruit path: minecraft:item/custom/magma_fruit
data: data:
item-name: <!i><white><i18n:item.magma_fruit> item-name: <!i><white><l10n:item.magma_fruit>
$$>=1.20.5: $$>=1.20.5:
food: food:
nutrition: 3 nutrition: 3

View File

@@ -2,7 +2,7 @@ items:
default:netherite_anvil: default:netherite_anvil:
material: nether_brick material: nether_brick
data: data:
item-name: <!i><i18n:item.netherite_anvil> item-name: <!i><l10n:item.netherite_anvil>
model: model:
type: minecraft:model type: minecraft:model
path: minecraft:item/custom/netherite_anvil path: minecraft:item/custom/netherite_anvil

View File

@@ -8,7 +8,7 @@ items:
- minecraft:logs - minecraft:logs
- minecraft:logs_that_burn - minecraft:logs_that_burn
data: data:
item-name: <!i><i18n:item.palm_log> item-name: <!i><l10n:item.palm_log>
model: model:
type: minecraft:model type: minecraft:model
path: minecraft:item/custom/palm_log path: minecraft:item/custom/palm_log
@@ -40,7 +40,7 @@ items:
- minecraft:logs - minecraft:logs
- minecraft:logs_that_burn - minecraft:logs_that_burn
data: data:
item-name: <!i><i18n:item.stripped_palm_log> item-name: <!i><l10n:item.stripped_palm_log>
model: model:
type: minecraft:model type: minecraft:model
path: minecraft:item/custom/stripped_palm_log path: minecraft:item/custom/stripped_palm_log
@@ -69,7 +69,7 @@ items:
- minecraft:logs - minecraft:logs
- minecraft:logs_that_burn - minecraft:logs_that_burn
data: data:
item-name: <!i><i18n:item.palm_wood> item-name: <!i><l10n:item.palm_wood>
model: model:
type: minecraft:model type: minecraft:model
path: minecraft:item/custom/palm_wood path: minecraft:item/custom/palm_wood
@@ -101,7 +101,7 @@ items:
- minecraft:logs - minecraft:logs
- minecraft:logs_that_burn - minecraft:logs_that_burn
data: data:
item-name: <!i><i18n:item.stripped_palm_wood> item-name: <!i><l10n:item.stripped_palm_wood>
model: model:
type: minecraft:model type: minecraft:model
path: minecraft:item/custom/stripped_palm_wood path: minecraft:item/custom/stripped_palm_wood
@@ -129,7 +129,7 @@ items:
- minecraft:planks - minecraft:planks
- minecraft:wooden_tool_materials - minecraft:wooden_tool_materials
data: data:
item-name: <!i><i18n:item.palm_planks> item-name: <!i><l10n:item.palm_planks>
model: model:
type: minecraft:model type: minecraft:model
path: minecraft:item/custom/palm_planks path: minecraft:item/custom/palm_planks
@@ -153,7 +153,7 @@ items:
settings: settings:
fuel-time: 100 fuel-time: 100
data: data:
item-name: <!i><i18n:item.palm_sapling> item-name: <!i><l10n:item.palm_sapling>
lore: lore:
- "<!i><gray>Requires the datapack tree configuration to function." - "<!i><gray>Requires the datapack tree configuration to function."
- "<!i><gray>If not configured, an oak tree will grow by default." - "<!i><gray>If not configured, an oak tree will grow by default."
@@ -197,7 +197,7 @@ items:
default:palm_leaves: default:palm_leaves:
material: oak_leaves material: oak_leaves
data: data:
item-name: <!i><i18n:item.palm_leaves> item-name: <!i><l10n:item.palm_leaves>
block-state: default:palm_leaves[persistent=true,waterlogged=false,distance=7] block-state: default:palm_leaves[persistent=true,waterlogged=false,distance=7]
model: model:
type: minecraft:model type: minecraft:model
@@ -227,7 +227,7 @@ items:
default:palm_trapdoor: default:palm_trapdoor:
material: nether_brick material: nether_brick
data: data:
item-name: <!i><i18n:item.palm_trapdoor> item-name: <!i><l10n:item.palm_trapdoor>
settings: settings:
fuel-time: 300 fuel-time: 300
model: model:
@@ -281,7 +281,7 @@ items:
default:palm_door: default:palm_door:
material: nether_brick material: nether_brick
data: data:
item-name: <!i><i18n:item.palm_door> item-name: <!i><l10n:item.palm_door>
settings: settings:
fuel-time: 200 fuel-time: 200
model: model:
@@ -355,7 +355,7 @@ items:
default:palm_fence_gate: default:palm_fence_gate:
material: nether_brick material: nether_brick
data: data:
item-name: <!i><i18n:item.palm_fence_gate> item-name: <!i><l10n:item.palm_fence_gate>
settings: settings:
fuel-time: 300 fuel-time: 300
model: model:
@@ -411,7 +411,7 @@ items:
default:palm_slab: default:palm_slab:
material: nether_brick material: nether_brick
data: data:
item-name: <!i><i18n:item.palm_slab> item-name: <!i><l10n:item.palm_slab>
settings: settings:
fuel-time: 150 fuel-time: 150
model: model:
@@ -462,7 +462,7 @@ items:
generation: generation:
parent: minecraft:block/custom/palm_stairs parent: minecraft:block/custom/palm_stairs
data: data:
item-name: <!i><i18n:item.palm_stairs> item-name: <!i><l10n:item.palm_stairs>
settings: settings:
fuel-time: 300 fuel-time: 300
behavior: behavior:
@@ -511,7 +511,7 @@ items:
generation: generation:
parent: minecraft:block/custom/palm_pressure_plate parent: minecraft:block/custom/palm_pressure_plate
data: data:
item-name: <!i><i18n:item.palm_pressure_plate> item-name: <!i><l10n:item.palm_pressure_plate>
settings: settings:
fuel-time: 300 fuel-time: 300
behavior: behavior:
@@ -560,7 +560,7 @@ items#pfence:
default:palm_fence: default:palm_fence:
material: nether_brick material: nether_brick
data: data:
item-name: <!i><i18n:item.palm_fence> item-name: <!i><l10n:item.palm_fence>
model: model:
type: minecraft:model type: minecraft:model
path: minecraft:item/custom/palm_fence_inventory path: minecraft:item/custom/palm_fence_inventory
@@ -632,7 +632,7 @@ items#button:
textures: textures:
texture: minecraft:block/custom/palm_planks texture: minecraft:block/custom/palm_planks
data: data:
item-name: <!i><i18n:item.palm_button> item-name: <!i><l10n:item.palm_button>
settings: settings:
fuel-time: 100 fuel-time: 100
behavior: behavior:

View File

@@ -2,7 +2,7 @@ items:
default:pebble: default:pebble:
material: nether_brick material: nether_brick
data: data:
item-name: <!i><i18n:item.pebble> item-name: <!i><l10n:item.pebble>
model: model:
template: default:model/simplified_generated template: default:model/simplified_generated
arguments: arguments:

View File

@@ -2,7 +2,7 @@ items:
default:reed: default:reed:
material: nether_brick material: nether_brick
data: data:
item-name: <!i><i18n:item.reed> item-name: <!i><l10n:item.reed>
model: model:
template: default:model/simplified_generated template: default:model/simplified_generated
arguments: arguments:

View File

@@ -2,7 +2,7 @@ items:
default:safe_block: default:safe_block:
material: nether_brick material: nether_brick
data: data:
item-name: <!i><i18n:item.safe_block> item-name: <!i><l10n:item.safe_block>
model: model:
type: minecraft:model type: minecraft:model
path: minecraft:item/custom/safe_block path: minecraft:item/custom/safe_block
@@ -31,7 +31,7 @@ items:
step: minecraft:block.stone.step step: minecraft:block.stone.step
behavior: behavior:
type: simple_storage_block type: simple_storage_block
title: "<i18n:item.safe_block>" title: "<l10n:item.safe_block>"
rows: 1 rows: 1
sounds: sounds:
open: minecraft:block.iron_trapdoor.open open: minecraft:block.iron_trapdoor.open
@@ -58,6 +58,7 @@ items:
front: minecraft:block/custom/safe_block_front front: minecraft:block/custom/safe_block_front
side: minecraft:block/custom/safe_block_side side: minecraft:block/custom/safe_block_side
top: minecraft:block/custom/safe_block_top top: minecraft:block/custom/safe_block_top
bottom: minecraft:block/custom/safe_block_bottom
east_open: east_open:
auto-state: note_block auto-state: note_block
model: model:
@@ -69,6 +70,7 @@ items:
front: minecraft:block/custom/safe_block_front_open front: minecraft:block/custom/safe_block_front_open
side: minecraft:block/custom/safe_block_side side: minecraft:block/custom/safe_block_side
top: minecraft:block/custom/safe_block_top top: minecraft:block/custom/safe_block_top
bottom: minecraft:block/custom/safe_block_bottom
north: north:
auto-state: note_block auto-state: note_block
model: model:

View File

@@ -2,7 +2,7 @@ items:
default:sleeper_sofa: default:sleeper_sofa:
material: nether_brick material: nether_brick
data: data:
item-name: <!i><i18n:item.sofa> item-name: <!i><l10n:item.sofa>
model: model:
type: minecraft:model type: minecraft:model
path: minecraft:item/custom/sleeper_sofa path: minecraft:item/custom/sleeper_sofa
@@ -50,7 +50,7 @@ items:
default:sofa: default:sofa:
material: nether_brick material: nether_brick
data: data:
item-name: <!i><i18n:item.sofa> item-name: <!i><l10n:item.sofa>
model: model:
type: minecraft:model type: minecraft:model
path: minecraft:item/custom/sofa path: minecraft:item/custom/sofa

View File

@@ -2,7 +2,7 @@ items:
default:table_lamp: default:table_lamp:
material: nether_brick material: nether_brick
data: data:
item-name: <!i><i18n:item.table_lamp> item-name: <!i><l10n:item.table_lamp>
model: model:
type: minecraft:model type: minecraft:model
path: minecraft:item/custom/table_lamp path: minecraft:item/custom/table_lamp

View File

@@ -2,7 +2,7 @@ items:
default:topaz_ore: default:topaz_ore:
material: nether_brick material: nether_brick
data: data:
item-name: <!i><i18n:item.topaz_ore> item-name: <!i><l10n:item.topaz_ore>
model: model:
type: minecraft:model type: minecraft:model
path: minecraft:item/custom/topaz_ore path: minecraft:item/custom/topaz_ore
@@ -14,7 +14,7 @@ items:
default:deepslate_topaz_ore: default:deepslate_topaz_ore:
material: nether_brick material: nether_brick
data: data:
item-name: <!i><i18n:item.deepslate_topaz_ore> item-name: <!i><l10n:item.deepslate_topaz_ore>
model: model:
type: minecraft:model type: minecraft:model
path: minecraft:item/custom/deepslate_topaz_ore path: minecraft:item/custom/deepslate_topaz_ore
@@ -31,7 +31,7 @@ items:
- '#default:topaz_tools' - '#default:topaz_tools'
percent: 0.25 percent: 0.25
data: data:
item-name: <!i><#FF8C00><i18n:item.topaz> item-name: <!i><#FF8C00><l10n:item.topaz>
model: model:
template: default:model/simplified_generated template: default:model/simplified_generated
arguments: arguments:

View File

@@ -1,16 +1,16 @@
categories: categories:
default:default: default:default:
priority: 1 priority: 1
name: <!i><white><i18n:category.default.name></white> name: <!i><white><l10n:category.default.name></white>
lore: lore:
- <!i><gray><i18n:category.default.lore> - <!i><gray><l10n:category.default.lore>
icon: default:topaz icon: default:topaz
list: list:
- '#default:palm_tree' - '#default:palm_tree'
- '#default:topaz' - '#default:topaz'
- '#default:misc' - '#default:misc'
default:palm_tree: default:palm_tree:
name: <!i><green><i18n:category.palm_tree></green> name: <!i><green><l10n:category.palm_tree></green>
hidden: true hidden: true
icon: default:palm_log icon: default:palm_log
list: list:
@@ -30,7 +30,7 @@ categories:
- default:palm_pressure_plate - default:palm_pressure_plate
- default:palm_button - default:palm_button
default:topaz: default:topaz:
name: <!i><#FF8C00><i18n:category.topaz></#FF8C00> name: <!i><#FF8C00><l10n:category.topaz></#FF8C00>
hidden: true hidden: true
icon: default:topaz icon: default:topaz
list: list:
@@ -51,7 +51,7 @@ categories:
- default:topaz_leggings - default:topaz_leggings
- default:topaz_boots - default:topaz_boots
default:misc: default:misc:
name: <!i><gray><i18n:category.misc></gray> name: <!i><gray><l10n:category.misc></gray>
hidden: true hidden: true
icon: default:chinese_lantern icon: default:chinese_lantern
list: list:

View File

@@ -1,6 +1,6 @@
templates: templates:
default:emoji/basic: default:emoji/basic:
content: <hover:show_text:'<i18n:emoji.tip>'><!shadow><white><arg:emoji></white></!shadow></hover> content: <hover:show_text:'<l10n:emoji.tip>'><!shadow><white><arg:emoji></white></!shadow></hover>
emoji: emoji:
default:emoji_smiley: default:emoji_smiley:
template: default:emoji/basic template: default:emoji/basic

View File

@@ -2,7 +2,7 @@ items:
default:bench: default:bench:
material: nether_brick material: nether_brick
data: data:
item-name: <!i><i18n:item.bench> item-name: <!i><l10n:item.bench>
model: model:
type: minecraft:model type: minecraft:model
path: minecraft:item/custom/bench path: minecraft:item/custom/bench

View File

@@ -2,7 +2,7 @@ items:
default:flower_basket: default:flower_basket:
material: nether_brick material: nether_brick
data: data:
item-name: <!i><i18n:item.flower_basket> item-name: <!i><l10n:item.flower_basket>
model: model:
template: default:model/simplified_generated template: default:model/simplified_generated
arguments: arguments:

View File

@@ -2,7 +2,7 @@ items:
default:wooden_chair: default:wooden_chair:
material: nether_brick material: nether_brick
data: data:
item-name: <!i><i18n:item.wooden_chair> item-name: <!i><l10n:item.wooden_chair>
model: model:
type: minecraft:model type: minecraft:model
path: minecraft:item/custom/wooden_chair path: minecraft:item/custom/wooden_chair

View File

@@ -4,7 +4,7 @@ items:
$$<=1.21.1: $$<=1.21.1:
client-bound-material: leather_horse_armor client-bound-material: leather_horse_armor
data: data:
item-name: <!i><white><i18n:item.cap> item-name: <!i><white><l10n:item.cap>
unbreakable: true unbreakable: true
remove-components: remove-components:
- attribute_modifiers - attribute_modifiers

View File

@@ -8,7 +8,7 @@ items:
asset-id: flame asset-id: flame
wings: flame_elytra wings: flame_elytra
data: data:
item-name: <!i><#FF8C00><i18n:item.flame_elytra> item-name: <!i><#FF8C00><l10n:item.flame_elytra>
model: model:
template: default:model/simplified_elytra template: default:model/simplified_elytra
arguments: arguments:

View File

@@ -2,7 +2,7 @@ templates:
default:armor/topaz: default:armor/topaz:
material: chainmail_${part} material: chainmail_${part}
data: data:
item-name: <!i><#FF8C00><i18n:item.topaz_${part}> item-name: <!i><#FF8C00><l10n:item.topaz_${part}>
tooltip-style: minecraft:topaz tooltip-style: minecraft:topaz
settings: settings:
tags: tags:

View File

@@ -5,7 +5,7 @@ items:
tags: tags:
- default:topaz_tools - default:topaz_tools
data: data:
item-name: <!i><#FF8C00><i18n:item.topaz_rod> item-name: <!i><#FF8C00><l10n:item.topaz_rod>
tooltip-style: minecraft:topaz tooltip-style: minecraft:topaz
model: model:
template: default:model/simplified_fishing_rod_2d template: default:model/simplified_fishing_rod_2d
@@ -18,7 +18,7 @@ items:
tags: tags:
- default:topaz_tools - default:topaz_tools
data: data:
item-name: <!i><#FF8C00><i18n:item.topaz_bow> item-name: <!i><#FF8C00><l10n:item.topaz_bow>
tooltip-style: minecraft:topaz tooltip-style: minecraft:topaz
model: model:
template: default:model/simplified_bow_2d template: default:model/simplified_bow_2d
@@ -33,7 +33,7 @@ items:
tags: tags:
- default:topaz_tools - default:topaz_tools
data: data:
item-name: <!i><#FF8C00><i18n:item.topaz_crossbow> item-name: <!i><#FF8C00><l10n:item.topaz_crossbow>
tooltip-style: minecraft:topaz tooltip-style: minecraft:topaz
model: model:
template: default:model/simplified_crossbow_2d template: default:model/simplified_crossbow_2d
@@ -50,7 +50,7 @@ items:
tags: tags:
- default:topaz_tools - default:topaz_tools
data: data:
item-name: <!i><#FF8C00><i18n:item.topaz_pickaxe> item-name: <!i><#FF8C00><l10n:item.topaz_pickaxe>
tooltip-style: minecraft:topaz tooltip-style: minecraft:topaz
max-damage: 64 max-damage: 64
model: model:
@@ -63,7 +63,7 @@ items:
tags: tags:
- default:topaz_tools - default:topaz_tools
data: data:
item-name: <!i><#FF8C00><i18n:item.topaz_axe> item-name: <!i><#FF8C00><l10n:item.topaz_axe>
tooltip-style: minecraft:topaz tooltip-style: minecraft:topaz
max-damage: 64 max-damage: 64
model: model:
@@ -76,7 +76,7 @@ items:
tags: tags:
- default:topaz_tools - default:topaz_tools
data: data:
item-name: <!i><#FF8C00><i18n:item.topaz_hoe> item-name: <!i><#FF8C00><l10n:item.topaz_hoe>
tooltip-style: minecraft:topaz tooltip-style: minecraft:topaz
max-damage: 64 max-damage: 64
model: model:
@@ -89,7 +89,7 @@ items:
tags: tags:
- default:topaz_tools - default:topaz_tools
data: data:
item-name: <!i><#FF8C00><i18n:item.topaz_shovel> item-name: <!i><#FF8C00><l10n:item.topaz_shovel>
tooltip-style: minecraft:topaz tooltip-style: minecraft:topaz
max-damage: 64 max-damage: 64
model: model:
@@ -102,7 +102,7 @@ items:
tags: tags:
- default:topaz_tools - default:topaz_tools
data: data:
item-name: <!i><#FF8C00><i18n:item.topaz_sword> item-name: <!i><#FF8C00><l10n:item.topaz_sword>
tooltip-style: minecraft:topaz tooltip-style: minecraft:topaz
max-damage: 64 max-damage: 64
model: model:
@@ -122,7 +122,7 @@ items:
tags: tags:
- default:topaz_tools - default:topaz_tools
data: data:
item-name: <!i><#FF8C00><i18n:item.topaz_trident> item-name: <!i><#FF8C00><l10n:item.topaz_trident>
tooltip-style: minecraft:topaz tooltip-style: minecraft:topaz
max-damage: 300 max-damage: 300
model: model:
@@ -163,7 +163,7 @@ items:
$$1.20.1~1.21.1: bow $$1.20.1~1.21.1: bow
$$1.21.2~1.21.3: honey_bottle $$1.21.2~1.21.3: honey_bottle
data: data:
item-name: <!i><#FF8C00><i18n:item.topaz_trident> item-name: <!i><#FF8C00><l10n:item.topaz_trident>
components: components:
minecraft:max_damage: 300 minecraft:max_damage: 300
$$>=1.21.2: $$>=1.21.2:

View File

@@ -2682,354 +2682,354 @@ templates#block_states:
state: ${base_block}[east=false,north=false,south=false,waterlogged=false,west=false] state: ${base_block}[east=false,north=false,south=false,waterlogged=false,west=false]
entity-renderer: entity-renderer:
- item: ${fence_post_item} - item: ${fence_post_item}
rotation: 180 yaw: 180
scale: 1.0003 scale: 1.0003
translation: 0,0.0001,0 translation: 0,0.0001,0
east=true,north=false,south=false,waterlogged=false,west=false: east=true,north=false,south=false,waterlogged=false,west=false:
state: ${base_block}[east=true,north=false,south=false,waterlogged=false,west=false] state: ${base_block}[east=true,north=false,south=false,waterlogged=false,west=false]
entity-renderer: entity-renderer:
- item: ${fence_post_item} - item: ${fence_post_item}
rotation: 180 yaw: 180
scale: 1.0003 scale: 1.0003
translation: 0,0.0001,0 translation: 0,0.0001,0
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 270 yaw: 270
east=false,north=true,south=false,waterlogged=false,west=false: east=false,north=true,south=false,waterlogged=false,west=false:
state: ${base_block}[east=false,north=true,south=false,waterlogged=false,west=false] state: ${base_block}[east=false,north=true,south=false,waterlogged=false,west=false]
entity-renderer: entity-renderer:
- item: ${fence_post_item} - item: ${fence_post_item}
rotation: 180 yaw: 180
scale: 1.0003 scale: 1.0003
translation: 0,0.0001,0 translation: 0,0.0001,0
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 180 yaw: 180
east=false,north=false,south=true,waterlogged=false,west=false: east=false,north=false,south=true,waterlogged=false,west=false:
state: ${base_block}[east=false,north=false,south=true,waterlogged=false,west=false] state: ${base_block}[east=false,north=false,south=true,waterlogged=false,west=false]
entity-renderer: entity-renderer:
- item: ${fence_post_item} - item: ${fence_post_item}
rotation: 180 yaw: 180
scale: 1.0003 scale: 1.0003
translation: 0,0.0001,0 translation: 0,0.0001,0
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 0 yaw: 0
east=false,north=false,south=false,waterlogged=false,west=true: east=false,north=false,south=false,waterlogged=false,west=true:
state: ${base_block}[east=false,north=false,south=false,waterlogged=false,west=true] state: ${base_block}[east=false,north=false,south=false,waterlogged=false,west=true]
entity-renderer: entity-renderer:
- item: ${fence_post_item} - item: ${fence_post_item}
rotation: 180 yaw: 180
scale: 1.0003 scale: 1.0003
translation: 0,0.0001,0 translation: 0,0.0001,0
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 90 yaw: 90
east=true,north=true,south=false,waterlogged=false,west=false: east=true,north=true,south=false,waterlogged=false,west=false:
state: ${base_block}[east=true,north=true,south=false,waterlogged=false,west=false] state: ${base_block}[east=true,north=true,south=false,waterlogged=false,west=false]
entity-renderer: entity-renderer:
- item: ${fence_post_item} - item: ${fence_post_item}
rotation: 180 yaw: 180
scale: 1.0003 scale: 1.0003
translation: 0,0.0001,0 translation: 0,0.0001,0
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 180 yaw: 180
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 270 yaw: 270
east=true,north=false,south=true,waterlogged=false,west=false: east=true,north=false,south=true,waterlogged=false,west=false:
state: ${base_block}[east=true,north=false,south=true,waterlogged=false,west=false] state: ${base_block}[east=true,north=false,south=true,waterlogged=false,west=false]
entity-renderer: entity-renderer:
- item: ${fence_post_item} - item: ${fence_post_item}
rotation: 180 yaw: 180
scale: 1.0003 scale: 1.0003
translation: 0,0.0001,0 translation: 0,0.0001,0
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 0 yaw: 0
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 270 yaw: 270
east=true,north=false,south=false,waterlogged=false,west=true: east=true,north=false,south=false,waterlogged=false,west=true:
state: ${base_block}[east=true,north=false,south=false,waterlogged=false,west=true] state: ${base_block}[east=true,north=false,south=false,waterlogged=false,west=true]
entity-renderer: entity-renderer:
- item: ${fence_post_item} - item: ${fence_post_item}
rotation: 180 yaw: 180
scale: 1.0003 scale: 1.0003
translation: 0,0.0001,0 translation: 0,0.0001,0
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 90 yaw: 90
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 270 yaw: 270
east=false,north=true,south=true,waterlogged=false,west=false: east=false,north=true,south=true,waterlogged=false,west=false:
state: ${base_block}[east=false,north=true,south=true,waterlogged=false,west=false] state: ${base_block}[east=false,north=true,south=true,waterlogged=false,west=false]
entity-renderer: entity-renderer:
- item: ${fence_post_item} - item: ${fence_post_item}
rotation: 180 yaw: 180
scale: 1.0003 scale: 1.0003
translation: 0,0.0001,0 translation: 0,0.0001,0
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 0 yaw: 0
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 180 yaw: 180
east=false,north=true,south=false,waterlogged=false,west=true: east=false,north=true,south=false,waterlogged=false,west=true:
state: ${base_block}[east=false,north=true,south=false,waterlogged=false,west=true] state: ${base_block}[east=false,north=true,south=false,waterlogged=false,west=true]
entity-renderer: entity-renderer:
- item: ${fence_post_item} - item: ${fence_post_item}
rotation: 180 yaw: 180
scale: 1.0003 scale: 1.0003
translation: 0,0.0001,0 translation: 0,0.0001,0
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 90 yaw: 90
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 180 yaw: 180
east=false,north=false,south=true,waterlogged=false,west=true: east=false,north=false,south=true,waterlogged=false,west=true:
state: ${base_block}[east=false,north=false,south=true,waterlogged=false,west=true] state: ${base_block}[east=false,north=false,south=true,waterlogged=false,west=true]
entity-renderer: entity-renderer:
- item: ${fence_post_item} - item: ${fence_post_item}
rotation: 180 yaw: 180
scale: 1.0003 scale: 1.0003
translation: 0,0.0001,0 translation: 0,0.0001,0
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 0 yaw: 0
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 90 yaw: 90
east=true,north=true,south=true,waterlogged=false,west=false: east=true,north=true,south=true,waterlogged=false,west=false:
state: ${base_block}[east=true,north=true,south=true,waterlogged=false,west=false] state: ${base_block}[east=true,north=true,south=true,waterlogged=false,west=false]
entity-renderer: entity-renderer:
- item: ${fence_post_item} - item: ${fence_post_item}
rotation: 180 yaw: 180
scale: 1.0003 scale: 1.0003
translation: 0,0.0001,0 translation: 0,0.0001,0
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 0 yaw: 0
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 180 yaw: 180
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 270 yaw: 270
east=true,north=true,south=false,waterlogged=false,west=true: east=true,north=true,south=false,waterlogged=false,west=true:
state: ${base_block}[east=true,north=true,south=false,waterlogged=false,west=true] state: ${base_block}[east=true,north=true,south=false,waterlogged=false,west=true]
entity-renderer: entity-renderer:
- item: ${fence_post_item} - item: ${fence_post_item}
rotation: 180 yaw: 180
scale: 1.0003 scale: 1.0003
translation: 0,0.0001,0 translation: 0,0.0001,0
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 90 yaw: 90
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 180 yaw: 180
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 270 yaw: 270
east=true,north=false,south=true,waterlogged=false,west=true: east=true,north=false,south=true,waterlogged=false,west=true:
state: ${base_block}[east=true,north=false,south=true,waterlogged=false,west=true] state: ${base_block}[east=true,north=false,south=true,waterlogged=false,west=true]
entity-renderer: entity-renderer:
- item: ${fence_post_item} - item: ${fence_post_item}
rotation: 180 yaw: 180
scale: 1.0003 scale: 1.0003
translation: 0,0.0001,0 translation: 0,0.0001,0
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 0 yaw: 0
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 90 yaw: 90
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 270 yaw: 270
east=false,north=true,south=true,waterlogged=false,west=true: east=false,north=true,south=true,waterlogged=false,west=true:
state: ${base_block}[east=false,north=true,south=true,waterlogged=false,west=true] state: ${base_block}[east=false,north=true,south=true,waterlogged=false,west=true]
entity-renderer: entity-renderer:
- item: ${fence_post_item} - item: ${fence_post_item}
rotation: 180 yaw: 180
scale: 1.0003 scale: 1.0003
translation: 0,0.0001,0 translation: 0,0.0001,0
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 0 yaw: 0
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 90 yaw: 90
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 180 yaw: 180
east=true,north=true,south=true,waterlogged=false,west=true: east=true,north=true,south=true,waterlogged=false,west=true:
state: ${base_block}[east=true,north=true,south=true,waterlogged=false,west=true] state: ${base_block}[east=true,north=true,south=true,waterlogged=false,west=true]
entity-renderer: entity-renderer:
- item: ${fence_post_item} - item: ${fence_post_item}
rotation: 180 yaw: 180
scale: 1.0003 scale: 1.0003
translation: 0,0.0001,0 translation: 0,0.0001,0
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 0 yaw: 0
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 90 yaw: 90
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 180 yaw: 180
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 270 yaw: 270
east=false,north=false,south=false,waterlogged=true,west=false: east=false,north=false,south=false,waterlogged=true,west=false:
state: ${base_block}[east=false,north=false,south=false,waterlogged=true,west=false] state: ${base_block}[east=false,north=false,south=false,waterlogged=true,west=false]
entity-renderer: entity-renderer:
- item: ${fence_post_item} - item: ${fence_post_item}
rotation: 180 yaw: 180
scale: 1.0003 scale: 1.0003
translation: 0,0.0001,0 translation: 0,0.0001,0
east=true,north=false,south=false,waterlogged=true,west=false: east=true,north=false,south=false,waterlogged=true,west=false:
state: ${base_block}[east=true,north=false,south=false,waterlogged=true,west=false] state: ${base_block}[east=true,north=false,south=false,waterlogged=true,west=false]
entity-renderer: entity-renderer:
- item: ${fence_post_item} - item: ${fence_post_item}
rotation: 180 yaw: 180
scale: 1.0003 scale: 1.0003
translation: 0,0.0001,0 translation: 0,0.0001,0
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 270 yaw: 270
east=false,north=true,south=false,waterlogged=true,west=false: east=false,north=true,south=false,waterlogged=true,west=false:
state: ${base_block}[east=false,north=true,south=false,waterlogged=true,west=false] state: ${base_block}[east=false,north=true,south=false,waterlogged=true,west=false]
entity-renderer: entity-renderer:
- item: ${fence_post_item} - item: ${fence_post_item}
rotation: 180 yaw: 180
scale: 1.0003 scale: 1.0003
translation: 0,0.0001,0 translation: 0,0.0001,0
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 180 yaw: 180
east=false,north=false,south=true,waterlogged=true,west=false: east=false,north=false,south=true,waterlogged=true,west=false:
state: ${base_block}[east=false,north=false,south=true,waterlogged=true,west=false] state: ${base_block}[east=false,north=false,south=true,waterlogged=true,west=false]
entity-renderer: entity-renderer:
- item: ${fence_post_item} - item: ${fence_post_item}
rotation: 180 yaw: 180
scale: 1.0003 scale: 1.0003
translation: 0,0.0001,0 translation: 0,0.0001,0
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 0 yaw: 0
east=false,north=false,south=false,waterlogged=true,west=true: east=false,north=false,south=false,waterlogged=true,west=true:
state: ${base_block}[east=false,north=false,south=false,waterlogged=true,west=true] state: ${base_block}[east=false,north=false,south=false,waterlogged=true,west=true]
entity-renderer: entity-renderer:
- item: ${fence_post_item} - item: ${fence_post_item}
rotation: 180 yaw: 180
scale: 1.0003 scale: 1.0003
translation: 0,0.0001,0 translation: 0,0.0001,0
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 90 yaw: 90
east=true,north=true,south=false,waterlogged=true,west=false: east=true,north=true,south=false,waterlogged=true,west=false:
state: ${base_block}[east=true,north=true,south=false,waterlogged=true,west=false] state: ${base_block}[east=true,north=true,south=false,waterlogged=true,west=false]
entity-renderer: entity-renderer:
- item: ${fence_post_item} - item: ${fence_post_item}
rotation: 180 yaw: 180
scale: 1.0003 scale: 1.0003
translation: 0,0.0001,0 translation: 0,0.0001,0
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 180 yaw: 180
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 270 yaw: 270
east=true,north=false,south=true,waterlogged=true,west=false: east=true,north=false,south=true,waterlogged=true,west=false:
state: ${base_block}[east=true,north=false,south=true,waterlogged=true,west=false] state: ${base_block}[east=true,north=false,south=true,waterlogged=true,west=false]
entity-renderer: entity-renderer:
- item: ${fence_post_item} - item: ${fence_post_item}
rotation: 180 yaw: 180
scale: 1.0003 scale: 1.0003
translation: 0,0.0001,0 translation: 0,0.0001,0
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 0 yaw: 0
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 270 yaw: 270
east=true,north=false,south=false,waterlogged=true,west=true: east=true,north=false,south=false,waterlogged=true,west=true:
state: ${base_block}[east=true,north=false,south=false,waterlogged=true,west=true] state: ${base_block}[east=true,north=false,south=false,waterlogged=true,west=true]
entity-renderer: entity-renderer:
- item: ${fence_post_item} - item: ${fence_post_item}
rotation: 180 yaw: 180
scale: 1.0003 scale: 1.0003
translation: 0,0.0001,0 translation: 0,0.0001,0
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 90 yaw: 90
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 270 yaw: 270
east=false,north=true,south=true,waterlogged=true,west=false: east=false,north=true,south=true,waterlogged=true,west=false:
state: ${base_block}[east=false,north=true,south=true,waterlogged=true,west=false] state: ${base_block}[east=false,north=true,south=true,waterlogged=true,west=false]
entity-renderer: entity-renderer:
- item: ${fence_post_item} - item: ${fence_post_item}
rotation: 180 yaw: 180
scale: 1.0003 scale: 1.0003
translation: 0,0.0001,0 translation: 0,0.0001,0
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 0 yaw: 0
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 180 yaw: 180
east=false,north=true,south=false,waterlogged=true,west=true: east=false,north=true,south=false,waterlogged=true,west=true:
state: ${base_block}[east=false,north=true,south=false,waterlogged=true,west=true] state: ${base_block}[east=false,north=true,south=false,waterlogged=true,west=true]
entity-renderer: entity-renderer:
- item: ${fence_post_item} - item: ${fence_post_item}
rotation: 180 yaw: 180
scale: 1.0003 scale: 1.0003
translation: 0,0.0001,0 translation: 0,0.0001,0
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 90 yaw: 90
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 180 yaw: 180
east=false,north=false,south=true,waterlogged=true,west=true: east=false,north=false,south=true,waterlogged=true,west=true:
state: ${base_block}[east=false,north=false,south=true,waterlogged=true,west=true] state: ${base_block}[east=false,north=false,south=true,waterlogged=true,west=true]
entity-renderer: entity-renderer:
- item: ${fence_post_item} - item: ${fence_post_item}
rotation: 180 yaw: 180
scale: 1.0003 scale: 1.0003
translation: 0,0.0001,0 translation: 0,0.0001,0
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 0 yaw: 0
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 90 yaw: 90
east=true,north=true,south=true,waterlogged=true,west=false: east=true,north=true,south=true,waterlogged=true,west=false:
state: ${base_block}[east=true,north=true,south=true,waterlogged=true,west=false] state: ${base_block}[east=true,north=true,south=true,waterlogged=true,west=false]
entity-renderer: entity-renderer:
- item: ${fence_post_item} - item: ${fence_post_item}
rotation: 180 yaw: 180
scale: 1.0003 scale: 1.0003
translation: 0,0.0001,0 translation: 0,0.0001,0
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 0 yaw: 0
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 180 yaw: 180
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 270 yaw: 270
east=true,north=true,south=false,waterlogged=true,west=true: east=true,north=true,south=false,waterlogged=true,west=true:
state: ${base_block}[east=true,north=true,south=false,waterlogged=true,west=true] state: ${base_block}[east=true,north=true,south=false,waterlogged=true,west=true]
entity-renderer: entity-renderer:
- item: ${fence_post_item} - item: ${fence_post_item}
rotation: 180 yaw: 180
scale: 1.0003 scale: 1.0003
translation: 0,0.0001,0 translation: 0,0.0001,0
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 90 yaw: 90
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 180 yaw: 180
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 270 yaw: 270
east=true,north=false,south=true,waterlogged=true,west=true: east=true,north=false,south=true,waterlogged=true,west=true:
state: ${base_block}[east=true,north=false,south=true,waterlogged=true,west=true] state: ${base_block}[east=true,north=false,south=true,waterlogged=true,west=true]
entity-renderer: entity-renderer:
- item: ${fence_post_item} - item: ${fence_post_item}
rotation: 180 yaw: 180
scale: 1.0003 scale: 1.0003
translation: 0,0.0001,0 translation: 0,0.0001,0
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 0 yaw: 0
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 90 yaw: 90
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 270 yaw: 270
east=false,north=true,south=true,waterlogged=true,west=true: east=false,north=true,south=true,waterlogged=true,west=true:
state: ${base_block}[east=false,north=true,south=true,waterlogged=true,west=true] state: ${base_block}[east=false,north=true,south=true,waterlogged=true,west=true]
entity-renderer: entity-renderer:
- item: ${fence_post_item} - item: ${fence_post_item}
rotation: 180 yaw: 180
scale: 1.0003 scale: 1.0003
translation: 0,0.0001,0 translation: 0,0.0001,0
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 0 yaw: 0
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 90 yaw: 90
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 180 yaw: 180
east=true,north=true,south=true,waterlogged=true,west=true: east=true,north=true,south=true,waterlogged=true,west=true:
state: ${base_block}[east=true,north=true,south=true,waterlogged=true,west=true] state: ${base_block}[east=true,north=true,south=true,waterlogged=true,west=true]
entity-renderer: entity-renderer:
- item: ${fence_post_item} - item: ${fence_post_item}
rotation: 180 yaw: 180
scale: 1.0003 scale: 1.0003
translation: 0,0.0001,0 translation: 0,0.0001,0
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 0 yaw: 0
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 90 yaw: 90
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 180 yaw: 180
- item: ${fence_side_item} - item: ${fence_side_item}
rotation: 270 yaw: 270
variants: variants:
waterlogged=true: waterlogged=true:
settings: settings:

View File

@@ -2,6 +2,4 @@ author: XiaoMoMi
version: 0.0.1 version: 0.0.1
description: Fix broken vanilla armor description: Fix broken vanilla armor
namespace: minecraft namespace: minecraft
enable: enable: false
$$>=1.21.2: false
$$<1.21.2: true

View File

@@ -374,6 +374,7 @@ warning.config.loot_table.function.apply_bonus.missing_enchantment: "<yellow>Iss
warning.config.loot_table.function.apply_bonus.missing_formula: "<yellow>Issue found in file <arg:0> - '<arg:1>' has a misconfigured loot table, function 'apply_bonus' is missing the required 'formula' argument.</yellow>" warning.config.loot_table.function.apply_bonus.missing_formula: "<yellow>Issue found in file <arg:0> - '<arg:1>' has a misconfigured loot table, function 'apply_bonus' is missing the required 'formula' argument.</yellow>"
warning.config.loot_table.function.drop_exp.missing_count: "<yellow>Issue found in file <arg:0> - '<arg:1>' has a misconfigured loot table, function 'drop_exp' is missing the required 'count' argument.</yellow>" warning.config.loot_table.function.drop_exp.missing_count: "<yellow>Issue found in file <arg:0> - '<arg:1>' has a misconfigured loot table, function 'drop_exp' is missing the required 'count' argument.</yellow>"
warning.config.loot_table.function.set_count.missing_count: "<yellow>Issue found in file <arg:0> - '<arg:1>' has a misconfigured loot table, function 'set_count' is missing the required 'count' argument.</yellow>" warning.config.loot_table.function.set_count.missing_count: "<yellow>Issue found in file <arg:0> - '<arg:1>' has a misconfigured loot table, function 'set_count' is missing the required 'count' argument.</yellow>"
warning.config.loot_table.function.apply_data.missing_data: "<yellow>Issue found in file <arg:0> - '<arg:1>' has a misconfigured loot table, function 'apply_data' is missing the required 'data' argument.</yellow>"
warning.config.loot_table.entry.missing_type: "<yellow>Issue found in file <arg:0> - '<arg:1>' has a misconfigured loot table, one of the entries is missing the required 'type' argument.</yellow>" warning.config.loot_table.entry.missing_type: "<yellow>Issue found in file <arg:0> - '<arg:1>' has a misconfigured loot table, one of the entries is missing the required 'type' argument.</yellow>"
warning.config.loot_table.entry.invalid_type: "<yellow>Issue found in file <arg:0> - '<arg:1>' has a misconfigured loot table, one of the entries is using an invalid entry type '<arg:2>'.</yellow>" warning.config.loot_table.entry.invalid_type: "<yellow>Issue found in file <arg:0> - '<arg:1>' has a misconfigured loot table, one of the entries is using an invalid entry type '<arg:2>'.</yellow>"
warning.config.loot_table.entry.exp.missing_count: "<yellow>Issue found in file <arg:0> - '<arg:1>' has a misconfigured loot table, entry 'exp' is missing the required 'count' argument.</yellow>" warning.config.loot_table.entry.exp.missing_count: "<yellow>Issue found in file <arg:0> - '<arg:1>' has a misconfigured loot table, entry 'exp' is missing the required 'count' argument.</yellow>"

View File

@@ -65,6 +65,9 @@ command.upload.failure.not_supported: "<red>当前托管模式 '<arg:0>' 不支
command.upload.on_progress: "<white>已开始上传进程. 检查控制台以获取详细信息</white>" command.upload.on_progress: "<white>已开始上传进程. 检查控制台以获取详细信息</white>"
command.send_resource_pack.success.single: "<white>发送资源包给 <arg:0></white>" command.send_resource_pack.success.single: "<white>发送资源包给 <arg:0></white>"
command.send_resource_pack.success.multiple: "<white>发送资源包给 <arg:0> 个玩家</white>" command.send_resource_pack.success.multiple: "<white>发送资源包给 <arg:0> 个玩家</white>"
command.locale.set.failure: "<red>区域设置格式无效: <arg:0></red>"
command.locale.set.success: "<white>已为 <arg:1> 更新选定区域设置为 <arg:0></white>"
command.locale.unset.success: "<white>已清除 <arg:0> 的选定区域设置</white>"
warning.network.resource_pack.unverified_uuid: "<yellow>玩家 <arg:0> 使用未经服务器验证的 UUID (<arg:1>) 尝试请求获取资源包</yellow>" warning.network.resource_pack.unverified_uuid: "<yellow>玩家 <arg:0> 使用未经服务器验证的 UUID (<arg:1>) 尝试请求获取资源包</yellow>"
warning.config.pack.duplicated_files: "<red>发现重复文件 请通过 config.yml 的 'resource-pack.duplicated-files-handler' 部分解决</red>" warning.config.pack.duplicated_files: "<red>发现重复文件 请通过 config.yml 的 'resource-pack.duplicated-files-handler' 部分解决</red>"
warning.config.yaml.duplicated_key: "<red>在文件 <arg:0> 发现问题 - 在第<arg:2>行发现重复的键 '<arg:1>', 这可能会导致一些意料之外的问题</red>" warning.config.yaml.duplicated_key: "<red>在文件 <arg:0> 发现问题 - 在第<arg:2>行发现重复的键 '<arg:1>', 这可能会导致一些意料之外的问题</red>"
@@ -160,10 +163,10 @@ warning.config.recipe.result.post_processor.missing_type: "<yellow>在文件 <ar
warning.config.recipe.result.post_processor.invalid_type: "<yellow>在文件 <arg:0> 发现问题 - 配方 '<arg:1>' 使用了无效结果后处理器类型 '<arg:2>'</yellow>" warning.config.recipe.result.post_processor.invalid_type: "<yellow>在文件 <arg:0> 发现问题 - 配方 '<arg:1>' 使用了无效结果后处理器类型 '<arg:2>'</yellow>"
warning.config.translation.unknown_locale: "<yellow>在文件 <arg:0> 发现问题 - 未知的语言环境 '<arg:1>'</yellow>" warning.config.translation.unknown_locale: "<yellow>在文件 <arg:0> 发现问题 - 未知的语言环境 '<arg:1>'</yellow>"
warning.config.template.duplicate: "<yellow>在文件 <arg:0> 发现问题 - 重复的模板 '<arg:1>' 请检查其他文件中是否存在相同配置</yellow>" warning.config.template.duplicate: "<yellow>在文件 <arg:0> 发现问题 - 重复的模板 '<arg:1>' 请检查其他文件中是否存在相同配置</yellow>"
warning.config.template.invalid: "<yellow>在文件 <arg:0> 发现问题 - 配置 '<arg:1>' 使用了无效的模板 '<arg:2>'</yellow>" warning.config.template.invalid: "<yellow>在文件 <arg:0> 发现问题 - 配置 '<arg:1>' 使用了无效的模板 '<arg:2>'</yellow>"
warning.config.template.argument.self_increase_int.invalid_range: "<yellow>在文件 <arg:0> 发现问题 - 模板 '<arg:1>' 在 'self_increase_int' 参数中使用了一个起始值 '<arg:2>' 大于终止值 '<arg:3>'</yellow>" warning.config.template.argument.self_increase_int.invalid_range: "<yellow>在文件 <arg:0> 发现问题 - 模板 '<arg:1>' 在 'self_increase_int' 参数中使用了一个起始值 '<arg:2>' 大于终止值 '<arg:3>'</yellow>"
warning.config.template.argument.list.invalid_type: "<yellow>在文件 <arg:0> 发现问题 - 模板 '<arg:1>' 的 'list' 参数需要列表类型 但输入参数类型为 '<arg:2>'</yellow>" warning.config.template.argument.list.invalid_type: "<yellow>在文件 <arg:0> 发现问题 - 模板 '<arg:1>' 的 'list' 参数需要列表类型 但输入参数类型为 '<arg:2>'</yellow>"
warning.config.template.argument.missing_value: "<yellow>在文件 <arg:0> 发现问题 - 配置 '<arg:1>' 缺少了 '<arg:2>' 必要的模板参数值. 请使用 arguments 选项进行配置或为此参数设定默认值</yellow>" warning.config.template.argument.missing_value: "<yellow>在文件 <arg:0> 发现问题 - 配置 '<arg:1>' 缺少了 '<arg:2>' 必要的模板参数值. 请使用 arguments 选项进行配置或为此参数设定默认值</yellow>"
warning.config.vanilla_loot.missing_type: "<yellow>在文件 <arg:0> 发现问题 - 原版战利品 '<arg:1>' 缺少必需的 'type' 参数</yellow>" warning.config.vanilla_loot.missing_type: "<yellow>在文件 <arg:0> 发现问题 - 原版战利品 '<arg:1>' 缺少必需的 'type' 参数</yellow>"
warning.config.vanilla_loot.invalid_type: "<yellow>在文件 <arg:0> 发现问题 - 原版战利品 '<arg:1>' 使用了无效类型 '<arg:2>' 允许的类型: [<arg:3>]</yellow>" warning.config.vanilla_loot.invalid_type: "<yellow>在文件 <arg:0> 发现问题 - 原版战利品 '<arg:1>' 使用了无效类型 '<arg:2>' 允许的类型: [<arg:3>]</yellow>"
warning.config.vanilla_loot.block.invalid_target: "<yellow>在文件 <arg:0> 发现问题 - 原版战利品 '<arg:1>' 中存在无效的方块目标 '<arg:2>'</yellow>" warning.config.vanilla_loot.block.invalid_target: "<yellow>在文件 <arg:0> 发现问题 - 原版战利品 '<arg:1>' 中存在无效的方块目标 '<arg:2>'</yellow>"
@@ -184,6 +187,10 @@ warning.config.item.settings.invulnerable.invalid_damage_source: "<yellow>在文
warning.config.item.settings.equipment.missing_asset_id: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 缺少 'equipment' 设置所需的 'asset-id' 参数</yellow>" warning.config.item.settings.equipment.missing_asset_id: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 缺少 'equipment' 设置所需的 'asset-id' 参数</yellow>"
warning.config.item.settings.equipment.invalid_asset_id: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 为 'equipment' 设置配置了无效的 'asset-id'. 这可能是因为你没有创建装备配置或是错误地拼写了 asset-id</yellow>" warning.config.item.settings.equipment.invalid_asset_id: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 为 'equipment' 设置配置了无效的 'asset-id'. 这可能是因为你没有创建装备配置或是错误地拼写了 asset-id</yellow>"
warning.config.item.settings.projectile.missing_item: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 缺少 'projectile' 设置所需的 'item' 参数</yellow>" warning.config.item.settings.projectile.missing_item: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 缺少 'projectile' 设置所需的 'item' 参数</yellow>"
warning.config.item.settings.craft_remainder.missing_type: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 缺少 'craft-remainder' 所需的 'type' 参数</yellow>"
warning.config.item.settings.craft_remainder.invalid_type: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 使用了无效的合成剩余物品类型 '<arg:2>'</yellow>"
warning.config.item.settings.craft_remainder.fixed.missing_item: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 的固定 'craft-remainder' 缺少所需的 'item' 参数</yellow>"
warning.config.item.settings.craft_remainder.recipe_based.missing_terms: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 缺少基于配方的 'craft-remainder' 所需的 'terms' 参数</yellow>"
warning.config.item.data.attribute_modifiers.missing_type: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 缺少 'attribute-modifiers' 数据所需的 'type' 参数</yellow>" warning.config.item.data.attribute_modifiers.missing_type: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 缺少 'attribute-modifiers' 数据所需的 'type' 参数</yellow>"
warning.config.item.data.attribute_modifiers.missing_amount: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 缺少 'attribute-modifiers' 数据所需的 'amount' 参数</yellow>" warning.config.item.data.attribute_modifiers.missing_amount: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 缺少 'attribute-modifiers' 数据所需的 'amount' 参数</yellow>"
warning.config.item.data.attribute_modifiers.missing_operation: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 缺少 'attribute-modifiers' 数据所需的 'operation' 参数</yellow>" warning.config.item.data.attribute_modifiers.missing_operation: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 缺少 'attribute-modifiers' 数据所需的 'operation' 参数</yellow>"
@@ -263,8 +270,8 @@ warning.config.item.model.special.copper_golem_statue.missing_texture: "<yellow>
warning.config.item.updater.missing_type: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 缺少物品更新器必需的参数 'type'</yellow>" warning.config.item.updater.missing_type: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 缺少物品更新器必需的参数 'type'</yellow>"
warning.config.item.updater.invalid_type: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 在物品更新器中使用了无效的 'type' 参数值 '<arg:2>'</yellow>" warning.config.item.updater.invalid_type: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 在物品更新器中使用了无效的 'type' 参数值 '<arg:2>'</yellow>"
warning.config.item.updater.transmute.missing_material: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 缺少物品转换更新所需的 'material' 参数</yellow>" warning.config.item.updater.transmute.missing_material: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 缺少物品转换更新所需的 'material' 参数</yellow>"
warning.config.block_state_mapping.invalid_state: "<yellow>在文件 <arg:0> 发现问题 - 配置 '<arg:1>' 使用了无效的方块状态 '<arg:2>'</yellow>" warning.config.block_state_mapping.invalid_state: "<yellow>在文件 <arg:0> 发现问题 - 配置 '<arg:1>' 使用了无效的方块状态 '<arg:2>'</yellow>"
warning.config.block_state_mapping.conflict: "<yellow>在文件 <arg:0> 发现问题 - 配置 '<arg:1>' 无法将方块状态 <arg:2> 映射到方块状态 <arg:3>, 因为该状态已被映射到 <arg:4></yellow>" warning.config.block_state_mapping.conflict: "<yellow>在文件 <arg:0> 发现问题 - 配置 '<arg:1>' 无法将方块状态 <arg:2> 映射到方块状态 <arg:3>, 因为该状态已被映射到 <arg:4></yellow>"
warning.config.block.duplicate: "<yellow>在文件 <arg:0> 发现问题 - 重复的方块 '<arg:1>' 请检查其他文件中是否存在相同配置</yellow>" warning.config.block.duplicate: "<yellow>在文件 <arg:0> 发现问题 - 重复的方块 '<arg:1>' 请检查其他文件中是否存在相同配置</yellow>"
warning.config.block.missing_state: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 缺少必需的 'state' 参数</yellow>" warning.config.block.missing_state: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 缺少必需的 'state' 参数</yellow>"
warning.config.block.state.property.missing_type: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 的属性 '<arg:2>' 缺少必需的 'type' 参数</yellow>" warning.config.block.state.property.missing_type: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 的属性 '<arg:2>' 缺少必需的 'type' 参数</yellow>"
@@ -454,14 +461,21 @@ warning.config.function.remove_cooldown.missing_id: "<yellow>在文件 <arg:0>
warning.config.function.mythic_mobs_skill.missing_skill: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少 'mythic_mobs_skill' 函数必需的 'skill' 参数</yellow>" warning.config.function.mythic_mobs_skill.missing_skill: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少 'mythic_mobs_skill' 函数必需的 'skill' 参数</yellow>"
warning.config.function.spawn_furniture.missing_furniture_id: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少 'spawn_furniture' 函数必需的 'furniture-id' 参数</yellow>" warning.config.function.spawn_furniture.missing_furniture_id: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少 'spawn_furniture' 函数必需的 'furniture-id' 参数</yellow>"
warning.config.function.replace_furniture.missing_furniture_id: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少 'replace_furniture' 函数必需的 'furniture-id' 参数</yellow>" warning.config.function.replace_furniture.missing_furniture_id: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少 'replace_furniture' 函数必需的 'furniture-id' 参数</yellow>"
warning.config.function.teleport.missing_x: "<yellow>在文件 <arg:0> 发现问题 - 配置 '<arg:1>' 缺少 'teleport' 函数所需的 'x' 参数</yellow>" warning.config.function.teleport.missing_x: "<yellow>在文件 <arg:0> 发现问题 - 配置 '<arg:1>' 缺少 'teleport' 函数所需的 'x' 参数</yellow>"
warning.config.function.teleport.missing_y: "<yellow>在文件 <arg:0> 发现问题 - 配置 '<arg:1>' 缺少 'teleport' 函数所需的 'y' 参数</yellow>" warning.config.function.teleport.missing_y: "<yellow>在文件 <arg:0> 发现问题 - 配置 '<arg:1>' 缺少 'teleport' 函数所需的 'y' 参数</yellow>"
warning.config.function.teleport.missing_z: "<yellow>在文件 <arg:0> 发现问题 - 配置 '<arg:1>' 缺少 'teleport' 函数所需的 'z' 参数</yellow>" warning.config.function.teleport.missing_z: "<yellow>在文件 <arg:0> 发现问题 - 配置 '<arg:1>' 缺少 'teleport' 函数所需的 'z' 参数</yellow>"
warning.config.function.set_variable.missing_name: "<yellow>在文件 <arg:0> 发现问题 - 配置 '<arg:1>' 缺少 'set_variable' 函数所需的 'name' 参数</yellow>" warning.config.function.set_variable.missing_name: "<yellow>在文件 <arg:0> 发现问题 - 配置 '<arg:1>' 缺少 'set_variable' 函数所需的 'name' 参数</yellow>"
warning.config.function.set_variable.missing_value: "<yellow>在文件 <arg:0> 发现问题 - 配置 '<arg:1>' 缺少 'set_variable' 函数所需的 'number' 或 'text' 参数</yellow>" warning.config.function.set_variable.missing_value: "<yellow>在文件 <arg:0> 发现问题 - 配置 '<arg:1>' 缺少 'set_variable' 函数所需的 'number' 或 'text' 参数</yellow>"
warning.config.function.toast.missing_toast: "<yellow>在文件 <arg:0> 发现问题 - 配置 '<arg:1>' 缺少 'toast' 函数所需的 'toast' 参数</yellow>" warning.config.function.toast.missing_toast: "<yellow>在文件 <arg:0> 发现问题 - 配置 '<arg:1>' 缺少 'toast' 函数所需的 'toast' 参数</yellow>"
warning.config.function.toast.missing_icon: "<yellow>在文件 <arg:0> 发现问题 - 配置 '<arg:1>' 缺少 'toast' 函数所需的 'icon' 参数</yellow>" warning.config.function.toast.missing_icon: "<yellow>在文件 <arg:0> 发现问题 - 配置 '<arg:1>' 缺少 'toast' 函数所需的 'icon' 参数</yellow>"
warning.config.function.toast.invalid_advancement_type: "<yellow>在文件 <arg:0> 发现问题 - 配置 '<arg:1>' 为 'toast' 函数使用了无效的进度类型 '<arg:2>'. 允许的类型: [<arg:3>]</yellow>" warning.config.function.toast.invalid_advancement_type: "<yellow>在文件 <arg:0> 发现问题 - 配置 '<arg:1>' 为 'toast' 函数使用了无效的进度类型 '<arg:2>'. 允许的类型: [<arg:3>]</yellow>"
warning.config.function.merchant_trade.missing_offers: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少 'merchant_trade' 函数所需的 'offers' 参数</yellow>"
warning.config.function.merchant_trade.offer.missing_cost_1: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少'merchant_trade' 函数所需的 'cost-1' 参数</yellow>"
warning.config.function.merchant_trade.offer.missing_result: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少'merchant_trade' 函数所需的 'result' 参数</yellow>"
warning.config.function.when.missing_source: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少 'when' 函数所需的 'source' 参数</yellow>"
warning.config.function.if_else.missing_rules: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少 'if_else' 函数所需的 'rules' 参数</yellow>"
warning.config.function.update_block_property.missing_properties: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少 'update_block_property' 函数所需的 'properties' 参数</yellow>"
warning.config.function.transform_block.missing_block: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少 'transform_block' 函数所需的 'block' 参数</yellow>"
warning.config.selector.missing_type: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少选择器必需的 'type' 参数</yellow>" warning.config.selector.missing_type: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少选择器必需的 'type' 参数</yellow>"
warning.config.selector.invalid_type: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 使用了无效的选择器类型 '<arg:2>'</yellow>" warning.config.selector.invalid_type: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 使用了无效的选择器类型 '<arg:2>'</yellow>"
warning.config.selector.invalid_target: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 使用了无效的选择器目标 '<arg:2>'</yellow>" warning.config.selector.invalid_target: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 使用了无效的选择器目标 '<arg:2>'</yellow>"
@@ -474,6 +488,7 @@ warning.config.resource_pack.generation.missing_item_model: "<yellow>物品'<arg
warning.config.resource_pack.generation.missing_block_model: "<yellow>方块状态'<arg:0>'缺少模型文件: '<arg:1>'</yellow>" warning.config.resource_pack.generation.missing_block_model: "<yellow>方块状态'<arg:0>'缺少模型文件: '<arg:1>'</yellow>"
warning.config.resource_pack.generation.missing_parent_model: "<yellow>模型'<arg:0>'找不到父级模型文件: '<arg:1>'</yellow>" warning.config.resource_pack.generation.missing_parent_model: "<yellow>模型'<arg:0>'找不到父级模型文件: '<arg:1>'</yellow>"
warning.config.resource_pack.generation.missing_equipment_texture: "<yellow>装备 '<arg:0>' 缺少纹理 '<arg:1>'</yellow>" warning.config.resource_pack.generation.missing_equipment_texture: "<yellow>装备 '<arg:0>' 缺少纹理 '<arg:1>'</yellow>"
warning.config.resource_pack.generation.missing_sound: "<yellow>声音事件 '<arg:0>' 缺少 ogg 文件 '<arg:1>'</yellow>"
warning.config.resource_pack.generation.texture_not_in_atlas: "<yellow>纹理'<arg:0>'不在图集内. 你需要将纹理路径或文件夹前缀添加到图集内, 或者启用 config.yml 中的 'fix-atlas' 选项</yellow>" warning.config.resource_pack.generation.texture_not_in_atlas: "<yellow>纹理'<arg:0>'不在图集内. 你需要将纹理路径或文件夹前缀添加到图集内, 或者启用 config.yml 中的 'fix-atlas' 选项</yellow>"
warning.config.resource_pack.invalid_overlay_format: "<yellow>在 config.yml 的 'resource-pack.overlay-format' 处发现问题 - 无效的overlay格式 '<arg:0>'. Overlay格式必须包含占位符 '{version}'</yellow>" warning.config.resource_pack.invalid_overlay_format: "<yellow>在 config.yml 的 'resource-pack.overlay-format' 处发现问题 - 无效的overlay格式 '<arg:0>'. Overlay格式必须包含占位符 '{version}'</yellow>"
warning.config.equipment.duplicate: "<yellow>在文件 <arg:0> 发现问题 - 重复的装备配置 '<arg:1>'. 请检查其他文件中是否存在相同配置</yellow>" warning.config.equipment.duplicate: "<yellow>在文件 <arg:0> 发现问题 - 重复的装备配置 '<arg:1>'. 请检查其他文件中是否存在相同配置</yellow>"

View File

@@ -143,7 +143,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
@Override @Override
public void delayedLoad() { public void delayedLoad() {
this.initSuggestions(); this.initSuggestions();
this.resendTags(); this.updateTags();
this.processSounds(); this.processSounds();
this.clearCache(); this.clearCache();
} }
@@ -232,7 +232,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
public abstract BlockBehavior createBlockBehavior(CustomBlock customBlock, List<Map<String, Object>> behaviorConfig); public abstract BlockBehavior createBlockBehavior(CustomBlock customBlock, List<Map<String, Object>> behaviorConfig);
protected abstract void resendTags(); protected abstract void updateTags();
protected abstract boolean isVanillaBlock(Key id); protected abstract boolean isVanillaBlock(Key id);

View File

@@ -330,6 +330,37 @@ public final class BlockKeys {
public static final Key CHERRY_SAPLING = Key.of("minecraft:cherry_sapling"); public static final Key CHERRY_SAPLING = Key.of("minecraft:cherry_sapling");
public static final Key PALE_OAK_SAPLING = Key.of("minecraft:pale_oak_sapling"); public static final Key PALE_OAK_SAPLING = Key.of("minecraft:pale_oak_sapling");
public static final Key OAK_SHELF = Key.of("minecraft:oak_shelf");
public static final Key SPRUCE_SHELF = Key.of("minecraft:spruce_shelf");
public static final Key BIRCH_SHELF = Key.of("minecraft:birch_shelf");
public static final Key JUNGLE_SHELF = Key.of("minecraft:jungle_shelf");
public static final Key ACACIA_SHELF = Key.of("minecraft:acacia_shelf");
public static final Key DARK_OAK_SHELF = Key.of("minecraft:dark_oak_shelf");
public static final Key MANGROVE_SHELF = Key.of("minecraft:mangrove_shelf");
public static final Key CHERRY_SHELF = Key.of("minecraft:cherry_shelf");
public static final Key PALE_OAK_SHELF = Key.of("minecraft:pale_oak_shelf");
public static final Key BAMBOO_SHELF = Key.of("minecraft:bamboo_shelf");
public static final Key CRIMSON_SHELF = Key.of("minecraft:crimson_shelf");
public static final Key WARPED_SHELF = Key.of("minecraft:warped_shelf");
public static final Key COPPER_GOLEM_STATUE = Key.of("minecraft:copper_golem_statue");
public static final Key EXPOSED_COPPER_GOLEM_STATUE = Key.of("minecraft:exposed_copper_golem_statue");
public static final Key WEATHERED_COPPER_GOLEM_STATUE = Key.of("minecraft:weathered_copper_golem_statue");
public static final Key OXIDIZED_COPPER_GOLEM_STATUE = Key.of("minecraft:oxidized_copper_golem_statue");
public static final Key WAXED_COPPER_GOLEM_STATUE = Key.of("minecraft:waxed_copper_golem_statue");
public static final Key WAXED_EXPOSED_COPPER_GOLEM_STATUE = Key.of("minecraft:waxed_exposed_copper_golem_statue");
public static final Key WAXED_WEATHERED_COPPER_GOLEM_STATUE = Key.of("minecraft:waxed_weathered_copper_golem_statue");
public static final Key WAXED_OXIDIZED_COPPER_GOLEM_STATUE = Key.of("minecraft:waxed_oxidized_copper_golem_statue");
public static final Key COPPER_CHEST = Key.of("minecraft:copper_chest");
public static final Key EXPOSED_COPPER_CHEST = Key.of("minecraft:exposed_copper_chest");
public static final Key WEATHERED_COPPER_CHEST = Key.of("minecraft:weathered_copper_chest");
public static final Key OXIDIZED_COPPER_CHEST = Key.of("minecraft:oxidized_copper_chest");
public static final Key WAXED_COPPER_CHEST = Key.of("minecraft:waxed_copper_chest");
public static final Key WAXED_EXPOSED_COPPER_CHEST = Key.of("minecraft:waxed_exposed_copper_chest");
public static final Key WAXED_WEATHERED_COPPER_CHEST = Key.of("minecraft:waxed_weathered_copper_chest");
public static final Key WAXED_OXIDIZED_COPPER_CHEST = Key.of("minecraft:waxed_oxidized_copper_chest");
public static final Key[] BUTTONS = new Key[]{ public static final Key[] BUTTONS = new Key[]{
OAK_BUTTON, SPRUCE_BUTTON, BIRCH_BUTTON, JUNGLE_BUTTON, ACACIA_BUTTON, DARK_OAK_BUTTON, MANGROVE_BUTTON, CHERRY_BUTTON, OAK_BUTTON, SPRUCE_BUTTON, BIRCH_BUTTON, JUNGLE_BUTTON, ACACIA_BUTTON, DARK_OAK_BUTTON, MANGROVE_BUTTON, CHERRY_BUTTON,
PALE_OAK_BUTTON, BAMBOO_BUTTON, CRIMSON_BUTTON, WARPED_BUTTON, STONE_BUTTON, POLISHED_BLACKSTONE_BUTTON PALE_OAK_BUTTON, BAMBOO_BUTTON, CRIMSON_BUTTON, WARPED_BUTTON, STONE_BUTTON, POLISHED_BLACKSTONE_BUTTON

View File

@@ -14,25 +14,37 @@ public class ConstantBlockEntityRenderer {
public void show(Player player) { public void show(Player player) {
for (BlockEntityElement element : this.elements) { for (BlockEntityElement element : this.elements) {
if (element != null) {
element.show(player); element.show(player);
} }
} }
}
public void hide(Player player) { public void hide(Player player) {
for (BlockEntityElement element : this.elements) { for (BlockEntityElement element : this.elements) {
if (element != null) {
element.hide(player); element.hide(player);
} }
} }
}
public void deactivate() { public void deactivate() {
for (BlockEntityElement element : this.elements) { for (BlockEntityElement element : this.elements) {
if (element != null) {
element.deactivate(); element.deactivate();
} }
} }
}
public void activate() { public void activate() {
for (BlockEntityElement element : this.elements) { for (BlockEntityElement element : this.elements) {
if (element != null) {
element.activate(); element.activate();
} }
} }
}
public BlockEntityElement[] elements() {
return this.elements;
}
} }

View File

@@ -10,6 +10,8 @@ public interface BlockEntityElement {
void hide(Player player); void hide(Player player);
default void transform(Player player) {}
default void deactivate() {} default void deactivate() {}
default void activate() {} default void activate() {}

View File

@@ -6,4 +6,10 @@ import net.momirealms.craftengine.core.world.World;
public interface BlockEntityElementConfig<E extends BlockEntityElement> { public interface BlockEntityElementConfig<E extends BlockEntityElement> {
E create(World world, BlockPos pos); E create(World world, BlockPos pos);
default E create(World world, BlockPos pos, E previous) {
return null;
}
Class<E> elementClass();
} }

View File

@@ -13,6 +13,7 @@ import java.util.Optional;
public abstract class BlockEntityElementConfigs { public abstract class BlockEntityElementConfigs {
public static final Key ITEM_DISPLAY = Key.of("craftengine:item_display"); public static final Key ITEM_DISPLAY = Key.of("craftengine:item_display");
public static final Key TEXT_DISPLAY = Key.of("craftengine:text_display"); public static final Key TEXT_DISPLAY = Key.of("craftengine:text_display");
public static final Key ITEM = Key.of("craftengine:item");
public static void register(Key key, BlockEntityElementConfigFactory type) { public static void register(Key key, BlockEntityElementConfigFactory type) {
((WritableRegistry<BlockEntityElementConfigFactory>) BuiltInRegistries.BLOCK_ENTITY_ELEMENT_TYPE) ((WritableRegistry<BlockEntityElementConfigFactory>) BuiltInRegistries.BLOCK_ENTITY_ELEMENT_TYPE)

View File

@@ -4,6 +4,7 @@ import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.item.context.BlockPlaceContext; import net.momirealms.craftengine.core.item.context.BlockPlaceContext;
import net.momirealms.craftengine.core.util.Direction; import net.momirealms.craftengine.core.util.Direction;
import net.momirealms.craftengine.core.util.HorizontalDirection; import net.momirealms.craftengine.core.util.HorizontalDirection;
import net.momirealms.craftengine.core.util.SegmentedAngle;
import net.momirealms.sparrow.nbt.Tag; import net.momirealms.sparrow.nbt.Tag;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -33,7 +34,7 @@ public abstract class Property<T extends Comparable<T>> {
Property<Direction> directionProperty = (Property<Direction>) property; Property<Direction> directionProperty = (Property<Direction>) property;
return (context, state) -> state.with(directionProperty, context.getNearestLookingDirection().opposite()); return (context, state) -> state.with(directionProperty, context.getNearestLookingDirection().opposite());
} else { } else {
throw new IllegalArgumentException("Unsupported property type used in hard-coded `facing` property: " + property.valueClass()); return (context, state) -> state;
} }
})); }));
HARD_CODED_PLACEMENTS.put("facing_clockwise", (property -> { HARD_CODED_PLACEMENTS.put("facing_clockwise", (property -> {
@@ -41,13 +42,26 @@ public abstract class Property<T extends Comparable<T>> {
Property<HorizontalDirection> directionProperty = (Property<HorizontalDirection>) property; Property<HorizontalDirection> directionProperty = (Property<HorizontalDirection>) property;
return (context, state) -> state.with(directionProperty, context.getHorizontalDirection().clockWise().toHorizontalDirection()); return (context, state) -> state.with(directionProperty, context.getHorizontalDirection().clockWise().toHorizontalDirection());
} else { } else {
throw new IllegalArgumentException("Unsupported property type used in hard-coded `facing_clockwise` property: " + property.valueClass()); return (context, state) -> state;
} }
})); }));
HARD_CODED_PLACEMENTS.put("waterlogged", (property -> { HARD_CODED_PLACEMENTS.put("waterlogged", (property -> {
Property<Boolean> waterloggedProperty = (Property<Boolean>) property; Property<Boolean> waterloggedProperty = (Property<Boolean>) property;
return (context, state) -> state.with(waterloggedProperty, context.isWaterSource()); return (context, state) -> state.with(waterloggedProperty, context.isWaterSource());
})); }));
HARD_CODED_PLACEMENTS.put("rotation", property -> {
if (property.valueClass() == Integer.class) {
IntegerProperty rotationProperty = (IntegerProperty) property;
if (rotationProperty.min == 0 && rotationProperty.max > 0) {
return (context, state) -> {
float rotation = context.getRotation();
SegmentedAngle segmentedAngle = new SegmentedAngle(rotationProperty.max + 1);
return state.with(rotationProperty, segmentedAngle.fromDegrees(rotation + 180));
};
}
}
return (context, state) -> state;
});
} }
private final Class<T> clazz; private final Class<T> clazz;

View File

@@ -73,6 +73,10 @@ public class UseOnContext {
return this.level; return this.level;
} }
public World getWorld() {
return this.level;
}
public Direction getHorizontalDirection() { public Direction getHorizontalDirection() {
return this.player == null ? Direction.NORTH : this.player.getDirection(); return this.player == null ? Direction.NORTH : this.player.getDirection();
} }

View File

@@ -28,6 +28,7 @@ public final class ItemDataModifiers {
public static final Key CUSTOM_NAME = Key.of("craftengine:custom-name"); public static final Key CUSTOM_NAME = Key.of("craftengine:custom-name");
public static final Key CUSTOM_MODEL_DATA = Key.of("craftengine:custom-model-data"); public static final Key CUSTOM_MODEL_DATA = Key.of("craftengine:custom-model-data");
public static final Key COMPONENTS = Key.of("craftengine:components"); public static final Key COMPONENTS = Key.of("craftengine:components");
public static final Key COMPONENT = Key.of("craftengine:component");
public static final Key ATTRIBUTE_MODIFIERS = Key.of("craftengine:attribute-modifiers"); public static final Key ATTRIBUTE_MODIFIERS = Key.of("craftengine:attribute-modifiers");
public static final Key ATTRIBUTES = Key.of("craftengine:attributes"); public static final Key ATTRIBUTES = Key.of("craftengine:attributes");
public static final Key ARGUMENTS = Key.of("craftengine:arguments"); public static final Key ARGUMENTS = Key.of("craftengine:arguments");
@@ -37,6 +38,7 @@ public final class ItemDataModifiers {
public static final Key OVERWRITABLE_ITEM_NAME = Key.of("craftengine:overwritable-item-name"); public static final Key OVERWRITABLE_ITEM_NAME = Key.of("craftengine:overwritable-item-name");
public static final Key JUKEBOX_PLAYABLE = Key.of("craftengine:jukebox-playable"); public static final Key JUKEBOX_PLAYABLE = Key.of("craftengine:jukebox-playable");
public static final Key REMOVE_COMPONENTS = Key.of("craftengine:remove-components"); public static final Key REMOVE_COMPONENTS = Key.of("craftengine:remove-components");
public static final Key REMOVE_COMPONENT = Key.of("craftengine:remove-component");
public static final Key TAGS = Key.of("craftengine:tags"); public static final Key TAGS = Key.of("craftengine:tags");
public static final Key NBT = Key.of("craftengine:nbt"); public static final Key NBT = Key.of("craftengine:nbt");
public static final Key TOOLTIP_STYLE = Key.of("craftengine:tooltip-style"); public static final Key TOOLTIP_STYLE = Key.of("craftengine:tooltip-style");
@@ -84,7 +86,9 @@ public final class ItemDataModifiers {
register(ITEM_NAME, ItemNameModifier.FACTORY); register(ITEM_NAME, ItemNameModifier.FACTORY);
register(DISPLAY_NAME, ItemNameModifier.FACTORY); register(DISPLAY_NAME, ItemNameModifier.FACTORY);
register(COMPONENTS, ComponentsModifier.FACTORY); register(COMPONENTS, ComponentsModifier.FACTORY);
register(COMPONENT, ComponentsModifier.FACTORY);
register(REMOVE_COMPONENTS, RemoveComponentModifier.FACTORY); register(REMOVE_COMPONENTS, RemoveComponentModifier.FACTORY);
register(REMOVE_COMPONENT, RemoveComponentModifier.FACTORY);
register(FOOD, FoodModifier.FACTORY); register(FOOD, FoodModifier.FACTORY);
register(MAX_DAMAGE, MaxDamageModifier.FACTORY); register(MAX_DAMAGE, MaxDamageModifier.FACTORY);
} else { } else {

View File

@@ -43,7 +43,7 @@ public class SingleItemLootEntryContainer<T> extends AbstractSingleLootEntryCont
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
public LootEntryContainer<A> create(Map<String, Object> arguments) { public LootEntryContainer<A> create(Map<String, Object> arguments) {
String itemObj = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("item"), "warning.config.loot_table.entry.item.missing_item"); String itemObj = ResourceConfigUtils.requireNonEmptyStringOrThrow(ResourceConfigUtils.get(arguments, "item", "id"), "warning.config.loot_table.entry.item.missing_item");
Key item = Key.from(itemObj); Key item = Key.from(itemObj);
int weight = ResourceConfigUtils.getAsInt(arguments.getOrDefault("weight", 1), "weight"); int weight = ResourceConfigUtils.getAsInt(arguments.getOrDefault("weight", 1), "weight");
int quality = ResourceConfigUtils.getAsInt(arguments.getOrDefault("quality", 0), "quality"); int quality = ResourceConfigUtils.getAsInt(arguments.getOrDefault("quality", 0), "quality");

View File

@@ -0,0 +1,58 @@
package net.momirealms.craftengine.core.loot.function;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.item.ItemBuildContext;
import net.momirealms.craftengine.core.item.modifier.ItemDataModifier;
import net.momirealms.craftengine.core.item.recipe.result.ApplyItemDataPostProcessor;
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.plugin.context.number.NumberProvider;
import net.momirealms.craftengine.core.plugin.context.number.NumberProviders;
import net.momirealms.craftengine.core.registry.BuiltInRegistries;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import java.util.*;
public class ApplyDataFunction<T> extends AbstractLootConditionalFunction<T> {
public static final Factory<?> FACTORY = new Factory<>();
private final ItemDataModifier<?>[] modifiers;
public ApplyDataFunction(List<Condition<LootContext>> conditions, ItemDataModifier<?>[] modifiers) {
super(conditions);
this.modifiers = modifiers;
}
@Override
public Key type() {
return LootFunctions.APPLY_DATA;
}
@SuppressWarnings({"unchecked", "rawtypes"})
@Override
protected Item<T> applyInternal(Item<T> item, LootContext context) {
ItemBuildContext ctx = ItemBuildContext.of(context.player());
for (ItemDataModifier modifier : this.modifiers) {
item = modifier.apply(item, ctx);
}
return item;
}
public static class Factory<A> implements LootFunctionFactory<A> {
@SuppressWarnings("unchecked")
@Override
public LootFunction<A> create(Map<String, Object> arguments) {
List<ItemDataModifier<?>> modifiers = new ArrayList<>();
Map<String, Object> data = ResourceConfigUtils.getAsMap(ResourceConfigUtils.requireNonNullOrThrow(arguments.get("data"), "warning.config.loot_table.function.apply_data.missing_data"), "data");
for (Map.Entry<String, Object> entry : data.entrySet()) {
Optional.ofNullable(BuiltInRegistries.ITEM_DATA_MODIFIER_FACTORY.getValue(Key.withDefaultNamespace(entry.getKey(), Key.DEFAULT_NAMESPACE)))
.ifPresent(factory -> modifiers.add(factory.create(entry.getValue())));
}
List<Condition<LootContext>> conditions = Optional.ofNullable(arguments.get("conditions"))
.map(it -> LootConditions.fromMapList((List<Map<String, Object>>) it))
.orElse(Collections.emptyList());
return new ApplyDataFunction<>(conditions, modifiers.toArray(new ItemDataModifier[0]));
}
}
}

View File

@@ -17,6 +17,7 @@ import java.util.function.BiFunction;
public class LootFunctions { public class LootFunctions {
public static final Key APPLY_BONUS = Key.from("craftengine:apply_bonus"); public static final Key APPLY_BONUS = Key.from("craftengine:apply_bonus");
public static final Key APPLY_DATA = Key.from("craftengine:apply_data");
public static final Key SET_COUNT = Key.from("craftengine:set_count"); public static final Key SET_COUNT = Key.from("craftengine:set_count");
public static final Key EXPLOSION_DECAY = Key.from("craftengine:explosion_decay"); public static final Key EXPLOSION_DECAY = Key.from("craftengine:explosion_decay");
public static final Key DROP_EXP = Key.from("craftengine:drop_exp"); public static final Key DROP_EXP = Key.from("craftengine:drop_exp");
@@ -24,6 +25,7 @@ public class LootFunctions {
static { static {
register(SET_COUNT, SetCountFunction.FACTORY); register(SET_COUNT, SetCountFunction.FACTORY);
register(APPLY_DATA, ApplyDataFunction.FACTORY);
register(EXPLOSION_DECAY, ExplosionDecayFunction.FACTORY); register(EXPLOSION_DECAY, ExplosionDecayFunction.FACTORY);
register(APPLY_BONUS, ApplyBonusCountFunction.FACTORY); register(APPLY_BONUS, ApplyBonusCountFunction.FACTORY);
register(DROP_EXP, DropExpFunction.FACTORY); register(DROP_EXP, DropExpFunction.FACTORY);

View File

@@ -40,10 +40,10 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.yaml.snakeyaml.LoaderOptions; import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.parser.ParserException;
import org.yaml.snakeyaml.scanner.ScannerException; import org.yaml.snakeyaml.scanner.ScannerException;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.*; import java.io.*;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
@@ -620,6 +620,9 @@ public abstract class AbstractPackManager implements PackManager {
AbstractPackManager.this.plugin.logger().severe("Error found while reading config file: " + path, e); AbstractPackManager.this.plugin.logger().severe("Error found while reading config file: " + path, e);
} }
return FileVisitResult.CONTINUE; return FileVisitResult.CONTINUE;
} catch (ParserException e) {
AbstractPackManager.this.plugin.logger().severe("Invalid YAML file found: " + path + ".\n" + e.getMessage() + "\nIt is recommended to use Visual Studio Code as your YAML editor to fix problems more quickly.");
return FileVisitResult.CONTINUE;
} catch (LocalizedException e) { } catch (LocalizedException e) {
e.setArgument(0, path.toString()); e.setArgument(0, path.toString());
TranslationManager.instance().log(e.node(), e.arguments()); TranslationManager.instance().log(e.node(), e.arguments());
@@ -734,10 +737,6 @@ public abstract class AbstractPackManager implements PackManager {
this.plugin.logger().info("Optimized resource pack in " + (time4 - time3) + "ms"); this.plugin.logger().info("Optimized resource pack in " + (time4 - time3) + "ms");
Path finalPath = resourcePackPath(); Path finalPath = resourcePackPath();
Files.createDirectories(finalPath.getParent()); Files.createDirectories(finalPath.getParent());
if (!VersionHelper.PREMIUM && Config.enableObfuscation()) {
Config.instance().setObf(false);
this.plugin.logger().warn("Resource pack obfuscation requires Premium Edition.");
}
try { try {
this.zipGenerator.accept(generatedPackPath, finalPath); this.zipGenerator.accept(generatedPackPath, finalPath);
} catch (Exception e) { } catch (Exception e) {

View File

@@ -38,7 +38,7 @@ public class ResolutionMergeAltas implements Resolution {
j3.add("sources", ja3); j3.add("sources", ja3);
GsonHelper.writeJsonFile(j3, existing.path()); GsonHelper.writeJsonFile(j3, existing.path());
} catch (Exception e) { } catch (Exception e) {
CraftEngine.instance().logger().severe("Failed to merge json when resolving file conflicts", e); CraftEngine.instance().logger().severe("Failed to merge altas when resolving file conflicts", e);
} }
} }

View File

@@ -0,0 +1,57 @@
package net.momirealms.craftengine.core.pack.conflict.resolution;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import net.momirealms.craftengine.core.pack.conflict.PathContext;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.util.GsonHelper;
import net.momirealms.craftengine.core.util.Key;
import java.util.HashSet;
import java.util.Map;
public class ResolutionMergeFont implements Resolution {
public static final Factory FACTORY = new Factory();
public static final ResolutionMergeFont INSTANCE = new ResolutionMergeFont();
@Override
public void run(PathContext existing, PathContext conflict) {
try {
JsonObject j1 = GsonHelper.readJsonFile(existing.path()).getAsJsonObject();
JsonObject j2 = GsonHelper.readJsonFile(conflict.path()).getAsJsonObject();
JsonObject j3 = new JsonObject();
JsonArray ja1 = j1.getAsJsonArray("providers");
JsonArray ja2 = j2.getAsJsonArray("providers");
JsonArray ja3 = new JsonArray();
HashSet<String> elements = new HashSet<>();
for (JsonElement je : ja1) {
if (elements.add(je.toString())) {
ja3.add(je);
}
}
for (JsonElement je : ja2) {
if (elements.add(je.toString())) {
ja3.add(je);
}
}
j3.add("providers", ja3);
GsonHelper.writeJsonFile(j3, existing.path());
} catch (Exception e) {
CraftEngine.instance().logger().severe("Failed to merge font when resolving file conflicts", e);
}
}
@Override
public Key type() {
return Resolutions.MERGE_FONT;
}
public static class Factory implements ResolutionFactory {
@Override
public Resolution create(Map<String, Object> arguments) {
return INSTANCE;
}
}
}

View File

@@ -14,6 +14,7 @@ public class Resolutions {
public static final Key RETAIN_MATCHING = Key.of("craftengine:retain_matching"); public static final Key RETAIN_MATCHING = Key.of("craftengine:retain_matching");
public static final Key MERGE_JSON = Key.of("craftengine:merge_json"); public static final Key MERGE_JSON = Key.of("craftengine:merge_json");
public static final Key MERGE_ATLAS = Key.of("craftengine:merge_atlas"); public static final Key MERGE_ATLAS = Key.of("craftengine:merge_atlas");
public static final Key MERGE_FONT = Key.of("craftengine:merge_font");
public static final Key CONDITIONAL = Key.of("craftengine:conditional"); public static final Key CONDITIONAL = Key.of("craftengine:conditional");
public static final Key MERGE_PACK_MCMETA = Key.of("craftengine:merge_pack_mcmeta"); public static final Key MERGE_PACK_MCMETA = Key.of("craftengine:merge_pack_mcmeta");
public static final Key MERGE_LEGACY_MODEL = Key.of("craftengine:merge_legacy_model"); public static final Key MERGE_LEGACY_MODEL = Key.of("craftengine:merge_legacy_model");
@@ -25,6 +26,7 @@ public class Resolutions {
register(MERGE_PACK_MCMETA, ResolutionMergePackMcMeta.FACTORY); register(MERGE_PACK_MCMETA, ResolutionMergePackMcMeta.FACTORY);
register(MERGE_ATLAS, ResolutionMergeAltas.FACTORY); register(MERGE_ATLAS, ResolutionMergeAltas.FACTORY);
register(MERGE_LEGACY_MODEL, ResolutionMergeLegacyModel.FACTORY); register(MERGE_LEGACY_MODEL, ResolutionMergeLegacyModel.FACTORY);
register(MERGE_FONT, ResolutionMergeFont.FACTORY);
} }
public static void register(Key key, ResolutionFactory factory) { public static void register(Key key, ResolutionFactory factory) {

View File

@@ -184,6 +184,8 @@ public abstract class CraftEngine implements Plugin {
delayedLoadTasks.add(CompletableFuture.runAsync(() -> this.recipeManager.delayedLoad(), this.scheduler.async())); delayedLoadTasks.add(CompletableFuture.runAsync(() -> this.recipeManager.delayedLoad(), this.scheduler.async()));
} }
CompletableFutures.allOf(delayedLoadTasks).join(); CompletableFutures.allOf(delayedLoadTasks).join();
// 重新发送tags需要等待tags更新完成
this.networkManager.delayedLoad();
long time2 = System.currentTimeMillis(); long time2 = System.currentTimeMillis();
asyncTime = time2 - time1; asyncTime = time2 - time1;
} finally { } finally {

View File

@@ -2,22 +2,32 @@ package net.momirealms.craftengine.core.plugin.context.condition;
import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.plugin.context.Condition;
import net.momirealms.craftengine.core.plugin.context.Context; import net.momirealms.craftengine.core.plugin.context.Context;
import net.momirealms.craftengine.core.plugin.context.number.NumberProvider;
import net.momirealms.craftengine.core.plugin.context.number.NumberProviders;
import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters;
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.MiscUtils;
import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import net.momirealms.craftengine.core.world.ExistingBlock; import net.momirealms.craftengine.core.world.ExistingBlock;
import net.momirealms.craftengine.core.world.World;
import net.momirealms.craftengine.core.world.WorldPosition;
import java.util.*; import java.util.*;
public class MatchBlockCondition<CTX extends Context> implements Condition<CTX> { public class MatchBlockCondition<CTX extends Context> implements Condition<CTX> {
private final Set<String> ids; private final Set<String> ids;
private final boolean regexMatch; private final boolean regexMatch;
private final NumberProvider x;
private final NumberProvider y;
private final NumberProvider z;
public MatchBlockCondition(Collection<String> ids, boolean regexMatch) { public MatchBlockCondition(Collection<String> ids, boolean regexMatch, NumberProvider x, NumberProvider y, NumberProvider z) {
this.ids = new HashSet<>(ids); this.ids = new HashSet<>(ids);
this.regexMatch = regexMatch; this.regexMatch = regexMatch;
this.x = x;
this.y = y;
this.z = z;
} }
@Override @Override
@@ -27,8 +37,13 @@ public class MatchBlockCondition<CTX extends Context> implements Condition<CTX>
@Override @Override
public boolean test(CTX ctx) { public boolean test(CTX ctx) {
Optional<ExistingBlock> block = ctx.getOptionalParameter(DirectContextParameters.BLOCK); Optional<WorldPosition> optionalWorldPosition = ctx.getOptionalParameter(DirectContextParameters.POSITION);
return block.filter(blockInWorld -> MiscUtils.matchRegex(blockInWorld.id().asString(), this.ids, this.regexMatch)).isPresent(); if (optionalWorldPosition.isPresent()) {
World world = optionalWorldPosition.get().world();
ExistingBlock blockAt = world.getBlockAt(MiscUtils.fastFloor(this.x.getDouble(ctx)), MiscUtils.fastFloor(this.y.getDouble(ctx)), MiscUtils.fastFloor(this.z.getDouble(ctx)));
return MiscUtils.matchRegex(blockAt.id().asString(), this.ids, this.regexMatch);
}
return false;
} }
public static class FactoryImpl<CTX extends Context> implements ConditionFactory<CTX> { public static class FactoryImpl<CTX extends Context> implements ConditionFactory<CTX> {
@@ -40,7 +55,10 @@ public class MatchBlockCondition<CTX extends Context> implements Condition<CTX>
throw new LocalizedResourceConfigException("warning.config.condition.match_block.missing_id"); throw new LocalizedResourceConfigException("warning.config.condition.match_block.missing_id");
} }
boolean regex = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("regex", false), "regex"); boolean regex = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("regex", false), "regex");
return new MatchBlockCondition<>(ids, regex); return new MatchBlockCondition<>(ids, regex,
NumberProviders.fromObject(arguments.getOrDefault("x", "<arg:position.x>")),
NumberProviders.fromObject(arguments.getOrDefault("y", "<arg:position.y>")),
NumberProviders.fromObject(arguments.getOrDefault("z", "<arg:position.z>")));
} }
} }
} }

View File

@@ -10,6 +10,7 @@ import net.momirealms.craftengine.core.plugin.context.number.NumberProviders;
import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters;
import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.MiscUtils;
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import net.momirealms.craftengine.core.world.World; import net.momirealms.craftengine.core.world.World;
import net.momirealms.craftengine.core.world.WorldPosition; import net.momirealms.craftengine.core.world.WorldPosition;
@@ -22,13 +23,15 @@ public class DropLootFunction<CTX extends Context> extends AbstractConditionalFu
private final NumberProvider y; private final NumberProvider y;
private final NumberProvider z; private final NumberProvider z;
private final LootTable<?> lootTable; private final LootTable<?> lootTable;
private final boolean toInv;
public DropLootFunction(NumberProvider x, NumberProvider y, NumberProvider z, LootTable<?> lootTable, List<Condition<CTX>> predicates) { public DropLootFunction(List<Condition<CTX>> predicates, NumberProvider x, NumberProvider y, NumberProvider z, LootTable<?> lootTable, boolean toInv) {
super(predicates); super(predicates);
this.x = x; this.x = x;
this.y = y; this.y = y;
this.z = z; this.z = z;
this.lootTable = lootTable; this.lootTable = lootTable;
this.toInv = toInv;
} }
@Override @Override
@@ -39,11 +42,17 @@ public class DropLootFunction<CTX extends Context> extends AbstractConditionalFu
WorldPosition position = new WorldPosition(world, x.getDouble(ctx), y.getDouble(ctx), z.getDouble(ctx)); WorldPosition position = new WorldPosition(world, x.getDouble(ctx), y.getDouble(ctx), z.getDouble(ctx));
Player player = ctx.getOptionalParameter(DirectContextParameters.PLAYER).orElse(null); Player player = ctx.getOptionalParameter(DirectContextParameters.PLAYER).orElse(null);
List<? extends Item<?>> items = lootTable.getRandomItems(ctx.contexts(), world, player); List<? extends Item<?>> items = lootTable.getRandomItems(ctx.contexts(), world, player);
if (this.toInv && player != null) {
for (Item<?> item : items) {
player.giveItem(item);
}
} else {
for (Item<?> item : items) { for (Item<?> item : items) {
world.dropItemNaturally(position, item); world.dropItemNaturally(position, item);
} }
} }
} }
}
@Override @Override
public Key type() { public Key type() {
@@ -62,7 +71,8 @@ public class DropLootFunction<CTX extends Context> extends AbstractConditionalFu
NumberProvider y = NumberProviders.fromObject(arguments.getOrDefault("y", "<arg:position.y>")); NumberProvider y = NumberProviders.fromObject(arguments.getOrDefault("y", "<arg:position.y>"));
NumberProvider z = NumberProviders.fromObject(arguments.getOrDefault("z", "<arg:position.z>")); NumberProvider z = NumberProviders.fromObject(arguments.getOrDefault("z", "<arg:position.z>"));
LootTable<?> loots = LootTable.fromMap(MiscUtils.castToMap(arguments.get("loot"), true)); LootTable<?> loots = LootTable.fromMap(MiscUtils.castToMap(arguments.get("loot"), true));
return new DropLootFunction<>(x, y, z, loots, getPredicates(arguments)); boolean toInv = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("to-inventory", false), "to-inventory");
return new DropLootFunction<>(getPredicates(arguments), x, y, z, loots, toInv);
} }
} }
} }

View File

@@ -0,0 +1,6 @@
package net.momirealms.craftengine.core.util;
import java.util.HashMap;
public class MarkedHashMap<K, V> extends HashMap<K, V> {
}

View File

@@ -0,0 +1,58 @@
package net.momirealms.craftengine.core.util;
public class SegmentedAngle {
private final int segments;
private final float degreeToAngle;
private final float angleToDegree;
public SegmentedAngle(int segments) {
if (segments < 2) {
throw new IllegalArgumentException("Segments cannot be less than 2");
} else if (segments > 360) {
throw new IllegalArgumentException("Segments cannot be greater than 360");
} else {
this.segments = segments;
this.degreeToAngle = (float) segments / 360.0F;
this.angleToDegree = 360.0F / (float) segments;
}
}
public boolean isSameAxis(int alpha, int beta) {
int halfSegments = this.segments / 2;
return (alpha % halfSegments) == (beta % halfSegments);
}
public int fromDirection(Direction direction) {
if (direction.axis().isVertical()) {
return 0;
} else {
int i = direction.data2d();
return i * (this.segments / 4);
}
}
public int fromDegreesWithTurns(float degrees) {
return Math.round(degrees * this.degreeToAngle);
}
public int fromDegrees(float degrees) {
return this.normalize(this.fromDegreesWithTurns(degrees));
}
public float toDegreesWithTurns(int rotation) {
return (float) rotation * this.angleToDegree;
}
public float toDegrees(int rotation) {
float f = this.toDegreesWithTurns(this.normalize(rotation));
return f >= 180.0F ? f - 360.0F : f;
}
public int normalize(int rotationBits) {
return ((rotationBits % this.segments) + this.segments) % this.segments;
}
public int getSegments() {
return this.segments;
}
}

View File

@@ -5,6 +5,7 @@ import com.google.gson.JsonObject;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Objects;
public class VersionHelper { public class VersionHelper {
public static final boolean PREMIUM = false; public static final boolean PREMIUM = false;
@@ -35,20 +36,30 @@ public class VersionHelper {
private static final boolean v1_21_8; private static final boolean v1_21_8;
private static final boolean v1_21_9; private static final boolean v1_21_9;
private static final boolean v1_21_10; private static final boolean v1_21_10;
private static final Class<?> UNOBFUSCATED_CLAZZ = Objects.requireNonNull(ReflectionUtils.getClazz(
"net.minecraft.obfuscate.DontObfuscate", // 因为无混淆版本没有这个类所以说多写几个防止找不到了
"net.minecraft.data.Main",
"net.minecraft.server.Main",
"net.minecraft.gametest.Main",
"net.minecraft.client.main.Main",
"net.minecraft.client.data.Main"
));
static { static {
try (InputStream inputStream = Class.forName("net.minecraft.obfuscate.DontObfuscate").getResourceAsStream("/version.json")) { try (InputStream inputStream = UNOBFUSCATED_CLAZZ.getResourceAsStream("/version.json")) {
if (inputStream == null) { if (inputStream == null) {
throw new IOException("Failed to load version.json"); throw new IOException("Failed to load version.json");
} }
JsonObject json = GsonHelper.parseJsonToJsonObject(new String(inputStream.readAllBytes(), StandardCharsets.UTF_8)); JsonObject json = GsonHelper.parseJsonToJsonObject(new String(inputStream.readAllBytes(), StandardCharsets.UTF_8));
String versionString = json.getAsJsonPrimitive("id").getAsString().split("-", 2)[0]; String versionString = json.getAsJsonPrimitive("id").getAsString()
.split("-", 2)[0] // 1.21.10-rc1 -> 1.21.10
.split("_", 2)[0]; // 1.21.11_unobfuscated -> 1.21.11
MINECRAFT_VERSION = new MinecraftVersion(versionString); MINECRAFT_VERSION = new MinecraftVersion(versionString);
String[] split = versionString.split("\\."); String[] split = versionString.split("\\.");
int major = Integer.parseInt(split[1]); int major = Integer.parseInt(split[1]);
int minor = split.length == 3 ? Integer.parseInt(split[2].split("-", 2)[0]) : 0; int minor = split.length == 3 ? Integer.parseInt(split[2]) : 0;
// 12001 = 1.20.1 // 12001 = 1.20.1
// 12104 = 1.21.4 // 12104 = 1.21.4

View File

@@ -39,6 +39,14 @@ public interface World {
this.setBlockAt(x, y, z, blockState.customBlockState(), flags); this.setBlockAt(x, y, z, blockState.customBlockState(), flags);
} }
default void setBlockAt(BlockPos pos, BlockStateWrapper blockState, int flags) {
this.setBlockAt(pos.x(), pos.y(), pos.z(), blockState, flags);
}
default void setBlockAt(BlockPos pos, ImmutableBlockState blockState, int flags) {
this.setBlockAt(pos.x(), pos.y(), pos.z(), blockState, flags);
}
String name(); String name();
Path directory(); Path directory();

View File

@@ -35,6 +35,7 @@ public class CEChunk {
private final ReentrantReadWriteLock renderLock = new ReentrantReadWriteLock(); private final ReentrantReadWriteLock renderLock = new ReentrantReadWriteLock();
private volatile boolean dirty; private volatile boolean dirty;
private volatile boolean loaded; private volatile boolean loaded;
private volatile boolean activated;
public CEChunk(CEWorld world, ChunkPos chunkPos) { public CEChunk(CEWorld world, ChunkPos chunkPos) {
this.world = world; this.world = world;
@@ -115,40 +116,129 @@ public class CEChunk {
} }
} }
public void addConstantBlockEntityRenderer(BlockPos pos) { public ConstantBlockEntityRenderer addConstantBlockEntityRenderer(BlockPos pos) {
this.addConstantBlockEntityRenderer(pos, this.getBlockState(pos)); return this.addConstantBlockEntityRenderer(pos, this.getBlockState(pos), null);
} }
public void addConstantBlockEntityRenderer(BlockPos pos, ImmutableBlockState state) { public ConstantBlockEntityRenderer addConstantBlockEntityRenderer(BlockPos pos, ImmutableBlockState state) {
return this.addConstantBlockEntityRenderer(pos, state, null);
}
@SuppressWarnings({"unchecked", "rawtypes"})
public ConstantBlockEntityRenderer addConstantBlockEntityRenderer(BlockPos pos, ImmutableBlockState state, @Nullable ConstantBlockEntityRenderer previous) {
BlockEntityElementConfig<? extends BlockEntityElement>[] renderers = state.constantRenderers(); BlockEntityElementConfig<? extends BlockEntityElement>[] renderers = state.constantRenderers();
if (renderers != null && renderers.length > 0) { if (renderers != null && renderers.length > 0) {
BlockEntityElement[] elements = new BlockEntityElement[renderers.length]; BlockEntityElement[] elements = new BlockEntityElement[renderers.length];
ConstantBlockEntityRenderer renderer = new ConstantBlockEntityRenderer(elements);
World wrappedWorld = this.world.world(); World wrappedWorld = this.world.world();
List<Player> trackedBy = getTrackedBy();
boolean hasTrackedBy = trackedBy != null && !trackedBy.isEmpty();
// 处理旧到新的转换
if (previous != null) {
// 由于entity-render的体量基本都很小所以考虑一个特殊情况即前后都是1个renderer对此情况进行简化和优化
BlockEntityElement[] previousElements = previous.elements().clone();
if (previousElements.length == 1 && renderers.length == 1) {
BlockEntityElement previousElement = previousElements[0];
BlockEntityElementConfig<? extends BlockEntityElement> config = renderers[0];
outer: {
if (config.elementClass().isInstance(previousElement)) {
BlockEntityElement element = ((BlockEntityElementConfig) config).create(wrappedWorld, pos, previousElement);
if (element != null) {
elements[0] = element;
if (hasTrackedBy) {
for (Player player : trackedBy) {
element.transform(player);
}
}
break outer;
}
}
BlockEntityElement element = config.create(wrappedWorld, pos);
elements[0] = element;
if (hasTrackedBy) {
for (Player player : trackedBy) {
previousElement.hide(player);
element.show(player);
}
}
}
} else {
outer: for (int i = 0; i < elements.length; i++) {
BlockEntityElementConfig<? extends BlockEntityElement> config = renderers[i];
for (int j = 0; j < previousElements.length; j++) {
BlockEntityElement previousElement = previousElements[j];
if (previousElement != null && config.elementClass().isInstance(previousElement)) {
BlockEntityElement newElement = ((BlockEntityElementConfig) config).create(wrappedWorld, pos, previousElement);
if (newElement != null) {
previousElements[j] = null;
elements[i] = newElement;
if (hasTrackedBy) {
for (Player player : trackedBy) {
newElement.transform(player);
}
}
continue outer;
}
}
}
BlockEntityElement newElement = config.create(wrappedWorld, pos);
elements[i] = newElement;
if (hasTrackedBy) {
for (Player player : trackedBy) {
newElement.show(player);
}
}
}
if (hasTrackedBy) {
for (int i = 0; i < previousElements.length; i++) {
BlockEntityElement previousElement = previousElements[i];
if (previousElement != null) {
for (Player player : trackedBy) {
previousElement.hide(player);
}
}
}
}
}
} else {
for (int i = 0; i < elements.length; i++) { for (int i = 0; i < elements.length; i++) {
elements[i] = renderers[i].create(wrappedWorld, pos); elements[i] = renderers[i].create(wrappedWorld, pos);
} }
ConstantBlockEntityRenderer renderer = new ConstantBlockEntityRenderer(elements); if (hasTrackedBy) {
for (Player player : getTrackedBy()) { for (Player player : trackedBy) {
renderer.show(player); renderer.show(player);
} }
}
}
try { try {
this.renderLock.writeLock().lock(); this.renderLock.writeLock().lock();
this.constantBlockEntityRenderers.put(pos, renderer); this.constantBlockEntityRenderers.put(pos, renderer);
return renderer;
} finally { } finally {
this.renderLock.writeLock().unlock(); this.renderLock.writeLock().unlock();
} }
} }
return null;
} }
public void removeConstantBlockEntityRenderer(BlockPos pos) { @Nullable
public ConstantBlockEntityRenderer removeConstantBlockEntityRenderer(BlockPos pos) {
return this.removeConstantBlockEntityRenderer(pos, true);
}
@Nullable
public ConstantBlockEntityRenderer removeConstantBlockEntityRenderer(BlockPos pos, boolean hide) {
try { try {
this.renderLock.writeLock().lock(); this.renderLock.writeLock().lock();
ConstantBlockEntityRenderer removed = this.constantBlockEntityRenderers.remove(pos); ConstantBlockEntityRenderer removed = this.constantBlockEntityRenderers.remove(pos);
if (removed != null) { if (removed != null) {
if (hide) {
for (Player player : getTrackedBy()) { for (Player player : getTrackedBy()) {
removed.hide(player); removed.hide(player);
} }
} }
}
return removed;
} finally { } finally {
this.renderLock.writeLock().unlock(); this.renderLock.writeLock().unlock();
} }
@@ -183,7 +273,12 @@ public class CEChunk {
this.removeDynamicBlockEntityRenderer(blockPos); this.removeDynamicBlockEntityRenderer(blockPos);
} }
public List<Player> getTrackedBy() {
return this.world.world.getTrackedBy(this.chunkPos);
}
public void activateAllBlockEntities() { public void activateAllBlockEntities() {
if (this.activated) return;
for (BlockEntity blockEntity : this.blockEntities.values()) { for (BlockEntity blockEntity : this.blockEntities.values()) {
blockEntity.setValid(true); blockEntity.setValid(true);
this.replaceOrCreateTickingBlockEntity(blockEntity); this.replaceOrCreateTickingBlockEntity(blockEntity);
@@ -192,13 +287,11 @@ public class CEChunk {
for (ConstantBlockEntityRenderer renderer : this.constantBlockEntityRenderers.values()) { for (ConstantBlockEntityRenderer renderer : this.constantBlockEntityRenderers.values()) {
renderer.activate(); renderer.activate();
} }
} this.activated = true;
public List<Player> getTrackedBy() {
return this.world.world.getTrackedBy(this.chunkPos);
} }
public void deactivateAllBlockEntities() { public void deactivateAllBlockEntities() {
if (!this.activated) return;
this.blockEntities.values().forEach(e -> e.setValid(false)); this.blockEntities.values().forEach(e -> e.setValid(false));
this.constantBlockEntityRenderers.values().forEach(ConstantBlockEntityRenderer::deactivate); this.constantBlockEntityRenderers.values().forEach(ConstantBlockEntityRenderer::deactivate);
this.dynamicBlockEntityRenderers.clear(); this.dynamicBlockEntityRenderers.clear();
@@ -206,6 +299,7 @@ public class CEChunk {
this.tickingSyncBlockEntitiesByPos.clear(); this.tickingSyncBlockEntitiesByPos.clear();
this.tickingAsyncBlockEntitiesByPos.values().forEach((ticker) -> ticker.setTicker(DummyTickingBlockEntity.INSTANCE)); this.tickingAsyncBlockEntitiesByPos.values().forEach((ticker) -> ticker.setTicker(DummyTickingBlockEntity.INSTANCE));
this.tickingAsyncBlockEntitiesByPos.clear(); this.tickingAsyncBlockEntitiesByPos.clear();
this.activated = false;
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@@ -452,14 +546,12 @@ public class CEChunk {
public void load() { public void load() {
if (this.loaded) return; if (this.loaded) return;
this.world.addLoadedChunk(this); this.world.addLoadedChunk(this);
this.activateAllBlockEntities();
this.loaded = true; this.loaded = true;
} }
public void unload() { public void unload() {
if (!this.loaded) return; if (!this.loaded) return;
this.world.removeLoadedChunk(this); this.world.removeLoadedChunk(this);
this.deactivateAllBlockEntities();
this.loaded = false; this.loaded = false;
} }
} }

View File

@@ -26,6 +26,11 @@ public class CachedStorage<T extends WorldDataStorage> implements WorldDataStora
.build(); .build();
} }
@Override
public CEChunk readNewChunkAt(CEWorld world, ChunkPos pos) throws IOException {
return this.storage.readNewChunkAt(world, pos);
}
@Override @Override
public @NotNull CEChunk readChunkAt(@NotNull CEWorld world, @NotNull ChunkPos pos) throws IOException { public @NotNull CEChunk readChunkAt(@NotNull CEWorld world, @NotNull ChunkPos pos) throws IOException {
CEChunk chunk = this.chunkCache.getIfPresent(pos); CEChunk chunk = this.chunkCache.getIfPresent(pos);
@@ -42,6 +47,12 @@ public class CachedStorage<T extends WorldDataStorage> implements WorldDataStora
this.storage.writeChunkAt(pos, chunk); this.storage.writeChunkAt(pos, chunk);
} }
@Override
public void clearChunkAt(@NotNull ChunkPos pos) throws IOException {
this.storage.clearChunkAt(pos);
this.chunkCache.invalidate(pos);
}
@Override @Override
public void close() throws IOException { public void close() throws IOException {
this.storage.close(); this.storage.close();

View File

@@ -120,6 +120,19 @@ public class DefaultRegionFileStorage implements WorldDataStorage {
} }
} }
@Override
public CEChunk readNewChunkAt(CEWorld world, ChunkPos pos) throws IOException {
RegionFile regionFile = this.getRegionFile(pos, false, true);
try {
if (regionFile.doesChunkExist(pos)) {
regionFile.clear(pos);
}
return new CEChunk(world, pos);
} finally {
regionFile.fileLock.unlock();
}
}
@Override @Override
public @NotNull CEChunk readChunkAt(@NotNull CEWorld world, @NotNull ChunkPos pos) throws IOException { public @NotNull CEChunk readChunkAt(@NotNull CEWorld world, @NotNull ChunkPos pos) throws IOException {
RegionFile regionFile = this.getRegionFile(pos, false, true); RegionFile regionFile = this.getRegionFile(pos, false, true);
@@ -152,6 +165,11 @@ public class DefaultRegionFileStorage implements WorldDataStorage {
writeChunkTagAt(pos, nbt); writeChunkTagAt(pos, nbt);
} }
@Override
public void clearChunkAt(@NotNull ChunkPos pos) throws IOException {
this.writeChunkTagAt(pos, null);
}
public void writeChunkTagAt(@NotNull ChunkPos pos, @Nullable CompoundTag nbt) throws IOException { public void writeChunkTagAt(@NotNull ChunkPos pos, @Nullable CompoundTag nbt) throws IOException {
RegionFile regionFile = this.getRegionFile(pos, nbt == null, true); RegionFile regionFile = this.getRegionFile(pos, nbt == null, true);
try { try {

View File

@@ -9,11 +9,18 @@ import java.io.IOException;
public interface WorldDataStorage { public interface WorldDataStorage {
default CEChunk readNewChunkAt(CEWorld world, ChunkPos pos) throws IOException {
this.clearChunkAt(pos);
return this.readChunkAt(world, pos);
}
@NotNull @NotNull
CEChunk readChunkAt(@NotNull CEWorld world, @NotNull ChunkPos pos) throws IOException; CEChunk readChunkAt(@NotNull CEWorld world, @NotNull ChunkPos pos) throws IOException;
void writeChunkAt(@NotNull ChunkPos pos, @NotNull CEChunk chunk) throws IOException; void writeChunkAt(@NotNull ChunkPos pos, @NotNull CEChunk chunk) throws IOException;
void clearChunkAt(@NotNull ChunkPos pos) throws IOException;
void flush() throws IOException; void flush() throws IOException;
void close() throws IOException; void close() throws IOException;

View File

@@ -2,9 +2,9 @@ org.gradle.jvmargs=-Xmx1G
# Project settings # Project settings
# Rule: [major update].[feature update].[bug fix] # Rule: [major update].[feature update].[bug fix]
project_version=0.0.65 project_version=0.0.65.6
config_version=52 config_version=53
lang_version=36 lang_version=37
project_group=net.momirealms project_group=net.momirealms
latest_supported_version=1.21.10 latest_supported_version=1.21.10
@@ -49,7 +49,7 @@ byte_buddy_version=1.17.8
ahocorasick_version=0.6.3 ahocorasick_version=0.6.3
snake_yaml_version=2.5 snake_yaml_version=2.5
anti_grief_version=1.0.4 anti_grief_version=1.0.4
nms_helper_version=1.0.123 nms_helper_version=1.0.127
evalex_version=3.5.0 evalex_version=3.5.0
reactive_streams_version=1.0.4 reactive_streams_version=1.0.4
amazon_awssdk_version=2.34.5 amazon_awssdk_version=2.34.5

1
wiki Submodule

Submodule wiki added at bec8bb7cf8