mirror of
https://github.com/Xiao-MoMi/craft-engine.git
synced 2025-12-19 15:09:15 +00:00
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "wiki"]
|
||||
path = wiki
|
||||
url = https://github.com/Xiao-MoMi/craft-engine-wiki.git
|
||||
@@ -75,7 +75,7 @@ repositories {
|
||||
```
|
||||
```kotlin
|
||||
dependencies {
|
||||
compileOnly("net.momirealms:craft-engine-core:0.0.64")
|
||||
compileOnly("net.momirealms:craft-engine-bukkit:0.0.64")
|
||||
compileOnly("net.momirealms:craft-engine-core:0.0.65")
|
||||
compileOnly("net.momirealms:craft-engine-bukkit:0.0.65")
|
||||
}
|
||||
```
|
||||
@@ -37,8 +37,9 @@ dependencies {
|
||||
compileOnly("com.infernalsuite.asp:api:4.0.0-SNAPSHOT")
|
||||
// ModelEngine
|
||||
compileOnly("com.ticxo.modelengine:ModelEngine:R4.0.8")
|
||||
// BetterModels
|
||||
compileOnly("io.github.toxicity188:BetterModel:1.7.0")
|
||||
// BetterModel
|
||||
compileOnly("io.github.toxicity188:bettermodel:1.14.0")
|
||||
compileOnly("com.mojang:authlib:${rootProject.properties["authlib_version"]}")
|
||||
// MMOItems
|
||||
compileOnly("net.Indyuce:MMOItems-API:6.10-SNAPSHOT")
|
||||
compileOnly("io.lumine:MythicLib-dist:1.6.2-SNAPSHOT")
|
||||
|
||||
@@ -26,6 +26,14 @@ public class LegacySlimeWorldDataStorage implements WorldDataStorage {
|
||||
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
|
||||
public @NotNull CEChunk readChunkAt(@NotNull CEWorld world, @NotNull ChunkPos pos) {
|
||||
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
|
||||
public void flush() {
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package net.momirealms.craftengine.bukkit.compatibility.model.bettermodel;
|
||||
import kr.toxicity.model.api.BetterModel;
|
||||
import kr.toxicity.model.api.data.renderer.ModelRenderer;
|
||||
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.entity.player.Player;
|
||||
import net.momirealms.craftengine.core.world.BlockPos;
|
||||
@@ -23,11 +24,13 @@ public class BetterModelBlockEntityElement implements BlockEntityElement {
|
||||
}
|
||||
|
||||
private DummyTracker createDummyTracker() {
|
||||
ModelRenderer modelRenderer = BetterModel.plugin().modelManager().renderer(this.config.model());
|
||||
ModelRenderer modelRenderer = BetterModel.plugin().modelManager().model(this.config.model());
|
||||
if (modelRenderer == null) {
|
||||
return null;
|
||||
} else {
|
||||
return modelRenderer.create(this.location);
|
||||
return modelRenderer.create(this.location, TrackerModifier.builder()
|
||||
.sightTrace(this.config.sightTrace())
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,28 +15,38 @@ public class BetterModelBlockEntityElementConfig implements BlockEntityElementCo
|
||||
private final float yaw;
|
||||
private final float pitch;
|
||||
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.position = position;
|
||||
this.yaw = yaw;
|
||||
this.model = model;
|
||||
this.sightTrace = sightTrace;
|
||||
}
|
||||
|
||||
public String model() {
|
||||
return model;
|
||||
return this.model;
|
||||
}
|
||||
|
||||
public float pitch() {
|
||||
return pitch;
|
||||
return this.pitch;
|
||||
}
|
||||
|
||||
public Vector3f position() {
|
||||
return position;
|
||||
return this.position;
|
||||
}
|
||||
|
||||
public float yaw() {
|
||||
return yaw;
|
||||
return this.yaw;
|
||||
}
|
||||
|
||||
public boolean sightTrace() {
|
||||
return this.sightTrace;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -44,6 +54,11 @@ public class BetterModelBlockEntityElementConfig implements BlockEntityElementCo
|
||||
return new BetterModelBlockEntityElement(world, pos, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<BetterModelBlockEntityElement> elementClass() {
|
||||
return BetterModelBlockEntityElement.class;
|
||||
}
|
||||
|
||||
public static class Factory implements BlockEntityElementConfigFactory {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -54,7 +69,8 @@ public class BetterModelBlockEntityElementConfig implements BlockEntityElementCo
|
||||
model,
|
||||
ResourceConfigUtils.getAsVector3f(arguments.getOrDefault("position", 0.5f), "position"),
|
||||
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")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import org.bukkit.entity.Entity;
|
||||
public class BetterModelUtils {
|
||||
|
||||
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) {
|
||||
throw new NullPointerException("Could not find BetterModel blueprint " + id);
|
||||
}
|
||||
|
||||
@@ -44,6 +44,11 @@ public class ModelEngineBlockEntityElementConfig implements BlockEntityElementCo
|
||||
return new ModelEngineBlockEntityElement(world, pos, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<ModelEngineBlockEntityElement> elementClass() {
|
||||
return ModelEngineBlockEntityElement.class;
|
||||
}
|
||||
|
||||
public static class Factory implements BlockEntityElementConfigFactory {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
||||
@@ -27,6 +27,14 @@ public class SlimeWorldDataStorage implements WorldDataStorage {
|
||||
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
|
||||
public @NotNull CEChunk readChunkAt(@NotNull CEWorld world, @NotNull ChunkPos pos) {
|
||||
SlimeChunk slimeChunk = getWorld().getChunk(pos.x, pos.z);
|
||||
@@ -42,7 +50,7 @@ public class SlimeWorldDataStorage implements WorldDataStorage {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
@Override
|
||||
public void writeChunkAt(@NotNull ChunkPos pos, @NotNull CEChunk chunk) {
|
||||
SlimeChunk slimeChunk = getWorld().getChunk(pos.x, pos.z);
|
||||
@@ -53,8 +61,7 @@ public class SlimeWorldDataStorage implements WorldDataStorage {
|
||||
} else {
|
||||
try {
|
||||
Object tag = adaptor.bytesToByteArrayTag(NBT.toBytes(nbt));
|
||||
Map<String, ?> data1 = slimeChunk.getExtraData();
|
||||
Map<String, Object> data2 = (Map<String, Object>) data1;
|
||||
Map<String, Object> data2 = (Map) slimeChunk.getExtraData();
|
||||
data2.put("craftengine", tag);
|
||||
} catch (Exception 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
|
||||
public void flush() {
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ public final class BukkitBlockManager extends AbstractBlockManager {
|
||||
private Map<Integer, List<String>> clientBoundTags = Map.of();
|
||||
private Map<Integer, List<String>> previousClientBoundTags = Map.of();
|
||||
// 缓存的原版方块tag包
|
||||
private Object cachedUpdateTagsPacket;
|
||||
private List<TagUtils.TagEntry> cachedUpdateTags = List.of();
|
||||
// 被移除声音的原版方块
|
||||
private Set<Object> missingPlaceSounds = Set.of();
|
||||
private Set<Object> missingBreakSounds = Set.of();
|
||||
@@ -150,23 +150,14 @@ public final class BukkitBlockManager extends AbstractBlockManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void resendTags() {
|
||||
protected void updateTags() {
|
||||
// if there's no change
|
||||
if (this.clientBoundTags.equals(this.previousClientBoundTags)) return;
|
||||
List<TagUtils.TagEntry> list = new ArrayList<>();
|
||||
for (Map.Entry<Integer, List<String>> entry : this.clientBoundTags.entrySet()) {
|
||||
list.add(new TagUtils.TagEntry(entry.getKey(), entry.getValue()));
|
||||
}
|
||||
Object packet = TagUtils.createUpdateTagsPacket(Map.of(MRegistries.BLOCK, list));
|
||||
for (BukkitServerPlayer player : this.plugin.networkManager().onlineUsers()) {
|
||||
player.sendPacket(packet, false);
|
||||
}
|
||||
// 如果空,那么新来的玩家就没必要收到更新包了
|
||||
if (list.isEmpty()) {
|
||||
this.cachedUpdateTagsPacket = null;
|
||||
} else {
|
||||
this.cachedUpdateTagsPacket = packet;
|
||||
}
|
||||
this.cachedUpdateTags = list;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -299,6 +290,10 @@ public final class BukkitBlockManager extends AbstractBlockManager {
|
||||
this.burnOdds.put(nmsBlock, settings.fireSpreadChance());
|
||||
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) {
|
||||
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() {
|
||||
return this.cachedUpdateTagsPacket;
|
||||
public List<TagUtils.TagEntry> cachedUpdateTags() {
|
||||
return this.cachedUpdateTags;
|
||||
}
|
||||
|
||||
public VisualBlockStatePacket cachedVisualBlockStatePacket() {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
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.core.block.ImmutableBlockState;
|
||||
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.sparrow.nbt.CompoundTag;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class SeatBlockEntity extends BlockEntity implements SeatOwner {
|
||||
private final Seat<SeatBlockEntity>[] seats;
|
||||
|
||||
@@ -41,25 +38,20 @@ public class SeatBlockEntity extends BlockEntity implements SeatOwner {
|
||||
}
|
||||
|
||||
public boolean spawnSeat(Player player) {
|
||||
Optional<SeatBlockBehavior> seatBehavior = super.blockState.behavior().getAs(SeatBlockBehavior.class);
|
||||
if (seatBehavior.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
float yRot = 0;
|
||||
Property<HorizontalDirection> directionProperty = seatBehavior.get().directionProperty();
|
||||
if (directionProperty != null) {
|
||||
HorizontalDirection direction = super.blockState.get(directionProperty);
|
||||
if (direction == HorizontalDirection.NORTH) {
|
||||
yRot = 180;
|
||||
} else if (direction == HorizontalDirection.EAST) {
|
||||
yRot = -90;
|
||||
} else if (direction == HorizontalDirection.WEST) {
|
||||
yRot = 90;
|
||||
}
|
||||
Property<?> facing = super.blockState.owner().value().getProperty("facing");
|
||||
int yRot = 0;
|
||||
if (facing != null && facing.valueClass() == HorizontalDirection.class) {
|
||||
HorizontalDirection direction = (HorizontalDirection) super.blockState.get(facing);
|
||||
yRot = switch (direction) {
|
||||
case NORTH -> 0;
|
||||
case SOUTH -> 180;
|
||||
case WEST -> 270;
|
||||
case EAST -> 90;
|
||||
};
|
||||
}
|
||||
for (Seat<SeatBlockEntity> seat : this.seats) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ public class BukkitBlockEntityElementConfigs extends BlockEntityElementConfigs {
|
||||
static {
|
||||
register(ITEM_DISPLAY, ItemDisplayBlockEntityElementConfig.FACTORY);
|
||||
register(TEXT_DISPLAY, TextDisplayBlockEntityElementConfig.FACTORY);
|
||||
register(ITEM, ItemBlockEntityElementConfig.FACTORY);
|
||||
}
|
||||
|
||||
private BukkitBlockEntityElementConfigs() {}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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")
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,13 +13,17 @@ import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class ItemDisplayBlockEntityElement implements BlockEntityElement {
|
||||
private final ItemDisplayBlockEntityElementConfig config;
|
||||
private final Object cachedSpawnPacket;
|
||||
private final Object cachedDespawnPacket;
|
||||
private final int entityId;
|
||||
public final ItemDisplayBlockEntityElementConfig config;
|
||||
public final Object cachedSpawnPacket;
|
||||
public final Object cachedDespawnPacket;
|
||||
public final Object cachedUpdatePosPacket;
|
||||
public final int entityId;
|
||||
|
||||
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();
|
||||
this.cachedSpawnPacket = FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket(
|
||||
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.cachedDespawnPacket = FastNMS.INSTANCE.constructor$ClientboundRemoveEntitiesPacket(IntList.of(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
|
||||
@@ -37,6 +42,15 @@ public class ItemDisplayBlockEntityElement implements BlockEntityElement {
|
||||
|
||||
@Override
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,6 +78,20 @@ public class ItemDisplayBlockEntityElementConfig implements BlockEntityElementCo
|
||||
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) {
|
||||
return this.item.apply(player);
|
||||
}
|
||||
|
||||
@@ -13,13 +13,17 @@ import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class TextDisplayBlockEntityElement implements BlockEntityElement {
|
||||
private final TextDisplayBlockEntityElementConfig config;
|
||||
private final Object cachedSpawnPacket;
|
||||
private final Object cachedDespawnPacket;
|
||||
private final int entityId;
|
||||
public final TextDisplayBlockEntityElementConfig config;
|
||||
public final Object cachedSpawnPacket;
|
||||
public final Object cachedDespawnPacket;
|
||||
public final Object cachedUpdatePosPacket;
|
||||
public final int entityId;
|
||||
|
||||
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();
|
||||
this.cachedSpawnPacket = FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket(
|
||||
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.cachedDespawnPacket = FastNMS.INSTANCE.constructor$ClientboundRemoveEntitiesPacket(IntList.of(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
|
||||
@@ -37,6 +42,19 @@ public class TextDisplayBlockEntityElement implements BlockEntityElement {
|
||||
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,6 +66,20 @@ public class TextDisplayBlockEntityElementConfig implements BlockEntityElementCo
|
||||
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) {
|
||||
return AdventureHelper.miniMessage().deserialize(this.text, PlayerOptionalContext.of(player).tagResolvers());
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class BukkitSeatManager implements SeatManager {
|
||||
public class BukkitSeatManager implements SeatManager, Listener {
|
||||
private static BukkitSeatManager instance;
|
||||
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);
|
||||
@@ -113,9 +113,9 @@ public class BukkitSeatManager implements SeatManager {
|
||||
if (!isSeat) return;
|
||||
Location location = seat.getLocation();
|
||||
if (seat instanceof ArmorStand) {
|
||||
location.add(0, 0.9875,0);
|
||||
location.add(0, 0.3875,0);
|
||||
} else {
|
||||
location.add(0,0.25,0);
|
||||
location.add(0,-0.35,0);
|
||||
}
|
||||
seat.remove();
|
||||
EntityUtils.safeDismount(player, location);
|
||||
|
||||
@@ -501,10 +501,17 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory<ComponentItemW
|
||||
if (trim == null) {
|
||||
item.resetComponent(DataComponentTypes.TRIM);
|
||||
} else {
|
||||
item.setJavaComponent(DataComponentTypes.TRIM, Map.of(
|
||||
"pattern", trim.pattern().asString(),
|
||||
"material", trim.material().asString()
|
||||
));
|
||||
try {
|
||||
item.setJavaComponent(DataComponentTypes.TRIM, Map.of(
|
||||
"pattern", trim.pattern().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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -201,6 +201,14 @@ public final class BlockGenerator {
|
||||
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 {
|
||||
ObjectHolder<BlockBehavior> behaviorHolder = new ObjectHolder<>(EmptyBlockBehavior.INSTANCE);
|
||||
ObjectHolder<BlockShape> shapeHolder = new ObjectHolder<>(STONE_SHAPE);
|
||||
|
||||
@@ -19,6 +19,7 @@ import net.momirealms.craftengine.core.block.DelegatingBlockState;
|
||||
import net.momirealms.craftengine.core.block.EmptyBlock;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
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.config.Config;
|
||||
import net.momirealms.craftengine.core.util.ReflectionUtils;
|
||||
@@ -226,7 +227,10 @@ public final class WorldStorageInjector {
|
||||
// 处理 自定义块到自定义块或原版块到自定义块
|
||||
CEChunk chunk = holder.ceChunk();
|
||||
chunk.setDirty(true);
|
||||
|
||||
ConstantBlockEntityRenderer previousRenderer = null;
|
||||
// 如果两个方块没有相同的主人 且 旧方块有方块实体
|
||||
|
||||
if (!previousImmutableBlockState.isEmpty()) {
|
||||
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);
|
||||
@@ -242,9 +246,11 @@ public final class WorldStorageInjector {
|
||||
}
|
||||
if (previousImmutableBlockState.hasConstantBlockEntityRenderer()) {
|
||||
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()) {
|
||||
BlockPos pos = new BlockPos(chunk.chunkPos.x * 16 + x, section.sectionY * 16 + y, chunk.chunkPos.z * 16 + z);
|
||||
BlockEntity blockEntity = chunk.getBlockEntity(pos, false);
|
||||
@@ -264,10 +270,13 @@ public final class WorldStorageInjector {
|
||||
chunk.createDynamicBlockEntityRenderer(blockEntity);
|
||||
}
|
||||
}
|
||||
|
||||
// 处理新老entity renderer更替
|
||||
if (newImmutableBlockState.hasConstantBlockEntityRenderer()) {
|
||||
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 (previousImmutableBlockState.isEmpty()) {
|
||||
|
||||
@@ -241,6 +241,19 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
|
||||
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) {
|
||||
FakeBukkitServerPlayer fakePlayer = new FakeBukkitServerPlayer(this.plugin);
|
||||
fakePlayer.setPlayer(player);
|
||||
@@ -1857,11 +1870,17 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
|
||||
|
||||
public static class UpdateTagsListener implements NMSPacketListener {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void onPacketSend(NetWorkUser user, NMSPacketEvent event, Object packet) {
|
||||
Object modifiedPacket = BukkitBlockManager.instance().cachedUpdateTagsPacket();
|
||||
if (packet.equals(modifiedPacket) || modifiedPacket == null) return;
|
||||
event.replacePacket(modifiedPacket);
|
||||
List<TagUtils.TagEntry> cachedUpdateTags = BukkitBlockManager.instance().cachedUpdateTags();
|
||||
if (cachedUpdateTags.isEmpty()) return;
|
||||
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);
|
||||
// todo 刷怪笼里的物品?
|
||||
|
||||
// 展示架
|
||||
if (VersionHelper.isOrAbove1_21_9() && tag != null && tag.containsKey("Items")) {
|
||||
// 通用方块实体存储的物品
|
||||
if (tag != null && tag.containsKey("Items")) {
|
||||
BukkitItemManager itemManager = BukkitItemManager.instance();
|
||||
ListTag itemsTag = tag.getList("Items");
|
||||
List<Pair<Byte, ItemStack>> items = new ArrayList<>();
|
||||
for (Tag itemTag : itemsTag) {
|
||||
if (itemTag instanceof CompoundTag itemCompoundTag) {
|
||||
byte slot = itemCompoundTag.getByte("Slot");
|
||||
Object nmsStack = CoreReflections.instance$ItemStack$CODEC.parse(MRegistryOps.SPARROW_NBT, itemCompoundTag)
|
||||
.resultOrPartial((error) -> CraftEngine.instance().logger().severe("Tried to parse invalid item: '" + error + "'")).orElse(null);
|
||||
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);
|
||||
} 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);
|
||||
Optional<ItemStack> optional = itemManager.s2c(bukkitStack, (BukkitServerPlayer) user);
|
||||
if (optional.isPresent()) {
|
||||
@@ -4155,8 +4180,14 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
|
||||
if (changed) {
|
||||
ListTag newItemsTag = new ListTag();
|
||||
for (Pair<Byte, ItemStack> pair : items) {
|
||||
CompoundTag 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);
|
||||
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);
|
||||
} 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) {
|
||||
newItemCompoundTag.putByte("Slot", pair.left());
|
||||
newItemsTag.add(newItemCompoundTag);
|
||||
|
||||
@@ -56,7 +56,7 @@ public record ClientCustomBlockPacket(int vanillaSize, int currentSize) implemen
|
||||
return;
|
||||
}
|
||||
int serverBlockRegistrySize = RegistryUtils.currentBlockRegistrySize();
|
||||
if (this.currentSize != serverBlockRegistrySize) {
|
||||
if (this.currentSize < serverBlockRegistrySize) {
|
||||
user.kick(Component.translatable(
|
||||
"disconnect.craftengine.current_block_registry_mismatch",
|
||||
TranslationArgument.numeric(this.currentSize),
|
||||
|
||||
@@ -1082,7 +1082,7 @@ public final class CoreReflections {
|
||||
public static final Class<?> clazz$MobEffect = requireNonNull(
|
||||
ReflectionUtils.getClazz(
|
||||
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(
|
||||
ReflectionUtils.getClazz(
|
||||
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(
|
||||
BukkitReflectionUtils.findReobfOrMojmapClass(
|
||||
"server.level.PlayerChunkMap",
|
||||
"server.level.ChunkMap"
|
||||
ReflectionUtils.getClazz(
|
||||
BukkitReflectionUtils.assembleMCClass("server.level.PlayerChunkMap"), // 这里paper会自动获取到NM.server.level.ChunkMap
|
||||
BukkitReflectionUtils.assembleMCClass("server.level.ChunkMap") // paper柠檬酸了
|
||||
)
|
||||
);
|
||||
|
||||
@@ -3238,7 +3238,7 @@ public final class CoreReflections {
|
||||
public static final Class<?> clazz$ResourceManager = requireNonNull(
|
||||
ReflectionUtils.getClazz(
|
||||
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(
|
||||
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()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1720,4 +1720,10 @@ public final class NetworkReflections {
|
||||
"network.protocol.game.ClientboundBlockEntityDataPacket"
|
||||
)
|
||||
);
|
||||
|
||||
public static final Field field$ClientboundUpdateTagsPacket$tags = requireNonNull(
|
||||
ReflectionUtils.getDeclaredField(
|
||||
clazz$ClientboundUpdateTagsPacket, Map.class, 0
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -63,32 +63,34 @@ public final class EntityUtils {
|
||||
BlockPos pos = new BlockPos(MiscUtils.fastFloor(x), MiscUtils.fastFloor(y), MiscUtils.fastFloor(z));
|
||||
try {
|
||||
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;
|
||||
}
|
||||
floorHeight -= 1;
|
||||
}
|
||||
Object aabb = CoreReflections.method$LivingEntity$getLocalBoundsForPose.invoke(serverPlayer, pose);
|
||||
Object vec3 = FastNMS.INSTANCE.constructor$Vec3(x, pos.y() + floorHeight, z);
|
||||
Object newAABB = FastNMS.INSTANCE.method$AABB$move(aabb, vec3);
|
||||
boolean canDismount = (boolean) CoreReflections.method$DismountHelper$canDismountTo0.invoke(null, serverLevel, serverPlayer, newAABB);
|
||||
if (!canDismount) {
|
||||
continue;
|
||||
}
|
||||
if (isBlockFloorValid(floorHeight)) {
|
||||
Object aabb = CoreReflections.method$LivingEntity$getLocalBoundsForPose.invoke(serverPlayer, pose);
|
||||
Object vec3 = FastNMS.INSTANCE.constructor$Vec3(x, pos.y() + floorHeight, z);
|
||||
Object newAABB = FastNMS.INSTANCE.method$AABB$move(aabb, vec3);
|
||||
boolean canDismount = (boolean) CoreReflections.method$DismountHelper$canDismountTo0.invoke(null, serverLevel, serverPlayer, newAABB);
|
||||
if (!canDismount) {
|
||||
continue;
|
||||
}
|
||||
if (!FastNMS.INSTANCE.checkEntityCollision(serverLevel, List.of(newAABB))) {
|
||||
continue;
|
||||
}
|
||||
if (VersionHelper.isFolia()) {
|
||||
player.teleportAsync(new Location(player.getWorld(), x, pos.y() + floorHeight, z, player.getYaw(), player.getPitch()));
|
||||
} else {
|
||||
player.teleport(new Location(player.getWorld(), x, pos.y() + floorHeight, z, player.getYaw(), player.getPitch()));
|
||||
}
|
||||
if (pose == CoreReflections.instance$Pose$STANDING) {
|
||||
player.setPose(Pose.STANDING);
|
||||
} else if (pose == CoreReflections.instance$Pose$CROUCHING) {
|
||||
player.setPose(Pose.SNEAKING);
|
||||
} else if (pose == CoreReflections.instance$Pose$SWIMMING) {
|
||||
player.setPose(Pose.SWIMMING);
|
||||
}
|
||||
if (!FastNMS.INSTANCE.checkEntityCollision(serverLevel, List.of(newAABB))) {
|
||||
continue;
|
||||
}
|
||||
if (VersionHelper.isFolia()) {
|
||||
player.teleportAsync(new Location(player.getWorld(), x, pos.y() + floorHeight, z, player.getYaw(), player.getPitch()));
|
||||
} else {
|
||||
player.teleport(new Location(player.getWorld(), x, pos.y() + floorHeight, z, player.getYaw(), player.getPitch()));
|
||||
}
|
||||
if (pose == CoreReflections.instance$Pose$STANDING) {
|
||||
player.setPose(Pose.STANDING);
|
||||
} else if (pose == CoreReflections.instance$Pose$CROUCHING) {
|
||||
player.setPose(Pose.SNEAKING);
|
||||
} else if (pose == CoreReflections.instance$Pose$SWIMMING) {
|
||||
player.setPose(Pose.SWIMMING);
|
||||
}
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new RuntimeException(e);
|
||||
|
||||
@@ -34,6 +34,7 @@ import org.bukkit.attribute.AttributeInstance;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.block.data.Directional;
|
||||
import org.bukkit.block.data.Levelled;
|
||||
import org.bukkit.block.data.Lightable;
|
||||
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.CRIMSON_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 {
|
||||
|
||||
@@ -5,6 +5,7 @@ import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.core.util.FriendlyByteBuf;
|
||||
import net.momirealms.craftengine.core.util.MarkedHashMap;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@@ -15,6 +16,9 @@ public final class TagUtils {
|
||||
|
||||
private TagUtils() {}
|
||||
|
||||
public record TagEntry(int id, List<String> tags) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建模拟标签更新数据包(用于向客户端添加虚拟标签)
|
||||
*
|
||||
@@ -39,11 +43,9 @@ public final class TagUtils {
|
||||
*
|
||||
* @return 可发送给客户端的 ClientboundUpdateTagsPacket 数据包对象
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Object createUpdateTagsPacket(Map<Object, List<TagEntry>> tags) {
|
||||
Map<Object, Object> registriesNetworkPayload = (Map<Object, Object>) FastNMS.INSTANCE.method$TagNetworkSerialization$serializeTagsToNetwork();
|
||||
Map<Object, Object> modified = new HashMap<>();
|
||||
for (Map.Entry<Object, Object> payload : registriesNetworkPayload.entrySet()) {
|
||||
public static Object createUpdateTagsPacket(Map<Object, List<TagEntry>> tags, Map<Object, Object> existingTags) {
|
||||
Map<Object, Object> modified = new MarkedHashMap<>();
|
||||
for (Map.Entry<Object, Object> payload : existingTags.entrySet()) {
|
||||
List<TagEntry> overrides = tags.get(payload.getKey());
|
||||
if (overrides == null || overrides.isEmpty()) {
|
||||
modified.put(payload.getKey(), payload.getValue());
|
||||
@@ -83,7 +85,4 @@ public final class TagUtils {
|
||||
}
|
||||
return FastNMS.INSTANCE.constructor$ClientboundUpdateTagsPacket(modified);
|
||||
}
|
||||
|
||||
public record TagEntry(int id, List<String> tags) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,10 +92,12 @@ public class BukkitWorldManager implements WorldManager, Listener {
|
||||
public void delayedInit() {
|
||||
// load loaded chunks
|
||||
for (World world : Bukkit.getWorlds()) {
|
||||
BukkitWorld wrappedWorld = new BukkitWorld(world);
|
||||
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()) {
|
||||
handleChunkLoad(ceWorld, chunk);
|
||||
handleChunkLoad(ceWorld, chunk, false);
|
||||
}
|
||||
ceWorld.setTicking(true);
|
||||
} catch (Exception e) {
|
||||
@@ -142,8 +144,9 @@ public class BukkitWorldManager implements WorldManager, Listener {
|
||||
CEWorld ceWorld = new BukkitCEWorld(world, this.storageAdaptor);
|
||||
this.worlds.put(uuid, ceWorld);
|
||||
this.resetWorldArray();
|
||||
this.injectChunkGenerator(ceWorld);
|
||||
for (Chunk chunk : ((World) world.platformWorld()).getLoadedChunks()) {
|
||||
handleChunkLoad(ceWorld, chunk);
|
||||
handleChunkLoad(ceWorld, chunk, false);
|
||||
}
|
||||
ceWorld.setTicking(true);
|
||||
}
|
||||
@@ -154,12 +157,20 @@ public class BukkitWorldManager implements WorldManager, Listener {
|
||||
if (this.worlds.containsKey(uuid)) return;
|
||||
this.worlds.put(uuid, world);
|
||||
this.resetWorldArray();
|
||||
this.injectChunkGenerator(world);
|
||||
for (Chunk chunk : ((World) world.world().platformWorld()).getLoadedChunks()) {
|
||||
handleChunkLoad(world, chunk);
|
||||
handleChunkLoad(world, chunk, false);
|
||||
}
|
||||
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
|
||||
public CEWorld createWorld(net.momirealms.craftengine.core.world.World world, WorldDataStorage storage) {
|
||||
return new BukkitCEWorld(world, storage);
|
||||
@@ -219,7 +230,7 @@ public class BukkitWorldManager implements WorldManager, Listener {
|
||||
if (world == null) {
|
||||
return;
|
||||
}
|
||||
handleChunkLoad(world, event.getChunk());
|
||||
handleChunkLoad(world, event.getChunk(), event.isNewChunk());
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
|
||||
@@ -273,14 +284,42 @@ public class BukkitWorldManager implements WorldManager, Listener {
|
||||
FastNMS.INSTANCE.method$LevelChunk$markUnsaved(levelChunk);
|
||||
}
|
||||
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 chunkZ = chunk.getZ();
|
||||
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;
|
||||
try {
|
||||
ceChunk = ceWorld.worldDataStorage().readChunkAt(ceWorld, chunkPos);
|
||||
@@ -382,5 +421,6 @@ public class BukkitWorldManager implements WorldManager, Listener {
|
||||
return;
|
||||
}
|
||||
ceChunk.load();
|
||||
ceChunk.activateAllBlockEntities();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,6 +81,15 @@ resource-pack:
|
||||
suffix: "minecraft/atlases"
|
||||
resolution:
|
||||
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
|
||||
# If your resource pack is compliant with the standard, you can disable validation to improve the resource pack generation speed.
|
||||
validation:
|
||||
|
||||
@@ -2,7 +2,7 @@ items:
|
||||
default:amethyst_torch:
|
||||
material: nether_brick
|
||||
data:
|
||||
item-name: <!i><i18n:item.amethyst_torch>
|
||||
item-name: <!i><l10n:item.amethyst_torch>
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: minecraft:item/custom/amethyst_torch
|
||||
@@ -20,7 +20,7 @@ items:
|
||||
default:amethyst_standing_torch:
|
||||
material: nether_brick
|
||||
data:
|
||||
item-name: <!i><i18n:item.amethyst_torch>
|
||||
item-name: <!i><l10n:item.amethyst_torch>
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: minecraft:block/custom/amethyst_torch
|
||||
@@ -31,7 +31,7 @@ items:
|
||||
default:amethyst_wall_torch:
|
||||
material: nether_brick
|
||||
data:
|
||||
item-name: <!i><i18n:item.amethyst_torch>
|
||||
item-name: <!i><l10n:item.amethyst_torch>
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: minecraft:block/custom/amethyst_wall_torch
|
||||
|
||||
@@ -2,7 +2,7 @@ items:
|
||||
default:chessboard_block:
|
||||
material: nether_brick
|
||||
data:
|
||||
item-name: <!i><i18n:item.chessboard_block>
|
||||
item-name: <!i><l10n:item.chessboard_block>
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: minecraft:item/custom/chessboard_block
|
||||
|
||||
@@ -2,7 +2,7 @@ items:
|
||||
default:chinese_lantern:
|
||||
material: nether_brick
|
||||
data:
|
||||
item-name: <!i><i18n:item.chinese_lantern>
|
||||
item-name: <!i><l10n:item.chinese_lantern>
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: minecraft:item/custom/chinese_lantern
|
||||
|
||||
@@ -2,7 +2,7 @@ items:
|
||||
default:copper_coil:
|
||||
material: nether_brick
|
||||
data:
|
||||
item-name: <!i><i18n:item.copper_coil>
|
||||
item-name: <!i><l10n:item.copper_coil>
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: minecraft:item/custom/copper_coil
|
||||
|
||||
@@ -2,7 +2,7 @@ items:
|
||||
default:ender_pearl_flower_seeds:
|
||||
material: nether_brick
|
||||
data:
|
||||
item-name: <!i><i18n:item.ender_pearl_flower_seeds>
|
||||
item-name: <!i><l10n:item.ender_pearl_flower_seeds>
|
||||
model:
|
||||
template: default:model/simplified_generated
|
||||
arguments:
|
||||
|
||||
@@ -2,7 +2,7 @@ items:
|
||||
default:fairy_flower:
|
||||
material: nether_brick
|
||||
data:
|
||||
item-name: <!i><i18n:item.fairy_flower>
|
||||
item-name: <!i><l10n:item.fairy_flower>
|
||||
model:
|
||||
template: default:model/simplified_generated
|
||||
arguments:
|
||||
|
||||
@@ -2,7 +2,7 @@ items:
|
||||
default:flame_cane:
|
||||
material: nether_brick
|
||||
data:
|
||||
item-name: <!i><i18n:item.flame_cane>
|
||||
item-name: <!i><l10n:item.flame_cane>
|
||||
model:
|
||||
template: default:model/simplified_generated
|
||||
arguments:
|
||||
|
||||
@@ -2,7 +2,7 @@ items:
|
||||
default:gunpowder_block:
|
||||
material: nether_brick
|
||||
data:
|
||||
item-name: <!i><i18n:item.gunpowder_block>
|
||||
item-name: <!i><l10n:item.gunpowder_block>
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: minecraft:item/custom/gunpowder_block
|
||||
@@ -37,7 +37,7 @@ items:
|
||||
default:solid_gunpowder_block:
|
||||
material: nether_brick
|
||||
data:
|
||||
item-name: <!i><i18n:item.solid_gunpowder_block>
|
||||
item-name: <!i><l10n:item.solid_gunpowder_block>
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: minecraft:item/custom/solid_gunpowder_block
|
||||
|
||||
@@ -2,7 +2,7 @@ items:
|
||||
default:hami_melon_slice:
|
||||
material: melon_slice
|
||||
data:
|
||||
item-name: <!i><i18n:item.hami_melon_slice>
|
||||
item-name: <!i><l10n:item.hami_melon_slice>
|
||||
$$>=1.20.5:
|
||||
food:
|
||||
nutrition: 2
|
||||
@@ -20,7 +20,7 @@ items:
|
||||
default:hami_melon:
|
||||
material: nether_brick
|
||||
data:
|
||||
item-name: <!i><i18n:item.hami_melon>
|
||||
item-name: <!i><l10n:item.hami_melon>
|
||||
model:
|
||||
path: minecraft:item/custom/hami_melon
|
||||
generation:
|
||||
@@ -31,7 +31,7 @@ items:
|
||||
default:hami_melon_seeds:
|
||||
material: nether_brick
|
||||
data:
|
||||
item-name: <!i><i18n:item.hami_melon_seeds>
|
||||
item-name: <!i><l10n:item.hami_melon_seeds>
|
||||
model:
|
||||
template: default:model/simplified_generated
|
||||
arguments:
|
||||
|
||||
@@ -6,7 +6,7 @@ items:
|
||||
arguments:
|
||||
path: minecraft:item/custom/magma_fruit
|
||||
data:
|
||||
item-name: <!i><white><i18n:item.magma_fruit>
|
||||
item-name: <!i><white><l10n:item.magma_fruit>
|
||||
$$>=1.20.5:
|
||||
food:
|
||||
nutrition: 3
|
||||
|
||||
@@ -2,7 +2,7 @@ items:
|
||||
default:netherite_anvil:
|
||||
material: nether_brick
|
||||
data:
|
||||
item-name: <!i><i18n:item.netherite_anvil>
|
||||
item-name: <!i><l10n:item.netherite_anvil>
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: minecraft:item/custom/netherite_anvil
|
||||
|
||||
@@ -8,7 +8,7 @@ items:
|
||||
- minecraft:logs
|
||||
- minecraft:logs_that_burn
|
||||
data:
|
||||
item-name: <!i><i18n:item.palm_log>
|
||||
item-name: <!i><l10n:item.palm_log>
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: minecraft:item/custom/palm_log
|
||||
@@ -40,7 +40,7 @@ items:
|
||||
- minecraft:logs
|
||||
- minecraft:logs_that_burn
|
||||
data:
|
||||
item-name: <!i><i18n:item.stripped_palm_log>
|
||||
item-name: <!i><l10n:item.stripped_palm_log>
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: minecraft:item/custom/stripped_palm_log
|
||||
@@ -69,7 +69,7 @@ items:
|
||||
- minecraft:logs
|
||||
- minecraft:logs_that_burn
|
||||
data:
|
||||
item-name: <!i><i18n:item.palm_wood>
|
||||
item-name: <!i><l10n:item.palm_wood>
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: minecraft:item/custom/palm_wood
|
||||
@@ -101,7 +101,7 @@ items:
|
||||
- minecraft:logs
|
||||
- minecraft:logs_that_burn
|
||||
data:
|
||||
item-name: <!i><i18n:item.stripped_palm_wood>
|
||||
item-name: <!i><l10n:item.stripped_palm_wood>
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: minecraft:item/custom/stripped_palm_wood
|
||||
@@ -129,7 +129,7 @@ items:
|
||||
- minecraft:planks
|
||||
- minecraft:wooden_tool_materials
|
||||
data:
|
||||
item-name: <!i><i18n:item.palm_planks>
|
||||
item-name: <!i><l10n:item.palm_planks>
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: minecraft:item/custom/palm_planks
|
||||
@@ -153,7 +153,7 @@ items:
|
||||
settings:
|
||||
fuel-time: 100
|
||||
data:
|
||||
item-name: <!i><i18n:item.palm_sapling>
|
||||
item-name: <!i><l10n:item.palm_sapling>
|
||||
lore:
|
||||
- "<!i><gray>Requires the datapack tree configuration to function."
|
||||
- "<!i><gray>If not configured, an oak tree will grow by default."
|
||||
@@ -197,7 +197,7 @@ items:
|
||||
default:palm_leaves:
|
||||
material: oak_leaves
|
||||
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]
|
||||
model:
|
||||
type: minecraft:model
|
||||
@@ -227,7 +227,7 @@ items:
|
||||
default:palm_trapdoor:
|
||||
material: nether_brick
|
||||
data:
|
||||
item-name: <!i><i18n:item.palm_trapdoor>
|
||||
item-name: <!i><l10n:item.palm_trapdoor>
|
||||
settings:
|
||||
fuel-time: 300
|
||||
model:
|
||||
@@ -281,7 +281,7 @@ items:
|
||||
default:palm_door:
|
||||
material: nether_brick
|
||||
data:
|
||||
item-name: <!i><i18n:item.palm_door>
|
||||
item-name: <!i><l10n:item.palm_door>
|
||||
settings:
|
||||
fuel-time: 200
|
||||
model:
|
||||
@@ -355,7 +355,7 @@ items:
|
||||
default:palm_fence_gate:
|
||||
material: nether_brick
|
||||
data:
|
||||
item-name: <!i><i18n:item.palm_fence_gate>
|
||||
item-name: <!i><l10n:item.palm_fence_gate>
|
||||
settings:
|
||||
fuel-time: 300
|
||||
model:
|
||||
@@ -411,7 +411,7 @@ items:
|
||||
default:palm_slab:
|
||||
material: nether_brick
|
||||
data:
|
||||
item-name: <!i><i18n:item.palm_slab>
|
||||
item-name: <!i><l10n:item.palm_slab>
|
||||
settings:
|
||||
fuel-time: 150
|
||||
model:
|
||||
@@ -462,7 +462,7 @@ items:
|
||||
generation:
|
||||
parent: minecraft:block/custom/palm_stairs
|
||||
data:
|
||||
item-name: <!i><i18n:item.palm_stairs>
|
||||
item-name: <!i><l10n:item.palm_stairs>
|
||||
settings:
|
||||
fuel-time: 300
|
||||
behavior:
|
||||
@@ -511,7 +511,7 @@ items:
|
||||
generation:
|
||||
parent: minecraft:block/custom/palm_pressure_plate
|
||||
data:
|
||||
item-name: <!i><i18n:item.palm_pressure_plate>
|
||||
item-name: <!i><l10n:item.palm_pressure_plate>
|
||||
settings:
|
||||
fuel-time: 300
|
||||
behavior:
|
||||
@@ -560,7 +560,7 @@ items#pfence:
|
||||
default:palm_fence:
|
||||
material: nether_brick
|
||||
data:
|
||||
item-name: <!i><i18n:item.palm_fence>
|
||||
item-name: <!i><l10n:item.palm_fence>
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: minecraft:item/custom/palm_fence_inventory
|
||||
@@ -632,7 +632,7 @@ items#button:
|
||||
textures:
|
||||
texture: minecraft:block/custom/palm_planks
|
||||
data:
|
||||
item-name: <!i><i18n:item.palm_button>
|
||||
item-name: <!i><l10n:item.palm_button>
|
||||
settings:
|
||||
fuel-time: 100
|
||||
behavior:
|
||||
|
||||
@@ -2,7 +2,7 @@ items:
|
||||
default:pebble:
|
||||
material: nether_brick
|
||||
data:
|
||||
item-name: <!i><i18n:item.pebble>
|
||||
item-name: <!i><l10n:item.pebble>
|
||||
model:
|
||||
template: default:model/simplified_generated
|
||||
arguments:
|
||||
|
||||
@@ -2,7 +2,7 @@ items:
|
||||
default:reed:
|
||||
material: nether_brick
|
||||
data:
|
||||
item-name: <!i><i18n:item.reed>
|
||||
item-name: <!i><l10n:item.reed>
|
||||
model:
|
||||
template: default:model/simplified_generated
|
||||
arguments:
|
||||
|
||||
@@ -2,7 +2,7 @@ items:
|
||||
default:safe_block:
|
||||
material: nether_brick
|
||||
data:
|
||||
item-name: <!i><i18n:item.safe_block>
|
||||
item-name: <!i><l10n:item.safe_block>
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: minecraft:item/custom/safe_block
|
||||
@@ -31,7 +31,7 @@ items:
|
||||
step: minecraft:block.stone.step
|
||||
behavior:
|
||||
type: simple_storage_block
|
||||
title: "<i18n:item.safe_block>"
|
||||
title: "<l10n:item.safe_block>"
|
||||
rows: 1
|
||||
sounds:
|
||||
open: minecraft:block.iron_trapdoor.open
|
||||
@@ -58,6 +58,7 @@ items:
|
||||
front: minecraft:block/custom/safe_block_front
|
||||
side: minecraft:block/custom/safe_block_side
|
||||
top: minecraft:block/custom/safe_block_top
|
||||
bottom: minecraft:block/custom/safe_block_bottom
|
||||
east_open:
|
||||
auto-state: note_block
|
||||
model:
|
||||
@@ -69,6 +70,7 @@ items:
|
||||
front: minecraft:block/custom/safe_block_front_open
|
||||
side: minecraft:block/custom/safe_block_side
|
||||
top: minecraft:block/custom/safe_block_top
|
||||
bottom: minecraft:block/custom/safe_block_bottom
|
||||
north:
|
||||
auto-state: note_block
|
||||
model:
|
||||
|
||||
@@ -2,7 +2,7 @@ items:
|
||||
default:sleeper_sofa:
|
||||
material: nether_brick
|
||||
data:
|
||||
item-name: <!i><i18n:item.sofa>
|
||||
item-name: <!i><l10n:item.sofa>
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: minecraft:item/custom/sleeper_sofa
|
||||
@@ -50,7 +50,7 @@ items:
|
||||
default:sofa:
|
||||
material: nether_brick
|
||||
data:
|
||||
item-name: <!i><i18n:item.sofa>
|
||||
item-name: <!i><l10n:item.sofa>
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: minecraft:item/custom/sofa
|
||||
|
||||
@@ -2,7 +2,7 @@ items:
|
||||
default:table_lamp:
|
||||
material: nether_brick
|
||||
data:
|
||||
item-name: <!i><i18n:item.table_lamp>
|
||||
item-name: <!i><l10n:item.table_lamp>
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: minecraft:item/custom/table_lamp
|
||||
|
||||
@@ -2,7 +2,7 @@ items:
|
||||
default:topaz_ore:
|
||||
material: nether_brick
|
||||
data:
|
||||
item-name: <!i><i18n:item.topaz_ore>
|
||||
item-name: <!i><l10n:item.topaz_ore>
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: minecraft:item/custom/topaz_ore
|
||||
@@ -14,7 +14,7 @@ items:
|
||||
default:deepslate_topaz_ore:
|
||||
material: nether_brick
|
||||
data:
|
||||
item-name: <!i><i18n:item.deepslate_topaz_ore>
|
||||
item-name: <!i><l10n:item.deepslate_topaz_ore>
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: minecraft:item/custom/deepslate_topaz_ore
|
||||
@@ -31,7 +31,7 @@ items:
|
||||
- '#default:topaz_tools'
|
||||
percent: 0.25
|
||||
data:
|
||||
item-name: <!i><#FF8C00><i18n:item.topaz>
|
||||
item-name: <!i><#FF8C00><l10n:item.topaz>
|
||||
model:
|
||||
template: default:model/simplified_generated
|
||||
arguments:
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
categories:
|
||||
default:default:
|
||||
priority: 1
|
||||
name: <!i><white><i18n:category.default.name></white>
|
||||
name: <!i><white><l10n:category.default.name></white>
|
||||
lore:
|
||||
- <!i><gray><i18n:category.default.lore>
|
||||
- <!i><gray><l10n:category.default.lore>
|
||||
icon: default:topaz
|
||||
list:
|
||||
- '#default:palm_tree'
|
||||
- '#default:topaz'
|
||||
- '#default:misc'
|
||||
default:palm_tree:
|
||||
name: <!i><green><i18n:category.palm_tree></green>
|
||||
name: <!i><green><l10n:category.palm_tree></green>
|
||||
hidden: true
|
||||
icon: default:palm_log
|
||||
list:
|
||||
@@ -30,7 +30,7 @@ categories:
|
||||
- default:palm_pressure_plate
|
||||
- default:palm_button
|
||||
default:topaz:
|
||||
name: <!i><#FF8C00><i18n:category.topaz></#FF8C00>
|
||||
name: <!i><#FF8C00><l10n:category.topaz></#FF8C00>
|
||||
hidden: true
|
||||
icon: default:topaz
|
||||
list:
|
||||
@@ -51,7 +51,7 @@ categories:
|
||||
- default:topaz_leggings
|
||||
- default:topaz_boots
|
||||
default:misc:
|
||||
name: <!i><gray><i18n:category.misc></gray>
|
||||
name: <!i><gray><l10n:category.misc></gray>
|
||||
hidden: true
|
||||
icon: default:chinese_lantern
|
||||
list:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
templates:
|
||||
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:
|
||||
default:emoji_smiley:
|
||||
template: default:emoji/basic
|
||||
|
||||
@@ -2,7 +2,7 @@ items:
|
||||
default:bench:
|
||||
material: nether_brick
|
||||
data:
|
||||
item-name: <!i><i18n:item.bench>
|
||||
item-name: <!i><l10n:item.bench>
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: minecraft:item/custom/bench
|
||||
|
||||
@@ -2,7 +2,7 @@ items:
|
||||
default:flower_basket:
|
||||
material: nether_brick
|
||||
data:
|
||||
item-name: <!i><i18n:item.flower_basket>
|
||||
item-name: <!i><l10n:item.flower_basket>
|
||||
model:
|
||||
template: default:model/simplified_generated
|
||||
arguments:
|
||||
|
||||
@@ -2,7 +2,7 @@ items:
|
||||
default:wooden_chair:
|
||||
material: nether_brick
|
||||
data:
|
||||
item-name: <!i><i18n:item.wooden_chair>
|
||||
item-name: <!i><l10n:item.wooden_chair>
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: minecraft:item/custom/wooden_chair
|
||||
|
||||
@@ -4,7 +4,7 @@ items:
|
||||
$$<=1.21.1:
|
||||
client-bound-material: leather_horse_armor
|
||||
data:
|
||||
item-name: <!i><white><i18n:item.cap>
|
||||
item-name: <!i><white><l10n:item.cap>
|
||||
unbreakable: true
|
||||
remove-components:
|
||||
- attribute_modifiers
|
||||
|
||||
@@ -8,7 +8,7 @@ items:
|
||||
asset-id: flame
|
||||
wings: flame_elytra
|
||||
data:
|
||||
item-name: <!i><#FF8C00><i18n:item.flame_elytra>
|
||||
item-name: <!i><#FF8C00><l10n:item.flame_elytra>
|
||||
model:
|
||||
template: default:model/simplified_elytra
|
||||
arguments:
|
||||
|
||||
@@ -2,7 +2,7 @@ templates:
|
||||
default:armor/topaz:
|
||||
material: chainmail_${part}
|
||||
data:
|
||||
item-name: <!i><#FF8C00><i18n:item.topaz_${part}>
|
||||
item-name: <!i><#FF8C00><l10n:item.topaz_${part}>
|
||||
tooltip-style: minecraft:topaz
|
||||
settings:
|
||||
tags:
|
||||
|
||||
@@ -5,7 +5,7 @@ items:
|
||||
tags:
|
||||
- default:topaz_tools
|
||||
data:
|
||||
item-name: <!i><#FF8C00><i18n:item.topaz_rod>
|
||||
item-name: <!i><#FF8C00><l10n:item.topaz_rod>
|
||||
tooltip-style: minecraft:topaz
|
||||
model:
|
||||
template: default:model/simplified_fishing_rod_2d
|
||||
@@ -18,7 +18,7 @@ items:
|
||||
tags:
|
||||
- default:topaz_tools
|
||||
data:
|
||||
item-name: <!i><#FF8C00><i18n:item.topaz_bow>
|
||||
item-name: <!i><#FF8C00><l10n:item.topaz_bow>
|
||||
tooltip-style: minecraft:topaz
|
||||
model:
|
||||
template: default:model/simplified_bow_2d
|
||||
@@ -33,7 +33,7 @@ items:
|
||||
tags:
|
||||
- default:topaz_tools
|
||||
data:
|
||||
item-name: <!i><#FF8C00><i18n:item.topaz_crossbow>
|
||||
item-name: <!i><#FF8C00><l10n:item.topaz_crossbow>
|
||||
tooltip-style: minecraft:topaz
|
||||
model:
|
||||
template: default:model/simplified_crossbow_2d
|
||||
@@ -50,7 +50,7 @@ items:
|
||||
tags:
|
||||
- default:topaz_tools
|
||||
data:
|
||||
item-name: <!i><#FF8C00><i18n:item.topaz_pickaxe>
|
||||
item-name: <!i><#FF8C00><l10n:item.topaz_pickaxe>
|
||||
tooltip-style: minecraft:topaz
|
||||
max-damage: 64
|
||||
model:
|
||||
@@ -63,7 +63,7 @@ items:
|
||||
tags:
|
||||
- default:topaz_tools
|
||||
data:
|
||||
item-name: <!i><#FF8C00><i18n:item.topaz_axe>
|
||||
item-name: <!i><#FF8C00><l10n:item.topaz_axe>
|
||||
tooltip-style: minecraft:topaz
|
||||
max-damage: 64
|
||||
model:
|
||||
@@ -76,7 +76,7 @@ items:
|
||||
tags:
|
||||
- default:topaz_tools
|
||||
data:
|
||||
item-name: <!i><#FF8C00><i18n:item.topaz_hoe>
|
||||
item-name: <!i><#FF8C00><l10n:item.topaz_hoe>
|
||||
tooltip-style: minecraft:topaz
|
||||
max-damage: 64
|
||||
model:
|
||||
@@ -89,7 +89,7 @@ items:
|
||||
tags:
|
||||
- default:topaz_tools
|
||||
data:
|
||||
item-name: <!i><#FF8C00><i18n:item.topaz_shovel>
|
||||
item-name: <!i><#FF8C00><l10n:item.topaz_shovel>
|
||||
tooltip-style: minecraft:topaz
|
||||
max-damage: 64
|
||||
model:
|
||||
@@ -102,7 +102,7 @@ items:
|
||||
tags:
|
||||
- default:topaz_tools
|
||||
data:
|
||||
item-name: <!i><#FF8C00><i18n:item.topaz_sword>
|
||||
item-name: <!i><#FF8C00><l10n:item.topaz_sword>
|
||||
tooltip-style: minecraft:topaz
|
||||
max-damage: 64
|
||||
model:
|
||||
@@ -122,7 +122,7 @@ items:
|
||||
tags:
|
||||
- default:topaz_tools
|
||||
data:
|
||||
item-name: <!i><#FF8C00><i18n:item.topaz_trident>
|
||||
item-name: <!i><#FF8C00><l10n:item.topaz_trident>
|
||||
tooltip-style: minecraft:topaz
|
||||
max-damage: 300
|
||||
model:
|
||||
@@ -163,7 +163,7 @@ items:
|
||||
$$1.20.1~1.21.1: bow
|
||||
$$1.21.2~1.21.3: honey_bottle
|
||||
data:
|
||||
item-name: <!i><#FF8C00><i18n:item.topaz_trident>
|
||||
item-name: <!i><#FF8C00><l10n:item.topaz_trident>
|
||||
components:
|
||||
minecraft:max_damage: 300
|
||||
$$>=1.21.2:
|
||||
|
||||
@@ -2682,354 +2682,354 @@ templates#block_states:
|
||||
state: ${base_block}[east=false,north=false,south=false,waterlogged=false,west=false]
|
||||
entity-renderer:
|
||||
- item: ${fence_post_item}
|
||||
rotation: 180
|
||||
yaw: 180
|
||||
scale: 1.0003
|
||||
translation: 0,0.0001,0
|
||||
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:
|
||||
- item: ${fence_post_item}
|
||||
rotation: 180
|
||||
yaw: 180
|
||||
scale: 1.0003
|
||||
translation: 0,0.0001,0
|
||||
- item: ${fence_side_item}
|
||||
rotation: 270
|
||||
yaw: 270
|
||||
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:
|
||||
- item: ${fence_post_item}
|
||||
rotation: 180
|
||||
yaw: 180
|
||||
scale: 1.0003
|
||||
translation: 0,0.0001,0
|
||||
- item: ${fence_side_item}
|
||||
rotation: 180
|
||||
yaw: 180
|
||||
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:
|
||||
- item: ${fence_post_item}
|
||||
rotation: 180
|
||||
yaw: 180
|
||||
scale: 1.0003
|
||||
translation: 0,0.0001,0
|
||||
- item: ${fence_side_item}
|
||||
rotation: 0
|
||||
yaw: 0
|
||||
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:
|
||||
- item: ${fence_post_item}
|
||||
rotation: 180
|
||||
yaw: 180
|
||||
scale: 1.0003
|
||||
translation: 0,0.0001,0
|
||||
- item: ${fence_side_item}
|
||||
rotation: 90
|
||||
yaw: 90
|
||||
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:
|
||||
- item: ${fence_post_item}
|
||||
rotation: 180
|
||||
yaw: 180
|
||||
scale: 1.0003
|
||||
translation: 0,0.0001,0
|
||||
- item: ${fence_side_item}
|
||||
rotation: 180
|
||||
yaw: 180
|
||||
- item: ${fence_side_item}
|
||||
rotation: 270
|
||||
yaw: 270
|
||||
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:
|
||||
- item: ${fence_post_item}
|
||||
rotation: 180
|
||||
yaw: 180
|
||||
scale: 1.0003
|
||||
translation: 0,0.0001,0
|
||||
- item: ${fence_side_item}
|
||||
rotation: 0
|
||||
yaw: 0
|
||||
- item: ${fence_side_item}
|
||||
rotation: 270
|
||||
yaw: 270
|
||||
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:
|
||||
- item: ${fence_post_item}
|
||||
rotation: 180
|
||||
yaw: 180
|
||||
scale: 1.0003
|
||||
translation: 0,0.0001,0
|
||||
- item: ${fence_side_item}
|
||||
rotation: 90
|
||||
yaw: 90
|
||||
- item: ${fence_side_item}
|
||||
rotation: 270
|
||||
yaw: 270
|
||||
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:
|
||||
- item: ${fence_post_item}
|
||||
rotation: 180
|
||||
yaw: 180
|
||||
scale: 1.0003
|
||||
translation: 0,0.0001,0
|
||||
- item: ${fence_side_item}
|
||||
rotation: 0
|
||||
yaw: 0
|
||||
- item: ${fence_side_item}
|
||||
rotation: 180
|
||||
yaw: 180
|
||||
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:
|
||||
- item: ${fence_post_item}
|
||||
rotation: 180
|
||||
yaw: 180
|
||||
scale: 1.0003
|
||||
translation: 0,0.0001,0
|
||||
- item: ${fence_side_item}
|
||||
rotation: 90
|
||||
yaw: 90
|
||||
- item: ${fence_side_item}
|
||||
rotation: 180
|
||||
yaw: 180
|
||||
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:
|
||||
- item: ${fence_post_item}
|
||||
rotation: 180
|
||||
yaw: 180
|
||||
scale: 1.0003
|
||||
translation: 0,0.0001,0
|
||||
- item: ${fence_side_item}
|
||||
rotation: 0
|
||||
yaw: 0
|
||||
- item: ${fence_side_item}
|
||||
rotation: 90
|
||||
yaw: 90
|
||||
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:
|
||||
- item: ${fence_post_item}
|
||||
rotation: 180
|
||||
yaw: 180
|
||||
scale: 1.0003
|
||||
translation: 0,0.0001,0
|
||||
- item: ${fence_side_item}
|
||||
rotation: 0
|
||||
yaw: 0
|
||||
- item: ${fence_side_item}
|
||||
rotation: 180
|
||||
yaw: 180
|
||||
- item: ${fence_side_item}
|
||||
rotation: 270
|
||||
yaw: 270
|
||||
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:
|
||||
- item: ${fence_post_item}
|
||||
rotation: 180
|
||||
yaw: 180
|
||||
scale: 1.0003
|
||||
translation: 0,0.0001,0
|
||||
- item: ${fence_side_item}
|
||||
rotation: 90
|
||||
yaw: 90
|
||||
- item: ${fence_side_item}
|
||||
rotation: 180
|
||||
yaw: 180
|
||||
- item: ${fence_side_item}
|
||||
rotation: 270
|
||||
yaw: 270
|
||||
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:
|
||||
- item: ${fence_post_item}
|
||||
rotation: 180
|
||||
yaw: 180
|
||||
scale: 1.0003
|
||||
translation: 0,0.0001,0
|
||||
- item: ${fence_side_item}
|
||||
rotation: 0
|
||||
yaw: 0
|
||||
- item: ${fence_side_item}
|
||||
rotation: 90
|
||||
yaw: 90
|
||||
- item: ${fence_side_item}
|
||||
rotation: 270
|
||||
yaw: 270
|
||||
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:
|
||||
- item: ${fence_post_item}
|
||||
rotation: 180
|
||||
yaw: 180
|
||||
scale: 1.0003
|
||||
translation: 0,0.0001,0
|
||||
- item: ${fence_side_item}
|
||||
rotation: 0
|
||||
yaw: 0
|
||||
- item: ${fence_side_item}
|
||||
rotation: 90
|
||||
yaw: 90
|
||||
- item: ${fence_side_item}
|
||||
rotation: 180
|
||||
yaw: 180
|
||||
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:
|
||||
- item: ${fence_post_item}
|
||||
rotation: 180
|
||||
yaw: 180
|
||||
scale: 1.0003
|
||||
translation: 0,0.0001,0
|
||||
- item: ${fence_side_item}
|
||||
rotation: 0
|
||||
yaw: 0
|
||||
- item: ${fence_side_item}
|
||||
rotation: 90
|
||||
yaw: 90
|
||||
- item: ${fence_side_item}
|
||||
rotation: 180
|
||||
yaw: 180
|
||||
- item: ${fence_side_item}
|
||||
rotation: 270
|
||||
yaw: 270
|
||||
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:
|
||||
- item: ${fence_post_item}
|
||||
rotation: 180
|
||||
yaw: 180
|
||||
scale: 1.0003
|
||||
translation: 0,0.0001,0
|
||||
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:
|
||||
- item: ${fence_post_item}
|
||||
rotation: 180
|
||||
yaw: 180
|
||||
scale: 1.0003
|
||||
translation: 0,0.0001,0
|
||||
- item: ${fence_side_item}
|
||||
rotation: 270
|
||||
yaw: 270
|
||||
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:
|
||||
- item: ${fence_post_item}
|
||||
rotation: 180
|
||||
yaw: 180
|
||||
scale: 1.0003
|
||||
translation: 0,0.0001,0
|
||||
- item: ${fence_side_item}
|
||||
rotation: 180
|
||||
yaw: 180
|
||||
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:
|
||||
- item: ${fence_post_item}
|
||||
rotation: 180
|
||||
yaw: 180
|
||||
scale: 1.0003
|
||||
translation: 0,0.0001,0
|
||||
- item: ${fence_side_item}
|
||||
rotation: 0
|
||||
yaw: 0
|
||||
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:
|
||||
- item: ${fence_post_item}
|
||||
rotation: 180
|
||||
yaw: 180
|
||||
scale: 1.0003
|
||||
translation: 0,0.0001,0
|
||||
- item: ${fence_side_item}
|
||||
rotation: 90
|
||||
yaw: 90
|
||||
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:
|
||||
- item: ${fence_post_item}
|
||||
rotation: 180
|
||||
yaw: 180
|
||||
scale: 1.0003
|
||||
translation: 0,0.0001,0
|
||||
- item: ${fence_side_item}
|
||||
rotation: 180
|
||||
yaw: 180
|
||||
- item: ${fence_side_item}
|
||||
rotation: 270
|
||||
yaw: 270
|
||||
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:
|
||||
- item: ${fence_post_item}
|
||||
rotation: 180
|
||||
yaw: 180
|
||||
scale: 1.0003
|
||||
translation: 0,0.0001,0
|
||||
- item: ${fence_side_item}
|
||||
rotation: 0
|
||||
yaw: 0
|
||||
- item: ${fence_side_item}
|
||||
rotation: 270
|
||||
yaw: 270
|
||||
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:
|
||||
- item: ${fence_post_item}
|
||||
rotation: 180
|
||||
yaw: 180
|
||||
scale: 1.0003
|
||||
translation: 0,0.0001,0
|
||||
- item: ${fence_side_item}
|
||||
rotation: 90
|
||||
yaw: 90
|
||||
- item: ${fence_side_item}
|
||||
rotation: 270
|
||||
yaw: 270
|
||||
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:
|
||||
- item: ${fence_post_item}
|
||||
rotation: 180
|
||||
yaw: 180
|
||||
scale: 1.0003
|
||||
translation: 0,0.0001,0
|
||||
- item: ${fence_side_item}
|
||||
rotation: 0
|
||||
yaw: 0
|
||||
- item: ${fence_side_item}
|
||||
rotation: 180
|
||||
yaw: 180
|
||||
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:
|
||||
- item: ${fence_post_item}
|
||||
rotation: 180
|
||||
yaw: 180
|
||||
scale: 1.0003
|
||||
translation: 0,0.0001,0
|
||||
- item: ${fence_side_item}
|
||||
rotation: 90
|
||||
yaw: 90
|
||||
- item: ${fence_side_item}
|
||||
rotation: 180
|
||||
yaw: 180
|
||||
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:
|
||||
- item: ${fence_post_item}
|
||||
rotation: 180
|
||||
yaw: 180
|
||||
scale: 1.0003
|
||||
translation: 0,0.0001,0
|
||||
- item: ${fence_side_item}
|
||||
rotation: 0
|
||||
yaw: 0
|
||||
- item: ${fence_side_item}
|
||||
rotation: 90
|
||||
yaw: 90
|
||||
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:
|
||||
- item: ${fence_post_item}
|
||||
rotation: 180
|
||||
yaw: 180
|
||||
scale: 1.0003
|
||||
translation: 0,0.0001,0
|
||||
- item: ${fence_side_item}
|
||||
rotation: 0
|
||||
yaw: 0
|
||||
- item: ${fence_side_item}
|
||||
rotation: 180
|
||||
yaw: 180
|
||||
- item: ${fence_side_item}
|
||||
rotation: 270
|
||||
yaw: 270
|
||||
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:
|
||||
- item: ${fence_post_item}
|
||||
rotation: 180
|
||||
yaw: 180
|
||||
scale: 1.0003
|
||||
translation: 0,0.0001,0
|
||||
- item: ${fence_side_item}
|
||||
rotation: 90
|
||||
yaw: 90
|
||||
- item: ${fence_side_item}
|
||||
rotation: 180
|
||||
yaw: 180
|
||||
- item: ${fence_side_item}
|
||||
rotation: 270
|
||||
yaw: 270
|
||||
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:
|
||||
- item: ${fence_post_item}
|
||||
rotation: 180
|
||||
yaw: 180
|
||||
scale: 1.0003
|
||||
translation: 0,0.0001,0
|
||||
- item: ${fence_side_item}
|
||||
rotation: 0
|
||||
yaw: 0
|
||||
- item: ${fence_side_item}
|
||||
rotation: 90
|
||||
yaw: 90
|
||||
- item: ${fence_side_item}
|
||||
rotation: 270
|
||||
yaw: 270
|
||||
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:
|
||||
- item: ${fence_post_item}
|
||||
rotation: 180
|
||||
yaw: 180
|
||||
scale: 1.0003
|
||||
translation: 0,0.0001,0
|
||||
- item: ${fence_side_item}
|
||||
rotation: 0
|
||||
yaw: 0
|
||||
- item: ${fence_side_item}
|
||||
rotation: 90
|
||||
yaw: 90
|
||||
- item: ${fence_side_item}
|
||||
rotation: 180
|
||||
yaw: 180
|
||||
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:
|
||||
- item: ${fence_post_item}
|
||||
rotation: 180
|
||||
yaw: 180
|
||||
scale: 1.0003
|
||||
translation: 0,0.0001,0
|
||||
- item: ${fence_side_item}
|
||||
rotation: 0
|
||||
yaw: 0
|
||||
- item: ${fence_side_item}
|
||||
rotation: 90
|
||||
yaw: 90
|
||||
- item: ${fence_side_item}
|
||||
rotation: 180
|
||||
yaw: 180
|
||||
- item: ${fence_side_item}
|
||||
rotation: 270
|
||||
yaw: 270
|
||||
variants:
|
||||
waterlogged=true:
|
||||
settings:
|
||||
|
||||
@@ -2,6 +2,4 @@ author: XiaoMoMi
|
||||
version: 0.0.1
|
||||
description: Fix broken vanilla armor
|
||||
namespace: minecraft
|
||||
enable:
|
||||
$$>=1.21.2: false
|
||||
$$<1.21.2: true
|
||||
enable: false
|
||||
|
||||
@@ -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.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.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.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>"
|
||||
|
||||
@@ -65,6 +65,9 @@ command.upload.failure.not_supported: "<red>当前托管模式 '<arg:0>' 不支
|
||||
command.upload.on_progress: "<white>已开始上传进程. 检查控制台以获取详细信息</white>"
|
||||
command.send_resource_pack.success.single: "<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.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>"
|
||||
@@ -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.translation.unknown_locale: "<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.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.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>"
|
||||
@@ -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.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.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_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>"
|
||||
@@ -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.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.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.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.duplicate: "<yellow>在文件 <arg:0> 发现问题 - 重复的方块 '<arg:1>' 请检查其他文件中是否存在相同配置</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>"
|
||||
@@ -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.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.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_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_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_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.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_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_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_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.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.invalid_type: "<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_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_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.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>"
|
||||
|
||||
@@ -143,7 +143,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
|
||||
@Override
|
||||
public void delayedLoad() {
|
||||
this.initSuggestions();
|
||||
this.resendTags();
|
||||
this.updateTags();
|
||||
this.processSounds();
|
||||
this.clearCache();
|
||||
}
|
||||
@@ -232,7 +232,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
|
||||
|
||||
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);
|
||||
|
||||
|
||||
@@ -330,6 +330,37 @@ public final class BlockKeys {
|
||||
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 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[]{
|
||||
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
|
||||
|
||||
@@ -14,25 +14,37 @@ public class ConstantBlockEntityRenderer {
|
||||
|
||||
public void show(Player player) {
|
||||
for (BlockEntityElement element : this.elements) {
|
||||
element.show(player);
|
||||
if (element != null) {
|
||||
element.show(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void hide(Player player) {
|
||||
for (BlockEntityElement element : this.elements) {
|
||||
element.hide(player);
|
||||
if (element != null) {
|
||||
element.hide(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void deactivate() {
|
||||
for (BlockEntityElement element : this.elements) {
|
||||
element.deactivate();
|
||||
if (element != null) {
|
||||
element.deactivate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void activate() {
|
||||
for (BlockEntityElement element : this.elements) {
|
||||
element.activate();
|
||||
if (element != null) {
|
||||
element.activate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public BlockEntityElement[] elements() {
|
||||
return this.elements;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ public interface BlockEntityElement {
|
||||
|
||||
void hide(Player player);
|
||||
|
||||
default void transform(Player player) {}
|
||||
|
||||
default void deactivate() {}
|
||||
|
||||
default void activate() {}
|
||||
|
||||
@@ -6,4 +6,10 @@ import net.momirealms.craftengine.core.world.World;
|
||||
public interface BlockEntityElementConfig<E extends BlockEntityElement> {
|
||||
|
||||
E create(World world, BlockPos pos);
|
||||
|
||||
default E create(World world, BlockPos pos, E previous) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Class<E> elementClass();
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import java.util.Optional;
|
||||
public abstract class BlockEntityElementConfigs {
|
||||
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 ITEM = Key.of("craftengine:item");
|
||||
|
||||
public static void register(Key key, BlockEntityElementConfigFactory type) {
|
||||
((WritableRegistry<BlockEntityElementConfigFactory>) BuiltInRegistries.BLOCK_ENTITY_ELEMENT_TYPE)
|
||||
|
||||
@@ -4,6 +4,7 @@ import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.item.context.BlockPlaceContext;
|
||||
import net.momirealms.craftengine.core.util.Direction;
|
||||
import net.momirealms.craftengine.core.util.HorizontalDirection;
|
||||
import net.momirealms.craftengine.core.util.SegmentedAngle;
|
||||
import net.momirealms.sparrow.nbt.Tag;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -33,7 +34,7 @@ public abstract class Property<T extends Comparable<T>> {
|
||||
Property<Direction> directionProperty = (Property<Direction>) property;
|
||||
return (context, state) -> state.with(directionProperty, context.getNearestLookingDirection().opposite());
|
||||
} 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 -> {
|
||||
@@ -41,13 +42,26 @@ public abstract class Property<T extends Comparable<T>> {
|
||||
Property<HorizontalDirection> directionProperty = (Property<HorizontalDirection>) property;
|
||||
return (context, state) -> state.with(directionProperty, context.getHorizontalDirection().clockWise().toHorizontalDirection());
|
||||
} 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 -> {
|
||||
Property<Boolean> waterloggedProperty = (Property<Boolean>) property;
|
||||
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;
|
||||
|
||||
@@ -73,6 +73,10 @@ public class UseOnContext {
|
||||
return this.level;
|
||||
}
|
||||
|
||||
public World getWorld() {
|
||||
return this.level;
|
||||
}
|
||||
|
||||
public Direction getHorizontalDirection() {
|
||||
return this.player == null ? Direction.NORTH : this.player.getDirection();
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ public final class ItemDataModifiers {
|
||||
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 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 ATTRIBUTES = Key.of("craftengine:attributes");
|
||||
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 JUKEBOX_PLAYABLE = Key.of("craftengine:jukebox-playable");
|
||||
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 NBT = Key.of("craftengine:nbt");
|
||||
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(DISPLAY_NAME, ItemNameModifier.FACTORY);
|
||||
register(COMPONENTS, ComponentsModifier.FACTORY);
|
||||
register(COMPONENT, ComponentsModifier.FACTORY);
|
||||
register(REMOVE_COMPONENTS, RemoveComponentModifier.FACTORY);
|
||||
register(REMOVE_COMPONENT, RemoveComponentModifier.FACTORY);
|
||||
register(FOOD, FoodModifier.FACTORY);
|
||||
register(MAX_DAMAGE, MaxDamageModifier.FACTORY);
|
||||
} else {
|
||||
|
||||
@@ -43,7 +43,7 @@ public class SingleItemLootEntryContainer<T> extends AbstractSingleLootEntryCont
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
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);
|
||||
int weight = ResourceConfigUtils.getAsInt(arguments.getOrDefault("weight", 1), "weight");
|
||||
int quality = ResourceConfigUtils.getAsInt(arguments.getOrDefault("quality", 0), "quality");
|
||||
|
||||
@@ -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]));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@ import java.util.function.BiFunction;
|
||||
|
||||
public class LootFunctions {
|
||||
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 EXPLOSION_DECAY = Key.from("craftengine:explosion_decay");
|
||||
public static final Key DROP_EXP = Key.from("craftengine:drop_exp");
|
||||
@@ -24,6 +25,7 @@ public class LootFunctions {
|
||||
|
||||
static {
|
||||
register(SET_COUNT, SetCountFunction.FACTORY);
|
||||
register(APPLY_DATA, ApplyDataFunction.FACTORY);
|
||||
register(EXPLOSION_DECAY, ExplosionDecayFunction.FACTORY);
|
||||
register(APPLY_BONUS, ApplyBonusCountFunction.FACTORY);
|
||||
register(DROP_EXP, DropExpFunction.FACTORY);
|
||||
|
||||
@@ -40,10 +40,10 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.yaml.snakeyaml.LoaderOptions;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
import org.yaml.snakeyaml.parser.ParserException;
|
||||
import org.yaml.snakeyaml.scanner.ScannerException;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.imageio.ImageReader;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.*;
|
||||
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);
|
||||
}
|
||||
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) {
|
||||
e.setArgument(0, path.toString());
|
||||
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");
|
||||
Path finalPath = resourcePackPath();
|
||||
Files.createDirectories(finalPath.getParent());
|
||||
if (!VersionHelper.PREMIUM && Config.enableObfuscation()) {
|
||||
Config.instance().setObf(false);
|
||||
this.plugin.logger().warn("Resource pack obfuscation requires Premium Edition.");
|
||||
}
|
||||
try {
|
||||
this.zipGenerator.accept(generatedPackPath, finalPath);
|
||||
} catch (Exception e) {
|
||||
|
||||
@@ -38,7 +38,7 @@ public class ResolutionMergeAltas implements Resolution {
|
||||
j3.add("sources", ja3);
|
||||
GsonHelper.writeJsonFile(j3, existing.path());
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ public class Resolutions {
|
||||
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_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 MERGE_PACK_MCMETA = Key.of("craftengine:merge_pack_mcmeta");
|
||||
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_ATLAS, ResolutionMergeAltas.FACTORY);
|
||||
register(MERGE_LEGACY_MODEL, ResolutionMergeLegacyModel.FACTORY);
|
||||
register(MERGE_FONT, ResolutionMergeFont.FACTORY);
|
||||
}
|
||||
|
||||
public static void register(Key key, ResolutionFactory factory) {
|
||||
|
||||
@@ -184,6 +184,8 @@ public abstract class CraftEngine implements Plugin {
|
||||
delayedLoadTasks.add(CompletableFuture.runAsync(() -> this.recipeManager.delayedLoad(), this.scheduler.async()));
|
||||
}
|
||||
CompletableFutures.allOf(delayedLoadTasks).join();
|
||||
// 重新发送tags,需要等待tags更新完成
|
||||
this.networkManager.delayedLoad();
|
||||
long time2 = System.currentTimeMillis();
|
||||
asyncTime = time2 - time1;
|
||||
} finally {
|
||||
|
||||
@@ -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.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.locale.LocalizedResourceConfigException;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import net.momirealms.craftengine.core.util.MiscUtils;
|
||||
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
|
||||
import net.momirealms.craftengine.core.world.ExistingBlock;
|
||||
import net.momirealms.craftengine.core.world.World;
|
||||
import net.momirealms.craftengine.core.world.WorldPosition;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class MatchBlockCondition<CTX extends Context> implements Condition<CTX> {
|
||||
private final Set<String> ids;
|
||||
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.regexMatch = regexMatch;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -27,8 +37,13 @@ public class MatchBlockCondition<CTX extends Context> implements Condition<CTX>
|
||||
|
||||
@Override
|
||||
public boolean test(CTX ctx) {
|
||||
Optional<ExistingBlock> block = ctx.getOptionalParameter(DirectContextParameters.BLOCK);
|
||||
return block.filter(blockInWorld -> MiscUtils.matchRegex(blockInWorld.id().asString(), this.ids, this.regexMatch)).isPresent();
|
||||
Optional<WorldPosition> optionalWorldPosition = ctx.getOptionalParameter(DirectContextParameters.POSITION);
|
||||
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> {
|
||||
@@ -40,7 +55,10 @@ public class MatchBlockCondition<CTX extends Context> implements Condition<CTX>
|
||||
throw new LocalizedResourceConfigException("warning.config.condition.match_block.missing_id");
|
||||
}
|
||||
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>")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.util.Key;
|
||||
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.WorldPosition;
|
||||
|
||||
@@ -22,13 +23,15 @@ public class DropLootFunction<CTX extends Context> extends AbstractConditionalFu
|
||||
private final NumberProvider y;
|
||||
private final NumberProvider z;
|
||||
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);
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
this.lootTable = lootTable;
|
||||
this.toInv = toInv;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -39,8 +42,14 @@ public class DropLootFunction<CTX extends Context> extends AbstractConditionalFu
|
||||
WorldPosition position = new WorldPosition(world, x.getDouble(ctx), y.getDouble(ctx), z.getDouble(ctx));
|
||||
Player player = ctx.getOptionalParameter(DirectContextParameters.PLAYER).orElse(null);
|
||||
List<? extends Item<?>> items = lootTable.getRandomItems(ctx.contexts(), world, player);
|
||||
for (Item<?> item : items) {
|
||||
world.dropItemNaturally(position, item);
|
||||
if (this.toInv && player != null) {
|
||||
for (Item<?> item : items) {
|
||||
player.giveItem(item);
|
||||
}
|
||||
} else {
|
||||
for (Item<?> item : items) {
|
||||
world.dropItemNaturally(position, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -62,7 +71,8 @@ public class DropLootFunction<CTX extends Context> extends AbstractConditionalFu
|
||||
NumberProvider y = NumberProviders.fromObject(arguments.getOrDefault("y", "<arg:position.y>"));
|
||||
NumberProvider z = NumberProviders.fromObject(arguments.getOrDefault("z", "<arg:position.z>"));
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
package net.momirealms.craftengine.core.util;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public class MarkedHashMap<K, V> extends HashMap<K, V> {
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import com.google.gson.JsonObject;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Objects;
|
||||
|
||||
public class VersionHelper {
|
||||
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_9;
|
||||
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 {
|
||||
try (InputStream inputStream = Class.forName("net.minecraft.obfuscate.DontObfuscate").getResourceAsStream("/version.json")) {
|
||||
try (InputStream inputStream = UNOBFUSCATED_CLAZZ.getResourceAsStream("/version.json")) {
|
||||
if (inputStream == null) {
|
||||
throw new IOException("Failed to load version.json");
|
||||
}
|
||||
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);
|
||||
|
||||
String[] split = versionString.split("\\.");
|
||||
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
|
||||
// 12104 = 1.21.4
|
||||
|
||||
@@ -39,6 +39,14 @@ public interface World {
|
||||
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();
|
||||
|
||||
Path directory();
|
||||
|
||||
@@ -35,6 +35,7 @@ public class CEChunk {
|
||||
private final ReentrantReadWriteLock renderLock = new ReentrantReadWriteLock();
|
||||
private volatile boolean dirty;
|
||||
private volatile boolean loaded;
|
||||
private volatile boolean activated;
|
||||
|
||||
public CEChunk(CEWorld world, ChunkPos chunkPos) {
|
||||
this.world = world;
|
||||
@@ -115,40 +116,129 @@ public class CEChunk {
|
||||
}
|
||||
}
|
||||
|
||||
public void addConstantBlockEntityRenderer(BlockPos pos) {
|
||||
this.addConstantBlockEntityRenderer(pos, this.getBlockState(pos));
|
||||
public ConstantBlockEntityRenderer addConstantBlockEntityRenderer(BlockPos 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();
|
||||
if (renderers != null && renderers.length > 0) {
|
||||
BlockEntityElement[] elements = new BlockEntityElement[renderers.length];
|
||||
World wrappedWorld = this.world.world();
|
||||
for (int i = 0; i < elements.length; i++) {
|
||||
elements[i] = renderers[i].create(wrappedWorld, pos);
|
||||
}
|
||||
ConstantBlockEntityRenderer renderer = new ConstantBlockEntityRenderer(elements);
|
||||
for (Player player : getTrackedBy()) {
|
||||
renderer.show(player);
|
||||
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++) {
|
||||
elements[i] = renderers[i].create(wrappedWorld, pos);
|
||||
}
|
||||
if (hasTrackedBy) {
|
||||
for (Player player : trackedBy) {
|
||||
renderer.show(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
this.renderLock.writeLock().lock();
|
||||
this.constantBlockEntityRenderers.put(pos, renderer);
|
||||
return renderer;
|
||||
} finally {
|
||||
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 {
|
||||
this.renderLock.writeLock().lock();
|
||||
ConstantBlockEntityRenderer removed = this.constantBlockEntityRenderers.remove(pos);
|
||||
if (removed != null) {
|
||||
for (Player player : getTrackedBy()) {
|
||||
removed.hide(player);
|
||||
if (hide) {
|
||||
for (Player player : getTrackedBy()) {
|
||||
removed.hide(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
return removed;
|
||||
} finally {
|
||||
this.renderLock.writeLock().unlock();
|
||||
}
|
||||
@@ -183,7 +273,12 @@ public class CEChunk {
|
||||
this.removeDynamicBlockEntityRenderer(blockPos);
|
||||
}
|
||||
|
||||
public List<Player> getTrackedBy() {
|
||||
return this.world.world.getTrackedBy(this.chunkPos);
|
||||
}
|
||||
|
||||
public void activateAllBlockEntities() {
|
||||
if (this.activated) return;
|
||||
for (BlockEntity blockEntity : this.blockEntities.values()) {
|
||||
blockEntity.setValid(true);
|
||||
this.replaceOrCreateTickingBlockEntity(blockEntity);
|
||||
@@ -192,13 +287,11 @@ public class CEChunk {
|
||||
for (ConstantBlockEntityRenderer renderer : this.constantBlockEntityRenderers.values()) {
|
||||
renderer.activate();
|
||||
}
|
||||
}
|
||||
|
||||
public List<Player> getTrackedBy() {
|
||||
return this.world.world.getTrackedBy(this.chunkPos);
|
||||
this.activated = true;
|
||||
}
|
||||
|
||||
public void deactivateAllBlockEntities() {
|
||||
if (!this.activated) return;
|
||||
this.blockEntities.values().forEach(e -> e.setValid(false));
|
||||
this.constantBlockEntityRenderers.values().forEach(ConstantBlockEntityRenderer::deactivate);
|
||||
this.dynamicBlockEntityRenderers.clear();
|
||||
@@ -206,6 +299,7 @@ public class CEChunk {
|
||||
this.tickingSyncBlockEntitiesByPos.clear();
|
||||
this.tickingAsyncBlockEntitiesByPos.values().forEach((ticker) -> ticker.setTicker(DummyTickingBlockEntity.INSTANCE));
|
||||
this.tickingAsyncBlockEntitiesByPos.clear();
|
||||
this.activated = false;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -452,14 +546,12 @@ public class CEChunk {
|
||||
public void load() {
|
||||
if (this.loaded) return;
|
||||
this.world.addLoadedChunk(this);
|
||||
this.activateAllBlockEntities();
|
||||
this.loaded = true;
|
||||
}
|
||||
|
||||
public void unload() {
|
||||
if (!this.loaded) return;
|
||||
this.world.removeLoadedChunk(this);
|
||||
this.deactivateAllBlockEntities();
|
||||
this.loaded = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,11 @@ public class CachedStorage<T extends WorldDataStorage> implements WorldDataStora
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CEChunk readNewChunkAt(CEWorld world, ChunkPos pos) throws IOException {
|
||||
return this.storage.readNewChunkAt(world, pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull CEChunk readChunkAt(@NotNull CEWorld world, @NotNull ChunkPos pos) throws IOException {
|
||||
CEChunk chunk = this.chunkCache.getIfPresent(pos);
|
||||
@@ -42,6 +47,12 @@ public class CachedStorage<T extends WorldDataStorage> implements WorldDataStora
|
||||
this.storage.writeChunkAt(pos, chunk);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearChunkAt(@NotNull ChunkPos pos) throws IOException {
|
||||
this.storage.clearChunkAt(pos);
|
||||
this.chunkCache.invalidate(pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
this.storage.close();
|
||||
|
||||
@@ -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
|
||||
public @NotNull CEChunk readChunkAt(@NotNull CEWorld world, @NotNull ChunkPos pos) throws IOException {
|
||||
RegionFile regionFile = this.getRegionFile(pos, false, true);
|
||||
@@ -152,6 +165,11 @@ public class DefaultRegionFileStorage implements WorldDataStorage {
|
||||
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 {
|
||||
RegionFile regionFile = this.getRegionFile(pos, nbt == null, true);
|
||||
try {
|
||||
|
||||
@@ -9,11 +9,18 @@ import java.io.IOException;
|
||||
|
||||
public interface WorldDataStorage {
|
||||
|
||||
default CEChunk readNewChunkAt(CEWorld world, ChunkPos pos) throws IOException {
|
||||
this.clearChunkAt(pos);
|
||||
return this.readChunkAt(world, pos);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
CEChunk readChunkAt(@NotNull CEWorld world, @NotNull ChunkPos pos) throws IOException;
|
||||
|
||||
void writeChunkAt(@NotNull ChunkPos pos, @NotNull CEChunk chunk) throws IOException;
|
||||
|
||||
void clearChunkAt(@NotNull ChunkPos pos) throws IOException;
|
||||
|
||||
void flush() throws IOException;
|
||||
|
||||
void close() throws IOException;
|
||||
|
||||
@@ -2,9 +2,9 @@ org.gradle.jvmargs=-Xmx1G
|
||||
|
||||
# Project settings
|
||||
# Rule: [major update].[feature update].[bug fix]
|
||||
project_version=0.0.65
|
||||
config_version=52
|
||||
lang_version=36
|
||||
project_version=0.0.65.6
|
||||
config_version=53
|
||||
lang_version=37
|
||||
project_group=net.momirealms
|
||||
latest_supported_version=1.21.10
|
||||
|
||||
@@ -49,7 +49,7 @@ byte_buddy_version=1.17.8
|
||||
ahocorasick_version=0.6.3
|
||||
snake_yaml_version=2.5
|
||||
anti_grief_version=1.0.4
|
||||
nms_helper_version=1.0.123
|
||||
nms_helper_version=1.0.127
|
||||
evalex_version=3.5.0
|
||||
reactive_streams_version=1.0.4
|
||||
amazon_awssdk_version=2.34.5
|
||||
|
||||
1
wiki
Submodule
1
wiki
Submodule
Submodule wiki added at bec8bb7cf8
Reference in New Issue
Block a user