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

家具重构part1

This commit is contained in:
XiaoMoMi
2025-12-02 01:48:44 +08:00
parent f0f2181a18
commit d2b794c70d
125 changed files with 1827 additions and 1753 deletions

View File

@@ -8,9 +8,8 @@ import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
import net.momirealms.craftengine.bukkit.world.BukkitWorld; import net.momirealms.craftengine.bukkit.world.BukkitWorld;
import net.momirealms.craftengine.core.entity.furniture.AnchorType; import net.momirealms.craftengine.core.entity.furniture.AnchorType;
import net.momirealms.craftengine.core.entity.furniture.CustomFurniture;
import net.momirealms.craftengine.core.entity.furniture.Furniture; import net.momirealms.craftengine.core.entity.furniture.Furniture;
import net.momirealms.craftengine.core.entity.furniture.FurnitureExtraData; import net.momirealms.craftengine.core.entity.furniture.FurnitureConfig;
import net.momirealms.craftengine.core.entity.player.InteractionHand; import net.momirealms.craftengine.core.entity.player.InteractionHand;
import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.loot.LootTable; import net.momirealms.craftengine.core.loot.LootTable;
@@ -46,7 +45,7 @@ public final class CraftEngineFurniture {
* @return a non-null map containing all loaded custom furniture * @return a non-null map containing all loaded custom furniture
*/ */
@NotNull @NotNull
public static Map<Key, CustomFurniture> loadedFurniture() { public static Map<Key, FurnitureConfig> loadedFurniture() {
return BukkitFurnitureManager.instance().loadedFurniture(); return BukkitFurnitureManager.instance().loadedFurniture();
} }
@@ -56,7 +55,7 @@ public final class CraftEngineFurniture {
* @param id id * @param id id
* @return the custom furniture * @return the custom furniture
*/ */
public static CustomFurniture byId(@NotNull Key id) { public static FurnitureConfig byId(@NotNull Key id) {
return BukkitFurnitureManager.instance().furnitureById(id).orElse(null); return BukkitFurnitureManager.instance().furnitureById(id).orElse(null);
} }
@@ -69,9 +68,11 @@ public final class CraftEngineFurniture {
*/ */
@Nullable @Nullable
public static BukkitFurniture place(Location location, Key furnitureId) { public static BukkitFurniture place(Location location, Key furnitureId) {
CustomFurniture furniture = byId(furnitureId); FurnitureConfig furniture = byId(furnitureId);
if (furniture == null) return null; if (furniture == null) return null;
return place(location, furnitureId, furniture.getAnyAnchorType()); // fixme API
// return place(location, furnitureId, furniture.getAnyAnchorType());
return null;
} }
/** /**
@@ -79,14 +80,17 @@ public final class CraftEngineFurniture {
* *
* @param location location * @param location location
* @param furnitureId furniture to place * @param furnitureId furniture to place
* @param anchorType anchor type * @param anchorType anchor id
* @return the loaded furniture * @return the loaded furniture
*/ */
@Nullable @Nullable
@Deprecated(since = "0.0.66", forRemoval = true)
public static BukkitFurniture place(Location location, Key furnitureId, AnchorType anchorType) { public static BukkitFurniture place(Location location, Key furnitureId, AnchorType anchorType) {
CustomFurniture furniture = byId(furnitureId); FurnitureConfig furniture = byId(furnitureId);
if (furniture == null) return null; if (furniture == null) return null;
return BukkitFurnitureManager.instance().place(location, furniture, FurnitureExtraData.builder().anchorType(anchorType).build(), true); // fixme API
// return BukkitFurnitureManager.instance().place(location, furniture, FurnitureDataAccessor.builder().anchorType(anchorType).build(), true);
return null;
} }
/** /**
@@ -94,12 +98,15 @@ public final class CraftEngineFurniture {
* *
* @param location location * @param location location
* @param furniture furniture to place * @param furniture furniture to place
* @param anchorType anchor type * @param anchorType anchor id
* @return the loaded furniture * @return the loaded furniture
*/ */
@NotNull @NotNull
public static BukkitFurniture place(Location location, CustomFurniture furniture, AnchorType anchorType) { @Deprecated(since = "0.0.66", forRemoval = true)
return BukkitFurnitureManager.instance().place(location, furniture, FurnitureExtraData.builder().anchorType(anchorType).build(), true); public static BukkitFurniture place(Location location, FurnitureConfig furniture, AnchorType anchorType) {
// fixme API
// return BukkitFurnitureManager.instance().place(location, furniture, FurnitureDataAccessor.builder().anchorType(anchorType).build(), true);
return null;
} }
/** /**
@@ -107,15 +114,18 @@ public final class CraftEngineFurniture {
* *
* @param location location * @param location location
* @param furnitureId furniture to place * @param furnitureId furniture to place
* @param anchorType anchor type * @param anchorType anchor id
* @param playSound whether to play place sounds * @param playSound whether to play place sounds
* @return the loaded furniture * @return the loaded furniture
*/ */
@Nullable @Nullable
@Deprecated(since = "0.0.66", forRemoval = true)
public static BukkitFurniture place(Location location, Key furnitureId, AnchorType anchorType, boolean playSound) { public static BukkitFurniture place(Location location, Key furnitureId, AnchorType anchorType, boolean playSound) {
CustomFurniture furniture = byId(furnitureId); FurnitureConfig furniture = byId(furnitureId);
if (furniture == null) return null; if (furniture == null) return null;
return BukkitFurnitureManager.instance().place(location, furniture, FurnitureExtraData.builder().anchorType(anchorType).build(), playSound); // fixme API
// return BukkitFurnitureManager.instance().place(location, furniture, FurnitureDataAccessor.builder().anchorType(anchorType).build(), playSound);
return null;
} }
/** /**
@@ -123,13 +133,16 @@ public final class CraftEngineFurniture {
* *
* @param location location * @param location location
* @param furniture furniture to place * @param furniture furniture to place
* @param anchorType anchor type * @param anchorType anchor id
* @param playSound whether to play place sounds * @param playSound whether to play place sounds
* @return the loaded furniture * @return the loaded furniture
*/ */
@NotNull @NotNull
public static BukkitFurniture place(Location location, CustomFurniture furniture, AnchorType anchorType, boolean playSound) { @Deprecated(since = "0.0.66", forRemoval = true)
return BukkitFurnitureManager.instance().place(location, furniture, FurnitureExtraData.builder().anchorType(anchorType).build(), playSound); public static BukkitFurniture place(Location location, FurnitureConfig furniture, AnchorType anchorType, boolean playSound) {
// fixme API
// return BukkitFurnitureManager.instance().place(location, furniture, FurnitureDataAccessor.builder().anchorType(anchorType).build(), playSound);
return null;
} }
/** /**
@@ -286,7 +299,7 @@ public final class CraftEngineFurniture {
boolean dropLoot, boolean dropLoot,
boolean playSound) { boolean playSound) {
if (!furniture.isValid()) return; if (!furniture.isValid()) return;
Location location = ((BukkitFurniture) furniture).dropLocation(); Location location = ((BukkitFurniture) furniture).getDropLocation();
furniture.destroy(); furniture.destroy();
LootTable<ItemStack> lootTable = (LootTable<ItemStack>) furniture.config().lootTable(); LootTable<ItemStack> lootTable = (LootTable<ItemStack>) furniture.config().lootTable();
World world = new BukkitWorld(location.getWorld()); World world = new BukkitWorld(location.getWorld());
@@ -295,7 +308,7 @@ public final class CraftEngineFurniture {
ContextHolder.Builder builder = ContextHolder.builder() ContextHolder.Builder builder = ContextHolder.builder()
.withParameter(DirectContextParameters.POSITION, position) .withParameter(DirectContextParameters.POSITION, position)
.withParameter(DirectContextParameters.FURNITURE, furniture) .withParameter(DirectContextParameters.FURNITURE, furniture)
.withOptionalParameter(DirectContextParameters.FURNITURE_ITEM, furniture.extraData().item().orElse(null)); .withOptionalParameter(DirectContextParameters.FURNITURE_ITEM, furniture.dataAccessor().item().orElse(null));
if (player != null) { if (player != null) {
Item<?> itemInHand = player.getItemInHand(InteractionHand.MAIN_HAND); Item<?> itemInHand = player.getItemInHand(InteractionHand.MAIN_HAND);
builder.withParameter(DirectContextParameters.PLAYER, player) builder.withParameter(DirectContextParameters.PLAYER, player)

View File

@@ -49,7 +49,7 @@ public final class AsyncResourcePackCacheEvent extends Event {
* Adds an external resource pack to the cache. * Adds an external resource pack to the cache.
* <p> * <p>
* This method accepts either a .zip file or a directory path representing a resource pack. * This method accepts either a .zip file or a directory path representing a resource pack.
* The resource pack will be added to the appropriate cache collection based on its type. * The resource pack will be added to the appropriate cache collection based on its id.
* </p> * </p>
* *
* @param path the file system path to the resource pack. Must be either a .zip file or a directory. * @param path the file system path to the resource pack. Must be either a .zip file or a directory.

View File

@@ -1,7 +1,7 @@
package net.momirealms.craftengine.bukkit.api.event; package net.momirealms.craftengine.bukkit.api.event;
import net.momirealms.craftengine.core.entity.furniture.AnchorType; import net.momirealms.craftengine.core.entity.furniture.AnchorType;
import net.momirealms.craftengine.core.entity.furniture.CustomFurniture; import net.momirealms.craftengine.core.entity.furniture.FurnitureConfig;
import net.momirealms.craftengine.core.entity.player.InteractionHand; import net.momirealms.craftengine.core.entity.player.InteractionHand;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.block.Block; import org.bukkit.block.Block;
@@ -15,7 +15,7 @@ import org.jetbrains.annotations.NotNull;
public final class FurnitureAttemptPlaceEvent extends PlayerEvent implements Cancellable { public final class FurnitureAttemptPlaceEvent extends PlayerEvent implements Cancellable {
private static final HandlerList HANDLER_LIST = new HandlerList(); private static final HandlerList HANDLER_LIST = new HandlerList();
private boolean cancelled; private boolean cancelled;
private final CustomFurniture furniture; private final FurnitureConfig furniture;
private final Location location; private final Location location;
private final AnchorType anchorType; private final AnchorType anchorType;
private final BlockFace clickedFace; private final BlockFace clickedFace;
@@ -23,7 +23,7 @@ public final class FurnitureAttemptPlaceEvent extends PlayerEvent implements Can
private final InteractionHand hand; private final InteractionHand hand;
public FurnitureAttemptPlaceEvent(@NotNull Player player, public FurnitureAttemptPlaceEvent(@NotNull Player player,
@NotNull CustomFurniture furniture, @NotNull FurnitureConfig furniture,
@NotNull AnchorType anchorType, @NotNull AnchorType anchorType,
@NotNull Location location, @NotNull Location location,
@NotNull BlockFace clickedFace, @NotNull BlockFace clickedFace,
@@ -69,7 +69,7 @@ public final class FurnitureAttemptPlaceEvent extends PlayerEvent implements Can
} }
@NotNull @NotNull
public CustomFurniture furniture() { public FurnitureConfig furniture() {
return furniture; return furniture;
} }

View File

@@ -1,7 +1,7 @@
package net.momirealms.craftengine.bukkit.api.event; package net.momirealms.craftengine.bukkit.api.event;
import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurniture; import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurniture;
import net.momirealms.craftengine.core.entity.furniture.HitBox; import net.momirealms.craftengine.core.entity.furniture.hitbox.HitBox;
import net.momirealms.craftengine.core.entity.player.InteractionHand; import net.momirealms.craftengine.core.entity.player.InteractionHand;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;

View File

@@ -45,7 +45,7 @@ public class NearLiquidBlockBehavior extends AbstractCanSurviveBlockBehavior {
public static class Factory implements BlockBehaviorFactory { public static class Factory implements BlockBehaviorFactory {
@Override @Override
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) { public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
List<String> liquidTypes = MiscUtils.getAsStringList(arguments.getOrDefault("liquid-type", List.of("water"))); List<String> liquidTypes = MiscUtils.getAsStringList(arguments.getOrDefault("liquid-id", List.of("water")));
boolean stackable = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("stackable", false), "stackable"); boolean stackable = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("stackable", false), "stackable");
int delay = ResourceConfigUtils.getAsInt(arguments.getOrDefault("delay", 0), "delay"); int delay = ResourceConfigUtils.getAsInt(arguments.getOrDefault("delay", 0), "delay");
List<String> positionsToCheck = MiscUtils.getAsStringList(arguments.getOrDefault("positions", List.of())); List<String> positionsToCheck = MiscUtils.getAsStringList(arguments.getOrDefault("positions", List.of()));

View File

@@ -40,7 +40,7 @@ public class OnLiquidBlockBehavior extends AbstractCanSurviveBlockBehavior {
public static class Factory implements BlockBehaviorFactory { public static class Factory implements BlockBehaviorFactory {
@Override @Override
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) { public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
List<String> liquidTypes = MiscUtils.getAsStringList(arguments.getOrDefault("liquid-type", List.of("water"))); List<String> liquidTypes = MiscUtils.getAsStringList(arguments.getOrDefault("liquid-id", List.of("water")));
boolean stackable = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("stackable", false), "stackable"); boolean stackable = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("stackable", false), "stackable");
int delay = ResourceConfigUtils.getAsInt(arguments.getOrDefault("delay", 0), "delay"); int delay = ResourceConfigUtils.getAsInt(arguments.getOrDefault("delay", 0), "delay");
return new OnLiquidBlockBehavior(block, delay, stackable, liquidTypes.contains("water"), liquidTypes.contains("lava")); return new OnLiquidBlockBehavior(block, delay, stackable, liquidTypes.contains("water"), liquidTypes.contains("lava"));

View File

@@ -6,8 +6,8 @@ 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.BlockEntityElement;
import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElementConfig; 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.block.entity.render.element.BlockEntityElementConfigFactory;
import net.momirealms.craftengine.core.entity.Billboard; import net.momirealms.craftengine.core.entity.display.Billboard;
import net.momirealms.craftengine.core.entity.ItemDisplayContext; import net.momirealms.craftengine.core.entity.display.ItemDisplayContext;
import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.Key;
@@ -19,7 +19,6 @@ import org.joml.Vector3f;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.function.Function; import java.util.function.Function;
@@ -173,8 +172,8 @@ public class ItemDisplayBlockEntityElementConfig implements BlockEntityElementCo
ResourceConfigUtils.getAsFloat(arguments.getOrDefault("pitch", 0f), "pitch"), ResourceConfigUtils.getAsFloat(arguments.getOrDefault("pitch", 0f), "pitch"),
ResourceConfigUtils.getAsFloat(arguments.getOrDefault("yaw", 0f), "yaw"), ResourceConfigUtils.getAsFloat(arguments.getOrDefault("yaw", 0f), "yaw"),
ResourceConfigUtils.getAsQuaternionf(arguments.getOrDefault("rotation", 0f), "rotation"), ResourceConfigUtils.getAsQuaternionf(arguments.getOrDefault("rotation", 0f), "rotation"),
ItemDisplayContext.valueOf(arguments.getOrDefault("display-context", "none").toString().toUpperCase(Locale.ROOT)), ResourceConfigUtils.getAsEnum(ResourceConfigUtils.get(arguments, "display-context", "display-transform"), ItemDisplayContext.class, ItemDisplayContext.NONE),
Billboard.valueOf(arguments.getOrDefault("billboard", "fixed").toString().toUpperCase(Locale.ROOT)), ResourceConfigUtils.getAsEnum(arguments.get("billboard"), Billboard.class, Billboard.FIXED),
ResourceConfigUtils.getAsFloat(arguments.getOrDefault("shadow-radius", 0f), "shadow-radius"), ResourceConfigUtils.getAsFloat(arguments.getOrDefault("shadow-radius", 0f), "shadow-radius"),
ResourceConfigUtils.getAsFloat(arguments.getOrDefault("shadow-strength", 1f), "shadow-strength") ResourceConfigUtils.getAsFloat(arguments.getOrDefault("shadow-strength", 1f), "shadow-strength")
); );

View File

@@ -7,7 +7,7 @@ import net.momirealms.craftengine.bukkit.util.ComponentUtils;
import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElement; import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElement;
import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElementConfig; 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.block.entity.render.element.BlockEntityElementConfigFactory;
import net.momirealms.craftengine.core.entity.Billboard; import net.momirealms.craftengine.core.entity.display.Billboard;
import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext;
import net.momirealms.craftengine.core.util.AdventureHelper; import net.momirealms.craftengine.core.util.AdventureHelper;

View File

@@ -1,7 +1,7 @@
package net.momirealms.craftengine.bukkit.entity; package net.momirealms.craftengine.bukkit.entity;
import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
import net.momirealms.craftengine.core.entity.ItemEntity; import net.momirealms.craftengine.core.entity.item.ItemEntity;
import org.bukkit.entity.Item; import org.bukkit.entity.Item;
public class BukkitItemEntity extends BukkitEntity implements ItemEntity { public class BukkitItemEntity extends BukkitEntity implements ItemEntity {

View File

@@ -6,7 +6,7 @@ public class ItemDisplayEntityData<T> extends DisplayEntityData<T> {
// Item display only // Item display only
public static final ItemDisplayEntityData<Object> DisplayedItem = new ItemDisplayEntityData<>(ItemDisplayEntityData.class, EntityDataValue.Serializers$ITEM_STACK, CoreReflections.instance$ItemStack$EMPTY); public static final ItemDisplayEntityData<Object> DisplayedItem = new ItemDisplayEntityData<>(ItemDisplayEntityData.class, EntityDataValue.Serializers$ITEM_STACK, CoreReflections.instance$ItemStack$EMPTY);
/** /**
* Display type: * Display id:
* 0 = NONE * 0 = NONE
* 1 = THIRD_PERSON_LEFT_HAND * 1 = THIRD_PERSON_LEFT_HAND
* 2 = THIRD_PERSON_RIGHT_HAND * 2 = THIRD_PERSON_RIGHT_HAND

View File

@@ -1,74 +0,0 @@
package net.momirealms.craftengine.bukkit.entity.furniture;
import net.momirealms.craftengine.core.entity.furniture.AbstractCustomFurniture;
import net.momirealms.craftengine.core.entity.furniture.AnchorType;
import net.momirealms.craftengine.core.entity.furniture.CustomFurniture;
import net.momirealms.craftengine.core.entity.furniture.FurnitureSettings;
import net.momirealms.craftengine.core.loot.LootTable;
import net.momirealms.craftengine.core.plugin.context.Context;
import net.momirealms.craftengine.core.plugin.context.event.EventTrigger;
import net.momirealms.craftengine.core.plugin.context.function.Function;
import net.momirealms.craftengine.core.util.Key;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Map;
public class BukkitCustomFurniture extends AbstractCustomFurniture {
protected BukkitCustomFurniture(@NotNull Key id,
@NotNull FurnitureSettings settings,
@NotNull Map<AnchorType, Placement> placements,
@NotNull Map<EventTrigger, List<Function<Context>>> events,
@Nullable LootTable<?> lootTable) {
super(id, settings, placements, events, lootTable);
}
public static Builder builder() {
return new BuilderImpl();
}
public static class BuilderImpl implements Builder {
private Key id;
private Map<AnchorType, Placement> placements;
private FurnitureSettings settings;
private Map<EventTrigger, List<Function<Context>>> events;
private LootTable<?> lootTable;
@Override
public CustomFurniture build() {
return new BukkitCustomFurniture(id, settings, placements, events, lootTable);
}
@Override
public Builder id(Key id) {
this.id = id;
return this;
}
@Override
public Builder placement(Map<AnchorType, Placement> placements) {
this.placements = placements;
return this;
}
@Override
public Builder settings(FurnitureSettings settings) {
this.settings = settings;
return this;
}
@Override
public Builder lootTable(LootTable<?> lootTable) {
this.lootTable = lootTable;
return this;
}
@Override
public Builder events(Map<EventTrigger, List<Function<Context>>> events) {
this.events = events;
return this;
}
}
}

View File

@@ -1,184 +1,166 @@
package net.momirealms.craftengine.bukkit.entity.furniture; package net.momirealms.craftengine.bukkit.entity.furniture;
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import net.momirealms.craftengine.bukkit.entity.BukkitEntity;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
import net.momirealms.craftengine.bukkit.util.LocationUtils; import net.momirealms.craftengine.bukkit.util.LocationUtils;
import net.momirealms.craftengine.core.entity.furniture.*; import net.momirealms.craftengine.core.entity.furniture.Furniture;
import net.momirealms.craftengine.core.entity.seat.Seat; import net.momirealms.craftengine.core.entity.furniture.FurnitureConfig;
import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.entity.furniture.FurnitureDataAccessor;
import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.entity.furniture.FurnitureVariant;
import net.momirealms.craftengine.core.entity.furniture.element.FurnitureElement;
import net.momirealms.craftengine.core.entity.furniture.element.FurnitureElementConfig;
import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.plugin.entityculling.CullingData;
import net.momirealms.craftengine.core.util.QuaternionUtils; import net.momirealms.craftengine.core.util.QuaternionUtils;
import net.momirealms.craftengine.core.world.WorldPosition; import net.momirealms.craftengine.core.world.WorldPosition;
import net.momirealms.sparrow.nbt.CompoundTag;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.persistence.PersistentDataType;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.joml.Quaternionf; import org.joml.Quaternionf;
import org.joml.Vector3f; import org.joml.Vector3f;
import java.io.IOException;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.*; import java.util.Optional;
import java.util.UUID;
public class BukkitFurniture implements Furniture { public class BukkitFurniture implements Furniture {
private final CustomFurniture furniture; private static final UUID INVALID_UUID = new UUID(0, 0);
private final CustomFurniture.Placement placement; @NotNull
private FurnitureExtraData extraData; private final FurnitureConfig config;
// location @NotNull
private final Location location; private final FurnitureDataAccessor dataAccessor;
// base entity
private final WeakReference<Entity> baseEntity;
private final int baseEntityId;
// colliders
private final Collider[] colliderEntities;
// cache
private final List<Integer> fakeEntityIds;
private final List<Integer> entityIds;
private final Map<Integer, BukkitHitBox> hitBoxes = new Int2ObjectArrayMap<>();
private final Map<Integer, HitBoxPart> hitBoxParts = new Int2ObjectArrayMap<>();
private final boolean minimized;
private final boolean hasExternalModel;
// cached spawn packet
private Object cachedSpawnPacket;
private Object cachedMinimizedSpawnPacket;
public BukkitFurniture(Entity baseEntity, private WeakReference<Entity> baseEntity;
CustomFurniture furniture, private FurnitureVariant currentVariant;
FurnitureExtraData extraData) { private Location location;
this.extraData = extraData; private boolean valid;
this.baseEntityId = baseEntity.getEntityId(); private UUID uuid;
this.location = baseEntity.getLocation(); private int entityId;
this.baseEntity = new WeakReference<>(baseEntity);
this.furniture = furniture;
this.minimized = furniture.settings().minimized();
this.placement = furniture.getValidPlacement(extraData.anchorType().orElseGet(furniture::getAnyAnchorType));
List<Integer> fakeEntityIds = new IntArrayList(); private FurnitureElement[] elements;
List<Integer> mainEntityIds = new IntArrayList();
mainEntityIds.add(this.baseEntityId);
// 绑定外部模型 public BukkitFurniture(@NotNull FurnitureConfig config,
Optional<ExternalModel> optionalExternal = placement.externalModel(); @NotNull CompoundTag data) {
if (optionalExternal.isPresent()) { this.dataAccessor = FurnitureDataAccessor.of(data);
try { this.currentVariant = Optional.ofNullable(getVariant()).orElseGet(config::anyVariant);
optionalExternal.get().bindModel(new BukkitEntity(baseEntity)); this.config = config;
} catch (Exception e) { this.baseEntity = new WeakReference<>(null);
CraftEngine.instance().logger().warn("Failed to load external model for furniture " + id(), e); this.valid = false;
} this.entityId = -1;
this.hasExternalModel = true; this.uuid = INVALID_UUID;
} else { }
this.hasExternalModel = false;
}
Quaternionf conjugated = QuaternionUtils.toQuaternionf(0, Math.toRadians(180 - this.location.getYaw()), 0).conjugate(); private void sync() {
List<Object> packets = new ArrayList<>();
List<Object> minimizedPackets = new ArrayList<>();
List<Collider> colliders = new ArrayList<>(4);
WorldPosition position = position(); WorldPosition position = position();
FurnitureElementConfig<?>[] elementConfigs = this.currentVariant.elements();
FurnitureElement[] elements = new FurnitureElement[elementConfigs.length];
// 初始化家具的元素 for (int i = 0; i < elementConfigs.length; i++) {
for (FurnitureElement element : placement.elements()) { FurnitureElement o = elementConfigs[i].create(position);
int entityId = CoreReflections.instance$Entity$ENTITY_COUNTER.incrementAndGet(); elements[i] = o;
fakeEntityIds.add(entityId);
element.initPackets(this, entityId, conjugated, packet -> {
packets.add(packet);
if (this.minimized) minimizedPackets.add(packet);
});
} }
this.elements = elements;
}
// 初始化碰撞箱 public void addToWorld(Location location) {
for (HitBoxConfig hitBoxConfig : this.placement.hitBoxConfigs()) { this.setLocation(location);
int[] ids = hitBoxConfig.acquireEntityIds(CoreReflections.instance$Entity$ENTITY_COUNTER::incrementAndGet); this.valid = true;
List<HitBoxPart> aabbs = new ArrayList<>(); Entity baseEntity = null; // fixme 处理生成
this.baseEntity = new WeakReference<>(baseEntity);
hitBoxConfig.initPacketsAndColliders(ids, position, conjugated, (packet, canBeMinimized) -> { this.uuid = baseEntity.getUniqueId();
packets.add(packet); this.entityId = baseEntity.getEntityId();
if (this.minimized && !canBeMinimized) { this.sync();
minimizedPackets.add(packet);
}
}, colliders::add, part -> {
this.hitBoxParts.put(part.entityId(), part);
aabbs.add(part);
});
BukkitHitBox hitBox = new BukkitHitBox(this, hitBoxConfig, aabbs.toArray(new HitBoxPart[0]));
for (int entityId : ids) {
fakeEntityIds.add(entityId);
mainEntityIds.add(entityId);
this.hitBoxes.put(entityId, hitBox);
}
}
// 初始化缓存的家具包
try {
this.cachedSpawnPacket = FastNMS.INSTANCE.constructor$ClientboundBundlePacket(packets);
if (this.minimized) {
this.cachedMinimizedSpawnPacket = FastNMS.INSTANCE.constructor$ClientboundBundlePacket(minimizedPackets);
}
} catch (Exception e) {
CraftEngine.instance().logger().warn("Failed to init spawn packets for furniture " + id(), e);
}
this.fakeEntityIds = fakeEntityIds;
this.entityIds = mainEntityIds;
this.colliderEntities = colliders.toArray(new Collider[0]);
} }
@Override @Override
public void initializeColliders() { public void show(Player player) {
Object world = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(this.location.getWorld()); for (FurnitureElement element : this.elements) {
for (Collider entity : this.colliderEntities) { element.show(player);
FastNMS.INSTANCE.method$LevelWriter$addFreshEntity(world, entity.handle());
Entity bukkitEntity = FastNMS.INSTANCE.method$Entity$getBukkitEntity(entity.handle());
bukkitEntity.getPersistentDataContainer().set(BukkitFurnitureManager.FURNITURE_COLLISION, PersistentDataType.BYTE, (byte) 1);
} }
} }
@NotNull @Override
public Object spawnPacket(Player player) { public void hide(Player player) {
// TODO hasPermission might be slow, can we use a faster way in the future? for (FurnitureElement element : this.elements) {
// TODO Make it based on conditions. So we can dynamically control which furniture should be sent to the player element.hide(player);
if (!this.minimized || player.hasPermission(FurnitureManager.FURNITURE_ADMIN_NODE)) {
return this.cachedSpawnPacket;
} else {
return this.cachedMinimizedSpawnPacket;
} }
} }
@Nullable
@Override
public CullingData cullingData() {
return this.config.cullingData();
}
@NotNull
@Override
public FurnitureConfig config() {
return this.config;
}
@NotNull
@Override
public FurnitureDataAccessor dataAccessor() {
return this.dataAccessor;
}
@Override @Override
public WorldPosition position() { public WorldPosition position() {
return LocationUtils.toWorldPosition(this.location); return LocationUtils.toWorldPosition(this.location);
} }
@NotNull @Override
public Location location() { public boolean isValid() {
return this.location.clone(); return this.valid;
}
@NotNull
public Entity baseEntity() {
Entity entity = this.baseEntity.get();
if (entity == null) {
throw new RuntimeException("Base entity not found. It might be unloaded.");
}
return entity;
} }
@Override @Override
public boolean isValid() { public void destroy() {
return baseEntity().isValid(); this.valid = false;
Optional.ofNullable(this.baseEntity.get()).ifPresent(Entity::remove);
} }
@NotNull @Override
public Location dropLocation() { public UUID uuid() {
Optional<Vector3f> dropOffset = this.placement.dropOffset(); return this.uuid;
}
@Override
public int entityId() {
return this.entityId;
}
public void teleport(WorldPosition position) {
Location newLocation = LocationUtils.toLocation(position);
if (newLocation.equals(this.location)) {
return;
}
this.setLocation(newLocation);
this.sync();
}
public Location location() {
return location;
}
private void setLocation(Location location) {
this.location = location;
}
public FurnitureVariant getVariant() {
return this.config.getVariant(this.dataAccessor.variant().orElseGet(this.config::anyVariantName));
}
public void setVariant(String variant) {
FurnitureVariant newVariant = this.config.getVariant(variant);
if (newVariant != this.currentVariant) {
this.currentVariant = newVariant;
this.sync();
}
}
// 获取掉落物的位置,受到家具变种的影响
public Location getDropLocation() {
Optional<Vector3f> dropOffset = this.getVariant().dropOffset();
if (dropOffset.isEmpty()) { if (dropOffset.isEmpty()) {
return location(); return location();
} }
@@ -186,105 +168,4 @@ public class BukkitFurniture implements Furniture {
Vector3f offset = conjugated.transform(new Vector3f(dropOffset.get())); Vector3f offset = conjugated.transform(new Vector3f(dropOffset.get()));
return new Location(this.location.getWorld(), this.location.getX() + offset.x, this.location.getY() + offset.y, this.location.getZ() - offset.z); return new Location(this.location.getWorld(), this.location.getX() + offset.x, this.location.getY() + offset.y, this.location.getZ() - offset.z);
} }
@Override
public void destroy() {
if (!isValid()) {
return;
}
this.baseEntity().remove();
this.destroyColliders();
this.destroySeats();
}
@Override
public void destroyColliders() {
for (Collider entity : this.colliderEntities) {
if (entity != null)
entity.destroy();
}
}
@Override
public void destroySeats() {
for (HitBox hitBox : this.hitBoxes.values()) {
for (Seat<HitBox> seat : hitBox.seats()) {
seat.destroy();
}
}
}
@Override
public UUID uuid() {
return this.baseEntity().getUniqueId();
}
@Override
public int baseEntityId() {
return this.baseEntityId;
}
@NotNull
public List<Integer> entityIds() {
return Collections.unmodifiableList(this.entityIds);
}
@NotNull
public List<Integer> fakeEntityIds() {
return Collections.unmodifiableList(this.fakeEntityIds);
}
public Collider[] collisionEntities() {
return this.colliderEntities;
}
@Override
public @Nullable HitBox hitBoxByEntityId(int id) {
return this.hitBoxes.get(id);
}
@Override
public @Nullable HitBoxPart hitBoxPartByEntityId(int id) {
return this.hitBoxParts.get(id);
}
@Override
public @NotNull AnchorType anchorType() {
return this.placement.anchorType();
}
@Override
public @NotNull Key id() {
return this.furniture.id();
}
@Override
public @NotNull CustomFurniture config() {
return this.furniture;
}
@Override
public boolean hasExternalModel() {
return hasExternalModel;
}
@Override
public FurnitureExtraData extraData() {
return this.extraData;
}
@Override
public void setExtraData(FurnitureExtraData extraData) {
this.extraData = extraData;
this.save();
}
@Override
public void save() {
try {
this.baseEntity().getPersistentDataContainer().set(BukkitFurnitureManager.FURNITURE_EXTRA_DATA_KEY, PersistentDataType.BYTE_ARRAY, this.extraData.toBytes());
} catch (IOException e) {
CraftEngine.instance().logger().warn("Failed to save furniture data.", e);
}
}
} }

View File

@@ -1,177 +0,0 @@
package net.momirealms.craftengine.bukkit.entity.furniture;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import net.momirealms.craftengine.bukkit.entity.data.ItemDisplayEntityData;
import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
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.entity.Billboard;
import net.momirealms.craftengine.core.entity.ItemDisplayContext;
import net.momirealms.craftengine.core.entity.furniture.AbstractFurnitureElement;
import net.momirealms.craftengine.core.entity.furniture.Furniture;
import net.momirealms.craftengine.core.entity.furniture.FurnitureElement;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.item.data.FireworkExplosion;
import net.momirealms.craftengine.core.util.Color;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.world.WorldPosition;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.joml.Quaternionf;
import org.joml.Vector3f;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.function.Consumer;
public class BukkitFurnitureElement extends AbstractFurnitureElement {
private final List<Object> commonValues;
public BukkitFurnitureElement(Key item,
Billboard billboard,
ItemDisplayContext transform,
Vector3f scale,
Vector3f translation,
Vector3f position,
Quaternionf rotation,
float shadowRadius,
float shadowStrength,
boolean applyDyedColor) {
super(item, billboard, transform, scale, translation, position, rotation, shadowRadius, shadowStrength, applyDyedColor);
this.commonValues = new ArrayList<>();
ItemDisplayEntityData.Scale.addEntityDataIfNotDefaultValue(scale(), this.commonValues);
ItemDisplayEntityData.RotationLeft.addEntityDataIfNotDefaultValue(rotation(), this.commonValues);
ItemDisplayEntityData.BillboardConstraints.addEntityDataIfNotDefaultValue(billboard().id(), this.commonValues);
ItemDisplayEntityData.Translation.addEntityDataIfNotDefaultValue(translation(), this.commonValues);
ItemDisplayEntityData.DisplayType.addEntityDataIfNotDefaultValue(transform().id(), this.commonValues);
ItemDisplayEntityData.ShadowRadius.addEntityDataIfNotDefaultValue(shadowRadius, this.commonValues);
ItemDisplayEntityData.ShadowStrength.addEntityDataIfNotDefaultValue(shadowStrength, this.commonValues);
}
@Override
public void initPackets(Furniture furniture, int entityId, @NotNull Quaternionf conjugated, Consumer<Object> packets) {
WorldPosition position = furniture.position();
Vector3f offset = conjugated.transform(new Vector3f(position()));
packets.accept(FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket(
entityId, UUID.randomUUID(), position.x() + offset.x, position.y() + offset.y, position.z() - offset.z, 0, position.yRot(),
MEntityTypes.ITEM_DISPLAY, 0, CoreReflections.instance$Vec3$Zero, 0
));
if (applyDyedColor()) {
packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId, getCachedValues(
furniture.extraData().dyedColor().orElse(null),
furniture.extraData().fireworkExplosionColors().orElse(null)
)));
} else {
packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId, getCachedValues(null, null)));
}
}
private synchronized List<Object> getCachedValues(@Nullable Color color, int @Nullable [] colors) {
List<Object> cachedValues = new ArrayList<>(this.commonValues);
Item<ItemStack> item = BukkitItemManager.instance().createWrappedItem(item(), null);
if (item == null) {
item = BukkitItemManager.instance().wrap(new ItemStack(Material.BARRIER));
} else {
if (color != null) {
item.dyedColor(color);
}
if (colors != null) {
item.fireworkExplosion(new FireworkExplosion(
FireworkExplosion.Shape.SMALL_BALL,
new IntArrayList(colors),
new IntArrayList(),
false,
false
));
}
}
ItemDisplayEntityData.DisplayedItem.addEntityDataIfNotDefaultValue(item.getLiteralObject(), cachedValues);
return cachedValues;
}
public static Builder builder() {
return new BuilderImpl();
}
public static class BuilderImpl implements Builder {
private boolean applyDyedColor;
private Key item;
private Billboard billboard;
private ItemDisplayContext transform;
private Vector3f scale;
private Vector3f translation;
private Vector3f position;
private Quaternionf rotation;
private float shadowRadius;
private float shadowStrength;
@Override
public Builder applyDyedColor(boolean applyDyedColor) {
this.applyDyedColor = applyDyedColor;
return this;
}
@Override
public Builder item(Key item) {
this.item = item;
return this;
}
@Override
public Builder billboard(Billboard billboard) {
this.billboard = billboard;
return this;
}
@Override
public Builder transform(ItemDisplayContext transform) {
this.transform = transform;
return this;
}
@Override
public Builder scale(Vector3f scale) {
this.scale = scale;
return this;
}
@Override
public Builder translation(Vector3f translation) {
this.translation = translation;
return this;
}
@Override
public Builder position(Vector3f position) {
this.position = position;
return this;
}
@Override
public Builder rotation(Quaternionf rotation) {
this.rotation = rotation;
return this;
}
@Override
public Builder shadowStrength(float shadowStrength) {
this.shadowStrength = shadowStrength;
return this;
}
@Override
public Builder shadowRadius(float shadowRadius) {
this.shadowRadius = shadowRadius;
return this;
}
@Override
public FurnitureElement build() {
return new BukkitFurnitureElement(item, billboard, transform, scale, translation, position, rotation, shadowRadius, shadowStrength, applyDyedColor);
}
}
}

View File

@@ -1,34 +1,23 @@
package net.momirealms.craftengine.bukkit.entity.furniture; package net.momirealms.craftengine.bukkit.entity.furniture;
import net.momirealms.craftengine.bukkit.api.BukkitAdaptors;
import net.momirealms.craftengine.bukkit.entity.furniture.hitbox.InteractionHitBoxConfig; import net.momirealms.craftengine.bukkit.entity.furniture.hitbox.InteractionHitBoxConfig;
import net.momirealms.craftengine.bukkit.nms.CollisionEntity;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
import net.momirealms.craftengine.bukkit.plugin.network.handler.FurniturePacketHandler;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MEntityTypes; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MEntityTypes;
import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer;
import net.momirealms.craftengine.bukkit.util.EntityUtils;
import net.momirealms.craftengine.bukkit.util.KeyUtils; import net.momirealms.craftengine.bukkit.util.KeyUtils;
import net.momirealms.craftengine.bukkit.util.LocationUtils;
import net.momirealms.craftengine.core.entity.furniture.*; import net.momirealms.craftengine.core.entity.furniture.*;
import net.momirealms.craftengine.core.entity.furniture.hitbox.HitBoxConfig;
import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.config.Config;
import net.momirealms.craftengine.core.sound.SoundData;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.VersionHelper;
import net.momirealms.craftengine.core.world.WorldPosition; import net.momirealms.craftengine.core.world.WorldPosition;
import org.bukkit.*; import org.bukkit.Bukkit;
import org.bukkit.entity.*; import org.bukkit.Location;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.Boat;
import org.bukkit.entity.Interaction;
import org.bukkit.event.HandlerList; import org.bukkit.event.HandlerList;
import org.bukkit.persistence.PersistentDataType;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiConsumer;
public class BukkitFurnitureManager extends AbstractFurnitureManager { public class BukkitFurnitureManager extends AbstractFurnitureManager {
public static final NamespacedKey FURNITURE_KEY = KeyUtils.toNamespacedKey(FurnitureManager.FURNITURE_KEY); public static final NamespacedKey FURNITURE_KEY = KeyUtils.toNamespacedKey(FurnitureManager.FURNITURE_KEY);
@@ -56,30 +45,32 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
} }
@Override @Override
public Furniture place(WorldPosition position, CustomFurniture furniture, FurnitureExtraData extraData, boolean playSound) { public Furniture place(WorldPosition position, FurnitureConfig furniture, FurnitureDataAccessor dataAccessor, boolean playSound) {
return this.place(LocationUtils.toLocation(position), furniture, extraData, playSound); // return this.place(LocationUtils.toLocation(position), furniture, dataAccessor, playSound);
return null;
} }
public BukkitFurniture place(Location location, CustomFurniture furniture, FurnitureExtraData extraData, boolean playSound) { public BukkitFurniture place(Location location, FurnitureConfig furniture, FurnitureDataAccessor extraData, boolean playSound) {
Optional<AnchorType> optionalAnchorType = extraData.anchorType(); // Optional<AnchorType> optionalAnchorType = extraData.anchorType();
if (optionalAnchorType.isEmpty() || !furniture.isAllowedPlacement(optionalAnchorType.get())) { // if (optionalAnchorType.isEmpty() || !furniture.isAllowedPlacement(optionalAnchorType.get())) {
extraData.anchorType(furniture.getAnyAnchorType()); // extraData.anchorType(furniture.getAnyAnchorType());
} // }
Entity furnitureEntity = EntityUtils.spawnEntity(location.getWorld(), location, EntityType.ITEM_DISPLAY, entity -> { // Entity furnitureEntity = EntityUtils.spawnEntity(location.getWorld(), location, EntityType.ITEM_DISPLAY, entity -> {
ItemDisplay display = (ItemDisplay) entity; // ItemDisplay display = (ItemDisplay) entity;
display.getPersistentDataContainer().set(BukkitFurnitureManager.FURNITURE_KEY, PersistentDataType.STRING, furniture.id().toString()); // display.getPersistentDataContainer().set(BukkitFurnitureManager.FURNITURE_KEY, PersistentDataType.STRING, furniture.id().toString());
try { // try {
display.getPersistentDataContainer().set(BukkitFurnitureManager.FURNITURE_EXTRA_DATA_KEY, PersistentDataType.BYTE_ARRAY, extraData.toBytes()); // display.getPersistentDataContainer().set(BukkitFurnitureManager.FURNITURE_EXTRA_DATA_KEY, PersistentDataType.BYTE_ARRAY, extraData.toBytes());
} catch (IOException e) { // } catch (IOException e) {
this.plugin.logger().warn("Failed to set furniture PDC for " + furniture.id().toString(), e); // this.plugin.logger().warn("Failed to set furniture PDC for " + furniture.id().toString(), e);
} // }
handleBaseEntityLoadEarly(display); // handleBaseEntityLoadEarly(display);
}); // });
if (playSound) { // if (playSound) {
SoundData data = furniture.settings().sounds().placeSound(); // SoundData data = furniture.settings().sounds().placeSound();
location.getWorld().playSound(location, data.id().toString(), SoundCategory.BLOCKS, data.volume().get(), data.pitch().get()); // location.getWorld().playSound(location, data.id().toString(), SoundCategory.BLOCKS, data.volume().get(), data.pitch().get());
} // }
return loadedFurnitureByRealEntityId(furnitureEntity.getEntityId()); // return loadedFurnitureByRealEntityId(furnitureEntity.getEntityId());
return null;
} }
@Override @Override
@@ -88,34 +79,34 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
NMS_COLLISION_ENTITY_TYPE = Config.colliderType() == ColliderType.INTERACTION ? MEntityTypes.INTERACTION : MEntityTypes.OAK_BOAT; NMS_COLLISION_ENTITY_TYPE = Config.colliderType() == ColliderType.INTERACTION ? MEntityTypes.INTERACTION : MEntityTypes.OAK_BOAT;
COLLISION_ENTITY_TYPE = Config.colliderType(); COLLISION_ENTITY_TYPE = Config.colliderType();
Bukkit.getPluginManager().registerEvents(this.furnitureEventListener, this.plugin.javaPlugin()); Bukkit.getPluginManager().registerEvents(this.furnitureEventListener, this.plugin.javaPlugin());
if (VersionHelper.isFolia()) { // if (VersionHelper.isFolia()) {
BiConsumer<Entity, Runnable> taskExecutor = (entity, runnable) -> entity.getScheduler().run(this.plugin.javaPlugin(), (t) -> runnable.run(), () -> {}); // BiConsumer<Entity, Runnable> taskExecutor = (entity, runnable) -> entity.getScheduler().run(this.plugin.javaPlugin(), (t) -> runnable.run(), () -> {});
for (World world : Bukkit.getWorlds()) { // for (World world : Bukkit.getWorlds()) {
List<Entity> entities = world.getEntities(); // List<Entity> entities = world.getEntities();
for (Entity entity : entities) { // for (Entity entity : entities) {
if (entity instanceof ItemDisplay display) { // if (entity instanceof ItemDisplay display) {
taskExecutor.accept(entity, () -> handleBaseEntityLoadEarly(display)); // taskExecutor.accept(entity, () -> handleBaseEntityLoadEarly(display));
} else if (entity instanceof Interaction interaction) { // } else if (entity instanceof Interaction interaction) {
taskExecutor.accept(entity, () -> handleCollisionEntityLoadOnEntitiesLoad(interaction)); // taskExecutor.accept(entity, () -> handleCollisionEntityLoadOnEntitiesLoad(interaction));
} else if (entity instanceof Boat boat) { // } else if (entity instanceof Boat boat) {
taskExecutor.accept(entity, () -> handleCollisionEntityLoadOnEntitiesLoad(boat)); // taskExecutor.accept(entity, () -> handleCollisionEntityLoadOnEntitiesLoad(boat));
} // }
} // }
} // }
} else { // } else {
for (World world : Bukkit.getWorlds()) { // for (World world : Bukkit.getWorlds()) {
List<Entity> entities = world.getEntities(); // List<Entity> entities = world.getEntities();
for (Entity entity : entities) { // for (Entity entity : entities) {
if (entity instanceof ItemDisplay display) { // if (entity instanceof ItemDisplay display) {
handleBaseEntityLoadEarly(display); // handleBaseEntityLoadEarly(display);
} else if (entity instanceof Interaction interaction) { // } else if (entity instanceof Interaction interaction) {
handleCollisionEntityLoadOnEntitiesLoad(interaction); // handleCollisionEntityLoadOnEntitiesLoad(interaction);
} else if (entity instanceof Boat boat) { // } else if (entity instanceof Boat boat) {
handleCollisionEntityLoadOnEntitiesLoad(boat); // handleCollisionEntityLoadOnEntitiesLoad(boat);
} // }
} // }
} // }
} // }
} }
@Override @Override
@@ -141,174 +132,165 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
return this.furnitureByEntityId.get(entityId); return this.furnitureByEntityId.get(entityId);
} }
@Override //
protected CustomFurniture.Builder furnitureBuilder() { // protected void handleBaseEntityUnload(Entity entity) {
return BukkitCustomFurniture.builder(); // int id = entity.getEntityId();
} // BukkitFurniture furniture = this.furnitureByRealEntityId.remove(id);
// if (furniture != null) {
@Override // Location location = entity.getLocation();
protected FurnitureElement.Builder furnitureElementBuilder() { // boolean isPreventing = FastNMS.INSTANCE.method$ServerLevel$isPreventingStatusUpdates(FastNMS.INSTANCE.field$CraftWorld$ServerLevel(location.getWorld()), location.getBlockX() >> 4, location.getBlockZ() >> 4);
return BukkitFurnitureElement.builder(); // if (!isPreventing) {
} // furniture.destroySeats();
// }
protected void handleBaseEntityUnload(Entity entity) { // for (int sub : furniture.entityIds()) {
int id = entity.getEntityId(); // this.furnitureByEntityId.remove(sub);
BukkitFurniture furniture = this.furnitureByRealEntityId.remove(id); // }
if (furniture != null) { // }
Location location = entity.getLocation(); // }
boolean isPreventing = FastNMS.INSTANCE.method$ServerLevel$isPreventingStatusUpdates(FastNMS.INSTANCE.field$CraftWorld$ServerLevel(location.getWorld()), location.getBlockX() >> 4, location.getBlockZ() >> 4); //
if (!isPreventing) { // protected void handleCollisionEntityUnload(Entity entity) {
furniture.destroySeats(); // int id = entity.getEntityId();
} // this.furnitureByRealEntityId.remove(id);
for (int sub : furniture.entityIds()) { // }
this.furnitureByEntityId.remove(sub); //
} // @SuppressWarnings("deprecation") // just a misleading name `getTrackedPlayers`
} // protected void handleBaseEntityLoadLate(ItemDisplay display, int depth) {
} // // must be a furniture item
// String id = display.getPersistentDataContainer().get(FURNITURE_KEY, PersistentDataType.STRING);
protected void handleCollisionEntityUnload(Entity entity) { // if (id == null) return;
int id = entity.getEntityId(); //
this.furnitureByRealEntityId.remove(id); // Key key = Key.of(id);
} // Optional<FurnitureConfig> optionalFurniture = furnitureById(key);
// if (optionalFurniture.isEmpty()) return;
@SuppressWarnings("deprecation") // just a misleading name `getTrackedPlayers` //
protected void handleBaseEntityLoadLate(ItemDisplay display, int depth) { // FurnitureConfig customFurniture = optionalFurniture.get();
// must be a furniture item // BukkitFurniture previous = this.furnitureByRealEntityId.get(display.getEntityId());
String id = display.getPersistentDataContainer().get(FURNITURE_KEY, PersistentDataType.STRING); // if (previous != null) return;
if (id == null) return; //
// Location location = display.getLocation();
Key key = Key.of(id); // boolean above1_20_1 = VersionHelper.isOrAbove1_20_2();
Optional<CustomFurniture> optionalFurniture = furnitureById(key); // boolean preventChange = FastNMS.INSTANCE.method$ServerLevel$isPreventingStatusUpdates(FastNMS.INSTANCE.field$CraftWorld$ServerLevel(location.getWorld()), location.getBlockX() >> 4, location.getBlockZ() >> 4);
if (optionalFurniture.isEmpty()) return; // if (above1_20_1) {
// if (!preventChange) {
CustomFurniture customFurniture = optionalFurniture.get(); // BukkitFurniture furniture = addNewFurniture(display, customFurniture);
BukkitFurniture previous = this.furnitureByRealEntityId.get(display.getEntityId()); // furniture.initializeColliders();
if (previous != null) return; // for (Player player : display.getTrackedPlayers()) {
// BukkitAdaptors.adapt(player).entityPacketHandlers().computeIfAbsent(furniture.baseEntityId(), k -> new FurniturePacketHandler(furniture.fakeEntityIds()));
Location location = display.getLocation(); // this.plugin.networkManager().sendPacket(BukkitAdaptors.adapt(player), furniture.spawnPacket(player));
boolean above1_20_1 = VersionHelper.isOrAbove1_20_2(); // }
boolean preventChange = FastNMS.INSTANCE.method$ServerLevel$isPreventingStatusUpdates(FastNMS.INSTANCE.field$CraftWorld$ServerLevel(location.getWorld()), location.getBlockX() >> 4, location.getBlockZ() >> 4); // }
if (above1_20_1) { // } else {
if (!preventChange) { // BukkitFurniture furniture = addNewFurniture(display, customFurniture);
BukkitFurniture furniture = addNewFurniture(display, customFurniture); // for (Player player : display.getTrackedPlayers()) {
furniture.initializeColliders(); // BukkitServerPlayer serverPlayer = BukkitAdaptors.adapt(player);
for (Player player : display.getTrackedPlayers()) { // serverPlayer.entityPacketHandlers().computeIfAbsent(furniture.baseEntityId(), k -> new FurniturePacketHandler(furniture.fakeEntityIds()));
BukkitAdaptors.adapt(player).entityPacketHandlers().computeIfAbsent(furniture.baseEntityId(), k -> new FurniturePacketHandler(furniture.fakeEntityIds())); // this.plugin.networkManager().sendPacket(serverPlayer, furniture.spawnPacket(player));
this.plugin.networkManager().sendPacket(BukkitAdaptors.adapt(player), furniture.spawnPacket(player)); // }
} // if (preventChange) {
} // this.plugin.scheduler().sync().runLater(furniture::initializeColliders, 1, location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4);
} else { // } else {
BukkitFurniture furniture = addNewFurniture(display, customFurniture); // furniture.initializeColliders();
for (Player player : display.getTrackedPlayers()) { // }
BukkitServerPlayer serverPlayer = BukkitAdaptors.adapt(player); // }
serverPlayer.entityPacketHandlers().computeIfAbsent(furniture.baseEntityId(), k -> new FurniturePacketHandler(furniture.fakeEntityIds())); // if (depth > 2) return;
this.plugin.networkManager().sendPacket(serverPlayer, furniture.spawnPacket(player)); // this.plugin.scheduler().sync().runLater(() -> handleBaseEntityLoadLate(display, depth + 1), 1, location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4);
} // }
if (preventChange) { //
this.plugin.scheduler().sync().runLater(furniture::initializeColliders, 1, location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4); // protected void handleCollisionEntityLoadLate(Entity entity, int depth) {
} else { // // remove the entity if it's not a collision entity, it might be wrongly copied by WorldEdit
furniture.initializeColliders(); // if (FastNMS.INSTANCE.method$CraftEntity$getHandle(entity) instanceof CollisionEntity) {
} // return;
} // }
if (depth > 2) return; // // not a collision entity
this.plugin.scheduler().sync().runLater(() -> handleBaseEntityLoadLate(display, depth + 1), 1, location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4); // Byte flag = entity.getPersistentDataContainer().get(FURNITURE_COLLISION, PersistentDataType.BYTE);
} // if (flag == null || flag != 1) {
// return;
protected void handleCollisionEntityLoadLate(Entity entity, int depth) { // }
// remove the entity if it's not a collision entity, it might be wrongly copied by WorldEdit //
if (FastNMS.INSTANCE.method$CraftEntity$getHandle(entity) instanceof CollisionEntity) { // Location location = entity.getLocation();
return; // World world = location.getWorld();
} // int chunkX = location.getBlockX() >> 4;
// not a collision entity // int chunkZ = location.getBlockZ() >> 4;
Byte flag = entity.getPersistentDataContainer().get(FURNITURE_COLLISION, PersistentDataType.BYTE); // if (!FastNMS.INSTANCE.method$ServerLevel$isPreventingStatusUpdates(FastNMS.INSTANCE.field$CraftWorld$ServerLevel(world), chunkX, chunkZ)) {
if (flag == null || flag != 1) { // entity.remove();
return; // return;
} // }
//
Location location = entity.getLocation(); // if (depth > 2) return;
World world = location.getWorld(); // plugin.scheduler().sync().runLater(() -> {
int chunkX = location.getBlockX() >> 4; // handleCollisionEntityLoadLate(entity, depth + 1);
int chunkZ = location.getBlockZ() >> 4; // }, 1, world, chunkX, chunkZ);
if (!FastNMS.INSTANCE.method$ServerLevel$isPreventingStatusUpdates(FastNMS.INSTANCE.field$CraftWorld$ServerLevel(world), chunkX, chunkZ)) { // }
entity.remove(); //
return; // public void handleBaseEntityLoadEarly(ItemDisplay display) {
} // String id = display.getPersistentDataContainer().get(FURNITURE_KEY, PersistentDataType.STRING);
// if (id == null) return;
if (depth > 2) return; // // Remove the entity if it's not a valid furniture
plugin.scheduler().sync().runLater(() -> { // if (Config.handleInvalidFurniture()) {
handleCollisionEntityLoadLate(entity, depth + 1); // String mapped = Config.furnitureMappings().get(id);
}, 1, world, chunkX, chunkZ); // if (mapped != null) {
} // if (mapped.isEmpty()) {
// display.remove();
public void handleBaseEntityLoadEarly(ItemDisplay display) { // return;
String id = display.getPersistentDataContainer().get(FURNITURE_KEY, PersistentDataType.STRING); // } else {
if (id == null) return; // id = mapped;
// Remove the entity if it's not a valid furniture // display.getPersistentDataContainer().set(FURNITURE_KEY, PersistentDataType.STRING, id);
if (Config.handleInvalidFurniture()) { // }
String mapped = Config.furnitureMappings().get(id); // }
if (mapped != null) { // }
if (mapped.isEmpty()) { //
display.remove(); // Key key = Key.of(id);
return; // Optional<FurnitureConfig> optionalFurniture = furnitureById(key);
} else { // if (optionalFurniture.isPresent()) {
id = mapped; // FurnitureConfig customFurniture = optionalFurniture.get();
display.getPersistentDataContainer().set(FURNITURE_KEY, PersistentDataType.STRING, id); // BukkitFurniture previous = this.furnitureByRealEntityId.get(display.getEntityId());
} // if (previous != null) return;
} // BukkitFurniture furniture = addNewFurniture(display, customFurniture);
} // furniture.initializeColliders(); // safely do it here
// }
Key key = Key.of(id); // }
Optional<CustomFurniture> optionalFurniture = furnitureById(key); //
if (optionalFurniture.isPresent()) { // public void handleCollisionEntityLoadOnEntitiesLoad(Entity collisionEntity) {
CustomFurniture customFurniture = optionalFurniture.get(); // // faster
BukkitFurniture previous = this.furnitureByRealEntityId.get(display.getEntityId()); // if (FastNMS.INSTANCE.method$CraftEntity$getHandle(collisionEntity) instanceof CollisionEntity) {
if (previous != null) return; // collisionEntity.remove();
BukkitFurniture furniture = addNewFurniture(display, customFurniture); // return;
furniture.initializeColliders(); // safely do it here // }
} //
} // // not a collision entity
// Byte flag = collisionEntity.getPersistentDataContainer().get(FURNITURE_COLLISION, PersistentDataType.BYTE);
public void handleCollisionEntityLoadOnEntitiesLoad(Entity collisionEntity) { // if (flag == null || flag != 1) {
// faster // return;
if (FastNMS.INSTANCE.method$CraftEntity$getHandle(collisionEntity) instanceof CollisionEntity) { // }
collisionEntity.remove(); //
return; // collisionEntity.remove();
} // }
//
// not a collision entity // private FurnitureDataAccessor getFurnitureExtraData(Entity baseEntity) throws IOException {
Byte flag = collisionEntity.getPersistentDataContainer().get(FURNITURE_COLLISION, PersistentDataType.BYTE); // byte[] extraData = baseEntity.getPersistentDataContainer().get(FURNITURE_EXTRA_DATA_KEY, PersistentDataType.BYTE_ARRAY);
if (flag == null || flag != 1) { // if (extraData == null) return FurnitureDataAccessor.builder().build();
return; // return FurnitureDataAccessor.fromBytes(extraData);
} // }
//
collisionEntity.remove(); // private synchronized BukkitFurniture addNewFurniture(ItemDisplay display, FurnitureConfig furniture) {
} // FurnitureDataAccessor extraData;
// try {
private FurnitureExtraData getFurnitureExtraData(Entity baseEntity) throws IOException { // extraData = getFurnitureExtraData(display);
byte[] extraData = baseEntity.getPersistentDataContainer().get(FURNITURE_EXTRA_DATA_KEY, PersistentDataType.BYTE_ARRAY); // } catch (IOException e) {
if (extraData == null) return FurnitureExtraData.builder().build(); // extraData = FurnitureDataAccessor.builder().build();
return FurnitureExtraData.fromBytes(extraData); // plugin.logger().warn("Furniture extra data could not be loaded", e);
} // }
// BukkitFurniture bukkitFurniture = new BukkitFurniture(display, furniture, extraData);
private synchronized BukkitFurniture addNewFurniture(ItemDisplay display, CustomFurniture furniture) { // this.furnitureByRealEntityId.put(bukkitFurniture.baseEntityId(), bukkitFurniture);
FurnitureExtraData extraData; // for (int entityId : bukkitFurniture.entityIds()) {
try { // this.furnitureByEntityId.put(entityId, bukkitFurniture);
extraData = getFurnitureExtraData(display); // }
} catch (IOException e) { // for (Collider collisionEntity : bukkitFurniture.collisionEntities()) {
extraData = FurnitureExtraData.builder().build(); // int collisionEntityId = FastNMS.INSTANCE.method$Entity$getId(collisionEntity.handle());
plugin.logger().warn("Furniture extra data could not be loaded", e); // this.furnitureByRealEntityId.put(collisionEntityId, bukkitFurniture);
} // }
BukkitFurniture bukkitFurniture = new BukkitFurniture(display, furniture, extraData); // return bukkitFurniture;
this.furnitureByRealEntityId.put(bukkitFurniture.baseEntityId(), bukkitFurniture); // }
for (int entityId : bukkitFurniture.entityIds()) {
this.furnitureByEntityId.put(entityId, bukkitFurniture);
}
for (Collider collisionEntity : bukkitFurniture.collisionEntities()) {
int collisionEntityId = FastNMS.INSTANCE.method$Entity$getId(collisionEntity.handle());
this.furnitureByRealEntityId.put(collisionEntityId, bukkitFurniture);
}
return bukkitFurniture;
}
@Override @Override
protected HitBoxConfig defaultHitBox() { protected HitBoxConfig defaultHitBox() {

View File

@@ -1,18 +1,6 @@
package net.momirealms.craftengine.bukkit.entity.furniture; package net.momirealms.craftengine.bukkit.entity.furniture;
import com.destroystokyo.paper.event.entity.EntityAddToWorldEvent;
import com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent;
import org.bukkit.entity.Entity;
import org.bukkit.entity.ItemDisplay;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.world.ChunkUnloadEvent;
import org.bukkit.event.world.EntitiesLoadEvent;
import org.bukkit.event.world.WorldLoadEvent;
import org.bukkit.event.world.WorldUnloadEvent;
import java.util.List;
public class FurnitureEventListener implements Listener { public class FurnitureEventListener implements Listener {
private final BukkitFurnitureManager manager; private final BukkitFurnitureManager manager;
@@ -21,77 +9,77 @@ public class FurnitureEventListener implements Listener {
this.manager = manager; this.manager = manager;
} }
/* // /*
* Load Entities // * Load Entities
*/ // */
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) // @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onEntitiesLoadEarly(EntitiesLoadEvent event) { // public void onEntitiesLoadEarly(EntitiesLoadEvent event) {
List<Entity> entities = event.getEntities(); // List<Entity> entities = event.getEntities();
for (Entity entity : entities) { // for (Entity entity : entities) {
if (entity instanceof ItemDisplay itemDisplay) { // if (entity instanceof ItemDisplay itemDisplay) {
this.manager.handleBaseEntityLoadEarly(itemDisplay); // this.manager.handleBaseEntityLoadEarly(itemDisplay);
} else if (BukkitFurnitureManager.COLLISION_ENTITY_CLASS.isInstance(entity)) { // } else if (BukkitFurnitureManager.COLLISION_ENTITY_CLASS.isInstance(entity)) {
this.manager.handleCollisionEntityLoadOnEntitiesLoad(entity); // this.manager.handleCollisionEntityLoadOnEntitiesLoad(entity);
} // }
} // }
} // }
//
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) // @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onWorldLoad(WorldLoadEvent event) { // public void onWorldLoad(WorldLoadEvent event) {
List<Entity> entities = event.getWorld().getEntities(); // List<Entity> entities = event.getWorld().getEntities();
for (Entity entity : entities) { // for (Entity entity : entities) {
if (entity instanceof ItemDisplay itemDisplay) { // if (entity instanceof ItemDisplay itemDisplay) {
this.manager.handleBaseEntityLoadEarly(itemDisplay); // this.manager.handleBaseEntityLoadEarly(itemDisplay);
} else if (BukkitFurnitureManager.COLLISION_ENTITY_CLASS.isInstance(entity)) { // } else if (BukkitFurnitureManager.COLLISION_ENTITY_CLASS.isInstance(entity)) {
this.manager.handleCollisionEntityLoadOnEntitiesLoad(entity); // this.manager.handleCollisionEntityLoadOnEntitiesLoad(entity);
} // }
} // }
} // }
//
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) // @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onEntityLoad(EntityAddToWorldEvent event) { // public void onEntityLoad(EntityAddToWorldEvent event) {
Entity entity = event.getEntity(); // Entity entity = event.getEntity();
if (entity instanceof ItemDisplay itemDisplay) { // if (entity instanceof ItemDisplay itemDisplay) {
this.manager.handleBaseEntityLoadLate(itemDisplay, 0); // this.manager.handleBaseEntityLoadLate(itemDisplay, 0);
} else if (BukkitFurnitureManager.COLLISION_ENTITY_CLASS.isInstance(entity)) { // } else if (BukkitFurnitureManager.COLLISION_ENTITY_CLASS.isInstance(entity)) {
this.manager.handleCollisionEntityLoadLate(entity, 0); // this.manager.handleCollisionEntityLoadLate(entity, 0);
} // }
} // }
//
/* // /*
* Unload Entities // * Unload Entities
*/ // */
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) // @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
public void onChunkUnload(ChunkUnloadEvent event) { // public void onChunkUnload(ChunkUnloadEvent event) {
Entity[] entities = event.getChunk().getEntities(); // Entity[] entities = event.getChunk().getEntities();
for (Entity entity : entities) { // for (Entity entity : entities) {
if (entity instanceof ItemDisplay) { // if (entity instanceof ItemDisplay) {
this.manager.handleBaseEntityUnload(entity); // this.manager.handleBaseEntityUnload(entity);
} else if (BukkitFurnitureManager.COLLISION_ENTITY_CLASS.isInstance(entity)) { // } else if (BukkitFurnitureManager.COLLISION_ENTITY_CLASS.isInstance(entity)) {
this.manager.handleCollisionEntityUnload(entity); // this.manager.handleCollisionEntityUnload(entity);
} // }
} // }
} // }
//
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) // @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
public void onWorldUnload(WorldUnloadEvent event) { // public void onWorldUnload(WorldUnloadEvent event) {
List<Entity> entities = event.getWorld().getEntities(); // List<Entity> entities = event.getWorld().getEntities();
for (Entity entity : entities) { // for (Entity entity : entities) {
if (entity instanceof ItemDisplay) { // if (entity instanceof ItemDisplay) {
this.manager.handleBaseEntityUnload(entity); // this.manager.handleBaseEntityUnload(entity);
} else if (BukkitFurnitureManager.COLLISION_ENTITY_CLASS.isInstance(entity)) { // } else if (BukkitFurnitureManager.COLLISION_ENTITY_CLASS.isInstance(entity)) {
this.manager.handleCollisionEntityUnload(entity); // this.manager.handleCollisionEntityUnload(entity);
} // }
} // }
} // }
//
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) // @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
public void onEntityUnload(EntityRemoveFromWorldEvent event) { // public void onEntityUnload(EntityRemoveFromWorldEvent event) {
Entity entity = event.getEntity(); // Entity entity = event.getEntity();
if (entity instanceof ItemDisplay) { // if (entity instanceof ItemDisplay) {
this.manager.handleBaseEntityUnload(entity); // this.manager.handleBaseEntityUnload(entity);
} else if (BukkitFurnitureManager.COLLISION_ENTITY_CLASS.isInstance(entity)) { // } else if (BukkitFurnitureManager.COLLISION_ENTITY_CLASS.isInstance(entity)) {
this.manager.handleCollisionEntityUnload(entity); // this.manager.handleCollisionEntityUnload(entity);
} // }
} // }
} }

View File

@@ -0,0 +1,6 @@
package net.momirealms.craftengine.bukkit.entity.furniture;
import net.momirealms.craftengine.core.util.Color;
public record ItemColorSource(Color dyedColor, int[] fireworkColors) {
}

View File

@@ -0,0 +1,15 @@
package net.momirealms.craftengine.bukkit.entity.furniture.element;
import net.momirealms.craftengine.core.entity.furniture.element.FurnitureElementConfigs;
public class BukkitFurnitureElementConfigs extends FurnitureElementConfigs {
static {
register(ITEM_DISPLAY, ItemDisplayFurnitureElementConfig.FACTORY);
}
private BukkitFurnitureElementConfigs() {}
public static void init() {
}
}

View File

@@ -0,0 +1,22 @@
package net.momirealms.craftengine.bukkit.entity.furniture.element;
import net.momirealms.craftengine.core.entity.furniture.element.FurnitureElement;
import net.momirealms.craftengine.core.entity.player.Player;
public class ItemDisplayFurnitureElement implements FurnitureElement {
private final ItemDisplayFurnitureElementConfig config;
public ItemDisplayFurnitureElement(ItemDisplayFurnitureElementConfig config) {
this.config = config;
}
@Override
public void show(Player player) {
}
@Override
public void hide(Player player) {
}
}

View File

@@ -0,0 +1,169 @@
package net.momirealms.craftengine.bukkit.entity.furniture.element;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import net.momirealms.craftengine.bukkit.entity.data.ItemDisplayEntityData;
import net.momirealms.craftengine.bukkit.entity.furniture.ItemColorSource;
import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
import net.momirealms.craftengine.core.entity.display.Billboard;
import net.momirealms.craftengine.core.entity.display.ItemDisplayContext;
import net.momirealms.craftengine.core.entity.furniture.element.FurnitureElement;
import net.momirealms.craftengine.core.entity.furniture.element.FurnitureElementConfig;
import net.momirealms.craftengine.core.entity.furniture.element.FurnitureElementConfigFactory;
import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.item.ItemKeys;
import net.momirealms.craftengine.core.item.data.FireworkExplosion;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import net.momirealms.craftengine.core.world.WorldPosition;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.joml.Quaternionf;
import org.joml.Vector3f;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.BiFunction;
public class ItemDisplayFurnitureElementConfig implements FurnitureElementConfig<ItemDisplayFurnitureElement> {
public static final Factory FACTORY = new Factory();
private final BiFunction<Player, ItemColorSource, List<Object>> lazyMetadataPacket;
private final BiFunction<Player, ItemColorSource, Item<?>> item;
private final Vector3f scale;
private final Vector3f position;
private final Vector3f translation;
private final float xRot;
private final float yRot;
private final Quaternionf rotation;
private final ItemDisplayContext displayContext;
private final Billboard billboard;
private final float shadowRadius;
private final float shadowStrength;
private final boolean applyDyedColor;
public ItemDisplayFurnitureElementConfig(BiFunction<Player, ItemColorSource, Item<?>> item,
Vector3f scale,
Vector3f position,
Vector3f translation,
float xRot,
float yRot,
Quaternionf rotation,
ItemDisplayContext displayContext,
Billboard billboard,
float shadowRadius,
float shadowStrength,
boolean applyDyedColor) {
this.scale = scale;
this.position = position;
this.translation = translation;
this.xRot = xRot;
this.yRot = yRot;
this.rotation = rotation;
this.displayContext = displayContext;
this.billboard = billboard;
this.shadowRadius = shadowRadius;
this.shadowStrength = shadowStrength;
this.applyDyedColor = applyDyedColor;
this.item = item;
this.lazyMetadataPacket = (player, source) -> {
List<Object> dataValues = new ArrayList<>();
ItemDisplayEntityData.DisplayedItem.addEntityData(item.apply(player, source).getLiteralObject(), dataValues);
ItemDisplayEntityData.Scale.addEntityData(this.scale, dataValues);
ItemDisplayEntityData.RotationLeft.addEntityData(this.rotation, dataValues);
ItemDisplayEntityData.BillboardConstraints.addEntityData(this.billboard.id(), dataValues);
ItemDisplayEntityData.Translation.addEntityData(this.translation, dataValues);
ItemDisplayEntityData.DisplayType.addEntityData(this.displayContext.id(), dataValues);
ItemDisplayEntityData.ShadowRadius.addEntityData(this.shadowRadius, dataValues);
ItemDisplayEntityData.ShadowStrength.addEntityData(this.shadowStrength, dataValues);
return dataValues;
};
}
public Vector3f scale() {
return scale;
}
public Vector3f position() {
return position;
}
public Vector3f translation() {
return translation;
}
public float xRot() {
return xRot;
}
public float yRot() {
return yRot;
}
public Quaternionf rotation() {
return rotation;
}
public ItemDisplayContext displayContext() {
return displayContext;
}
public Billboard billboard() {
return billboard;
}
public float shadowRadius() {
return shadowRadius;
}
public float shadowStrength() {
return shadowStrength;
}
public boolean applyDyedColor() {
return applyDyedColor;
}
@Override
public ItemDisplayFurnitureElement create(@NotNull WorldPosition position) {
return new ItemDisplayFurnitureElement(this);
}
public static class Factory implements FurnitureElementConfigFactory {
@SuppressWarnings("unchecked")
@Override
public <E extends FurnitureElement> FurnitureElementConfig<E> create(Map<String, Object> arguments) {
Key itemId = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("item"), "warning.config.furniture.element.item_display.missing_item"));
boolean applyDyedColor = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("apply-dyed-color", true), "apply-dyed-color");
return (FurnitureElementConfig<E>) new ItemDisplayFurnitureElementConfig(
(player, colorSource) -> {
Item<ItemStack> wrappedItem = BukkitItemManager.instance().createWrappedItem(itemId, player);
if (applyDyedColor && colorSource != null && wrappedItem != null) {
Optional.ofNullable(colorSource.dyedColor()).ifPresent(wrappedItem::dyedColor);
Optional.ofNullable(colorSource.fireworkColors()).ifPresent(colors -> wrappedItem.fireworkExplosion(new FireworkExplosion(
FireworkExplosion.Shape.SMALL_BALL,
new IntArrayList(colors),
new IntArrayList(),
false,
false
)));
}
return Optional.ofNullable(wrappedItem).orElseGet(() -> BukkitItemManager.instance().createWrappedItem(ItemKeys.BARRIER, null));
},
ResourceConfigUtils.getAsVector3f(arguments.getOrDefault("scale", 1f), "scale"),
ResourceConfigUtils.getAsVector3f(arguments.getOrDefault("position", 0.5f), "position"),
ResourceConfigUtils.getAsVector3f(arguments.get("translation"), "translation"),
ResourceConfigUtils.getAsFloat(arguments.getOrDefault("pitch", 0f), "pitch"),
ResourceConfigUtils.getAsFloat(arguments.getOrDefault("yaw", 0f), "yaw"),
ResourceConfigUtils.getAsQuaternionf(arguments.getOrDefault("rotation", 0f), "rotation"),
ResourceConfigUtils.getAsEnum(ResourceConfigUtils.get(arguments, "display-context", "display-transform"), ItemDisplayContext.class, ItemDisplayContext.NONE),
ResourceConfigUtils.getAsEnum(arguments.get("billboard"), Billboard.class, Billboard.FIXED),
ResourceConfigUtils.getAsFloat(arguments.getOrDefault("shadow-radius", 0f), "shadow-radius"),
ResourceConfigUtils.getAsFloat(arguments.getOrDefault("shadow-strength", 1f), "shadow-strength"),
applyDyedColor
);
}
}
}

View File

@@ -1,6 +1,6 @@
package net.momirealms.craftengine.bukkit.entity.furniture.hitbox; package net.momirealms.craftengine.bukkit.entity.furniture.hitbox;
import net.momirealms.craftengine.core.entity.furniture.HitBoxTypes; import net.momirealms.craftengine.core.entity.furniture.hitbox.HitBoxTypes;
public class BukkitHitBoxTypes extends HitBoxTypes { public class BukkitHitBoxTypes extends HitBoxTypes {

View File

@@ -1,42 +1,34 @@
package net.momirealms.craftengine.bukkit.entity.furniture.hitbox; package net.momirealms.craftengine.bukkit.entity.furniture.hitbox;
import net.momirealms.craftengine.bukkit.entity.data.BaseEntityData; import net.momirealms.craftengine.core.entity.furniture.hitbox.AbstractHitBoxConfig;
import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.core.entity.furniture.hitbox.HitBoxConfig;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.core.entity.furniture.hitbox.HitBoxConfigFactory;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MAttributeHolders; import net.momirealms.craftengine.core.entity.furniture.hitbox.HitBoxTypes;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections;
import net.momirealms.craftengine.core.entity.furniture.*;
import net.momirealms.craftengine.core.entity.seat.SeatConfig; import net.momirealms.craftengine.core.entity.seat.SeatConfig;
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import net.momirealms.craftengine.core.util.VersionHelper;
import net.momirealms.craftengine.core.world.WorldPosition;
import net.momirealms.craftengine.core.world.collision.AABB;
import org.bukkit.NamespacedKey; import org.bukkit.NamespacedKey;
import org.bukkit.Registry; import org.bukkit.Registry;
import org.bukkit.entity.EntityType; import org.bukkit.entity.EntityType;
import org.joml.Quaternionf;
import org.joml.Vector3f; import org.joml.Vector3f;
import java.util.*; import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class CustomHitBoxConfig extends AbstractHitBoxConfig { public class CustomHitBoxConfig extends AbstractHitBoxConfig {
public static final Factory FACTORY = new Factory(); public static final Factory FACTORY = new Factory();
private final float scale; private final float scale;
private final EntityType entityType; private final EntityType entityType;
private final List<Object> cachedValues = new ArrayList<>();
public CustomHitBoxConfig(SeatConfig[] seats, Vector3f position, EntityType type, float scale, boolean blocksBuilding, boolean canBeHitByProjectile) { public CustomHitBoxConfig(SeatConfig[] seats,
Vector3f position,
EntityType type,
float scale,
boolean blocksBuilding,
boolean canBeHitByProjectile) {
super(seats, position, false, blocksBuilding, canBeHitByProjectile); super(seats, position, false, blocksBuilding, canBeHitByProjectile);
this.scale = scale; this.scale = scale;
this.entityType = type; this.entityType = type;
BaseEntityData.NoGravity.addEntityDataIfNotDefaultValue(true, this.cachedValues);
BaseEntityData.Silent.addEntityDataIfNotDefaultValue(true, this.cachedValues);
BaseEntityData.SharedFlags.addEntityDataIfNotDefaultValue((byte) 0x20, this.cachedValues);
} }
public EntityType entityType() { public EntityType entityType() {
@@ -52,41 +44,13 @@ public class CustomHitBoxConfig extends AbstractHitBoxConfig {
return HitBoxTypes.CUSTOM; return HitBoxTypes.CUSTOM;
} }
@Override
public void initPacketsAndColliders(int[] entityId, WorldPosition position, Quaternionf conjugated, BiConsumer<Object, Boolean> packets, Consumer<Collider> collider, Consumer<HitBoxPart> aabb) {
Vector3f offset = conjugated.transform(new Vector3f(position()));
try {
packets.accept(FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket(
entityId[0], UUID.randomUUID(), position.x() + offset.x, position.y() + offset.y, position.z() - offset.z, 0, position.yRot(),
FastNMS.INSTANCE.method$CraftEntityType$toNMSEntityType(this.entityType), 0, CoreReflections.instance$Vec3$Zero, 0
), true);
packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId[0], List.copyOf(this.cachedValues)), true);
if (VersionHelper.isOrAbove1_20_5() && this.scale != 1) {
Object attributeInstance = CoreReflections.constructor$AttributeInstance.newInstance(MAttributeHolders.SCALE, (Consumer<?>) (o) -> {});
CoreReflections.method$AttributeInstance$setBaseValue.invoke(attributeInstance, this.scale);
packets.accept(NetworkReflections.constructor$ClientboundUpdateAttributesPacket0.newInstance(entityId[0], Collections.singletonList(attributeInstance)), false);
}
} catch (ReflectiveOperationException e) {
throw new RuntimeException("Failed to construct custom hitbox spawn packet", e);
}
}
@Override
public void initShapeForPlacement(double x, double y, double z, float yaw, Quaternionf conjugated, Consumer<AABB> aabbs) {
}
@Override
public int[] acquireEntityIds(Supplier<Integer> entityIdSupplier) {
return new int[] {entityIdSupplier.get()};
}
public static class Factory implements HitBoxConfigFactory { public static class Factory implements HitBoxConfigFactory {
@Override @Override
public HitBoxConfig create(Map<String, Object> arguments) { public HitBoxConfig create(Map<String, Object> arguments) {
Vector3f position = ResourceConfigUtils.getAsVector3f(arguments.getOrDefault("position", "0"), "position"); Vector3f position = ResourceConfigUtils.getAsVector3f(arguments.getOrDefault("position", "0"), "position");
float scale = ResourceConfigUtils.getAsFloat(arguments.getOrDefault("scale", 1), "scale"); float scale = ResourceConfigUtils.getAsFloat(arguments.getOrDefault("scale", 1), "scale");
String type = (String) arguments.getOrDefault("entity-type", "slime"); String type = (String) arguments.getOrDefault("entity-id", "slime");
EntityType entityType = Registry.ENTITY_TYPE.get(new NamespacedKey("minecraft", type)); EntityType entityType = Registry.ENTITY_TYPE.get(new NamespacedKey("minecraft", type));
if (entityType == null) { if (entityType == null) {
throw new LocalizedResourceConfigException("warning.config.furniture.hitbox.custom.invalid_entity", new IllegalArgumentException("EntityType not found: " + type), type); throw new LocalizedResourceConfigException("warning.config.furniture.hitbox.custom.invalid_entity", new IllegalArgumentException("EntityType not found: " + type), type);

View File

@@ -7,7 +7,8 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflect
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MAttributeHolders; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MAttributeHolders;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MEntityTypes; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MEntityTypes;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections;
import net.momirealms.craftengine.core.entity.furniture.*; import net.momirealms.craftengine.core.entity.furniture.Collider;
import net.momirealms.craftengine.core.entity.furniture.hitbox.*;
import net.momirealms.craftengine.core.entity.seat.SeatConfig; import net.momirealms.craftengine.core.entity.seat.SeatConfig;
import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils;

View File

@@ -5,7 +5,8 @@ import net.momirealms.craftengine.bukkit.entity.furniture.BukkitCollider;
import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MEntityTypes; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MEntityTypes;
import net.momirealms.craftengine.core.entity.furniture.*; import net.momirealms.craftengine.core.entity.furniture.Collider;
import net.momirealms.craftengine.core.entity.furniture.hitbox.*;
import net.momirealms.craftengine.core.entity.seat.SeatConfig; import net.momirealms.craftengine.core.entity.seat.SeatConfig;
import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils;

View File

@@ -9,7 +9,8 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MAttributeH
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MEntityTypes; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MEntityTypes;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections;
import net.momirealms.craftengine.bukkit.util.DirectionUtils; import net.momirealms.craftengine.bukkit.util.DirectionUtils;
import net.momirealms.craftengine.core.entity.furniture.*; import net.momirealms.craftengine.core.entity.furniture.Collider;
import net.momirealms.craftengine.core.entity.furniture.hitbox.*;
import net.momirealms.craftengine.core.entity.seat.SeatConfig; import net.momirealms.craftengine.core.entity.seat.SeatConfig;
import net.momirealms.craftengine.core.util.*; import net.momirealms.craftengine.core.util.*;
import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.core.world.Vec3d;

View File

@@ -1,43 +1,18 @@
package net.momirealms.craftengine.bukkit.item.behavior; package net.momirealms.craftengine.bukkit.item.behavior;
import net.momirealms.craftengine.bukkit.api.event.FurnitureAttemptPlaceEvent;
import net.momirealms.craftengine.bukkit.api.event.FurniturePlaceEvent;
import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurniture;
import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager; import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
import net.momirealms.craftengine.bukkit.util.DirectionUtils;
import net.momirealms.craftengine.bukkit.util.EventUtils;
import net.momirealms.craftengine.bukkit.util.LocationUtils;
import net.momirealms.craftengine.core.entity.furniture.AnchorType;
import net.momirealms.craftengine.core.entity.furniture.CustomFurniture;
import net.momirealms.craftengine.core.entity.furniture.FurnitureExtraData;
import net.momirealms.craftengine.core.entity.furniture.HitBoxConfig;
import net.momirealms.craftengine.core.entity.player.InteractionResult; import net.momirealms.craftengine.core.entity.player.InteractionResult;
import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.item.behavior.ItemBehavior;
import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory; import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory;
import net.momirealms.craftengine.core.item.context.UseOnContext; import net.momirealms.craftengine.core.item.context.UseOnContext;
import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.pack.Pack;
import net.momirealms.craftengine.core.pack.PendingConfigSection; import net.momirealms.craftengine.core.pack.PendingConfigSection;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.context.ContextHolder;
import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext;
import net.momirealms.craftengine.core.plugin.context.event.EventTrigger;
import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters;
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
import net.momirealms.craftengine.core.util.*; import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.core.util.MiscUtils;
import net.momirealms.craftengine.core.world.collision.AABB;
import org.bukkit.Location;
import org.bukkit.World;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional;
public class FurnitureItemBehavior extends ItemBehavior { public class FurnitureItemBehavior extends ItemBehavior {
public static final Factory FACTORY = new Factory(); public static final Factory FACTORY = new Factory();
@@ -57,121 +32,121 @@ public class FurnitureItemBehavior extends ItemBehavior {
} }
public InteractionResult place(UseOnContext context) { public InteractionResult place(UseOnContext context) {
Optional<CustomFurniture> optionalCustomFurniture = BukkitFurnitureManager.instance().furnitureById(this.id); // Optional<FurnitureConfig> optionalCustomFurniture = BukkitFurnitureManager.instance().furnitureById(this.id);
if (optionalCustomFurniture.isEmpty()) { // if (optionalCustomFurniture.isEmpty()) {
CraftEngine.instance().logger().warn("Furniture " + this.id + " not found"); // CraftEngine.instance().logger().warn("Furniture " + this.id + " not found");
return InteractionResult.FAIL; // return InteractionResult.FAIL;
} // }
CustomFurniture customFurniture = optionalCustomFurniture.get(); // FurnitureConfig customFurniture = optionalCustomFurniture.get();
//
Direction clickedFace = context.getClickedFace(); // Direction clickedFace = context.getClickedFace();
AnchorType anchorType = switch (clickedFace) { // AnchorType anchorType = switch (clickedFace) {
case EAST, WEST, NORTH, SOUTH -> AnchorType.WALL; // case EAST, WEST, NORTH, SOUTH -> AnchorType.WALL;
case UP -> AnchorType.GROUND; // case UP -> AnchorType.GROUND;
case DOWN -> AnchorType.CEILING; // case DOWN -> AnchorType.CEILING;
}; // };
//
CustomFurniture.Placement placement = customFurniture.getPlacement(anchorType); // FurnitureConfig.Variant placement = customFurniture.getPlacement(anchorType);
if (placement == null) { // if (placement == null) {
return InteractionResult.FAIL; // return InteractionResult.FAIL;
} // }
//
Player player = context.getPlayer(); // Player player = context.getPlayer();
// todo adventure check // // todo adventure check
if (player != null && player.isAdventureMode()) { // if (player != null && player.isAdventureMode()) {
return InteractionResult.FAIL; // return InteractionResult.FAIL;
} // }
//
Vec3d clickedPosition = context.getClickLocation(); // Vec3d clickedPosition = context.getClickLocation();
//
// trigger event // // trigger event
org.bukkit.entity.Player bukkitPlayer = player != null ? (org.bukkit.entity.Player) player.platformPlayer() : null; // org.bukkit.entity.Player bukkitPlayer = player != null ? (org.bukkit.entity.Player) player.platformPlayer() : null;
World world = (World) context.getLevel().platformWorld(); // World world = (World) context.getLevel().platformWorld();
//
// get position and rotation for placement // // get position and rotation for placement
Vec3d finalPlacePosition; // Vec3d finalPlacePosition;
double furnitureYaw; // double furnitureYaw;
if (anchorType == AnchorType.WALL) { // if (anchorType == AnchorType.WALL) {
furnitureYaw = Direction.getYaw(clickedFace); // furnitureYaw = Direction.getYaw(clickedFace);
if (clickedFace == Direction.EAST || clickedFace == Direction.WEST) { // if (clickedFace == Direction.EAST || clickedFace == Direction.WEST) {
Pair<Double, Double> xz = placement.alignmentRule().apply(Pair.of(clickedPosition.y(), clickedPosition.z())); // Pair<Double, Double> xz = placement.alignmentRule().apply(Pair.of(clickedPosition.y(), clickedPosition.z()));
finalPlacePosition = new Vec3d(clickedPosition.x(), xz.left(), xz.right()); // finalPlacePosition = new Vec3d(clickedPosition.x(), xz.left(), xz.right());
} else { // } else {
Pair<Double, Double> xz = placement.alignmentRule().apply(Pair.of(clickedPosition.x(), clickedPosition.y())); // Pair<Double, Double> xz = placement.alignmentRule().apply(Pair.of(clickedPosition.x(), clickedPosition.y()));
finalPlacePosition = new Vec3d(xz.left(), xz.right(), clickedPosition.z()); // finalPlacePosition = new Vec3d(xz.left(), xz.right(), clickedPosition.z());
} // }
} else { // } else {
furnitureYaw = placement.rotationRule().apply(180 + (player != null ? player.yRot() : 0)); // furnitureYaw = placement.rotationRule().apply(180 + (player != null ? player.yRot() : 0));
Pair<Double, Double> xz = placement.alignmentRule().apply(Pair.of(clickedPosition.x(), clickedPosition.z())); // Pair<Double, Double> xz = placement.alignmentRule().apply(Pair.of(clickedPosition.x(), clickedPosition.z()));
finalPlacePosition = new Vec3d(xz.left(), clickedPosition.y(), xz.right()); // finalPlacePosition = new Vec3d(xz.left(), clickedPosition.y(), xz.right());
} // }
//
Location furnitureLocation = new Location(world, finalPlacePosition.x(), finalPlacePosition.y(), finalPlacePosition.z(), (float) furnitureYaw, 0); // Location furnitureLocation = new Location(world, finalPlacePosition.x(), finalPlacePosition.y(), finalPlacePosition.z(), (float) furnitureYaw, 0);
//
List<AABB> aabbs = new ArrayList<>(); // List<AABB> aabbs = new ArrayList<>();
for (HitBoxConfig hitBoxConfig : placement.hitBoxConfigs()) { // for (HitBoxConfig hitBoxConfig : placement.hitBoxConfigs()) {
hitBoxConfig.initShapeForPlacement(finalPlacePosition.x(), finalPlacePosition.y(), finalPlacePosition.z(), (float) furnitureYaw, QuaternionUtils.toQuaternionf(0, Math.toRadians(180 - furnitureYaw), 0).conjugate(), aabbs::add); // hitBoxConfig.initShapeForPlacement(finalPlacePosition.x(), finalPlacePosition.y(), finalPlacePosition.z(), (float) furnitureYaw, QuaternionUtils.toQuaternionf(0, Math.toRadians(180 - furnitureYaw), 0).conjugate(), aabbs::add);
} // }
if (!aabbs.isEmpty()) { // if (!aabbs.isEmpty()) {
if (!FastNMS.INSTANCE.checkEntityCollision(context.getLevel().serverWorld(), aabbs.stream().map(it -> FastNMS.INSTANCE.constructor$AABB(it.minX, it.minY, it.minZ, it.maxX, it.maxY, it.maxZ)).toList())) { // if (!FastNMS.INSTANCE.checkEntityCollision(context.getLevel().serverWorld(), aabbs.stream().map(it -> FastNMS.INSTANCE.constructor$AABB(it.minX, it.minY, it.minZ, it.maxX, it.maxY, it.maxZ)).toList())) {
return InteractionResult.FAIL; // return InteractionResult.FAIL;
} // }
} // }
//
if (!BukkitCraftEngine.instance().antiGriefProvider().canPlace(bukkitPlayer, furnitureLocation)) { // if (!BukkitCraftEngine.instance().antiGriefProvider().canPlace(bukkitPlayer, furnitureLocation)) {
return InteractionResult.FAIL; // return InteractionResult.FAIL;
} // }
//
if (player != null) { // if (player != null) {
FurnitureAttemptPlaceEvent attemptPlaceEvent = new FurnitureAttemptPlaceEvent(bukkitPlayer, customFurniture, anchorType, furnitureLocation.clone(), // FurnitureAttemptPlaceEvent attemptPlaceEvent = new FurnitureAttemptPlaceEvent(bukkitPlayer, customFurniture, anchorType, furnitureLocation.clone(),
DirectionUtils.toBlockFace(clickedFace), context.getHand(), world.getBlockAt(context.getClickedPos().x(), context.getClickedPos().y(), context.getClickedPos().z())); // DirectionUtils.toBlockFace(clickedFace), context.getHand(), world.getBlockAt(context.getClickedPos().x(), context.getClickedPos().y(), context.getClickedPos().z()));
if (EventUtils.fireAndCheckCancel(attemptPlaceEvent)) { // if (EventUtils.fireAndCheckCancel(attemptPlaceEvent)) {
return InteractionResult.FAIL; // return InteractionResult.FAIL;
} // }
} // }
//
Item<?> item = context.getItem(); // Item<?> item = context.getItem();
// 不可能 // // 不可能
if (ItemUtils.isEmpty(item)) return InteractionResult.FAIL; // if (ItemUtils.isEmpty(item)) return InteractionResult.FAIL;
//
BukkitFurniture bukkitFurniture = BukkitFurnitureManager.instance().place( // BukkitFurniture bukkitFurniture = BukkitFurnitureManager.instance().place(
furnitureLocation.clone(), customFurniture, // furnitureLocation.clone(), customFurniture,
FurnitureExtraData.builder() // FurnitureDataAccessor.builder()
.item(item.copyWithCount(1)) // .item(item.copyWithCount(1))
.anchorType(anchorType) // .anchorType(anchorType)
.dyedColor(item.dyedColor().orElse(null)) // .dyedColor(item.dyedColor().orElse(null))
.fireworkExplosionColors(item.fireworkExplosion().map(explosion -> explosion.colors().toIntArray()).orElse(null)) // .fireworkExplosionColors(item.fireworkExplosion().map(explosion -> explosion.colors().toIntArray()).orElse(null))
.build(), false); // .build(), false);
//
if (player != null) { // if (player != null) {
FurniturePlaceEvent placeEvent = new FurniturePlaceEvent(bukkitPlayer, bukkitFurniture, furnitureLocation, context.getHand()); // FurniturePlaceEvent placeEvent = new FurniturePlaceEvent(bukkitPlayer, bukkitFurniture, furnitureLocation, context.getHand());
if (EventUtils.fireAndCheckCancel(placeEvent)) { // if (EventUtils.fireAndCheckCancel(placeEvent)) {
bukkitFurniture.destroy(); // bukkitFurniture.destroy();
return InteractionResult.FAIL; // return InteractionResult.FAIL;
} // }
} // }
//
Cancellable dummy = Cancellable.dummy(); // Cancellable dummy = Cancellable.dummy();
PlayerOptionalContext functionContext = PlayerOptionalContext.of(player, ContextHolder.builder() // PlayerOptionalContext functionContext = PlayerOptionalContext.of(player, ContextHolder.builder()
.withParameter(DirectContextParameters.FURNITURE, bukkitFurniture) // .withParameter(DirectContextParameters.FURNITURE, bukkitFurniture)
.withParameter(DirectContextParameters.POSITION, LocationUtils.toWorldPosition(furnitureLocation)) // .withParameter(DirectContextParameters.POSITION, LocationUtils.toWorldPosition(furnitureLocation))
.withParameter(DirectContextParameters.EVENT, dummy) // .withParameter(DirectContextParameters.EVENT, dummy)
.withParameter(DirectContextParameters.HAND, context.getHand()) // .withParameter(DirectContextParameters.HAND, context.getHand())
.withParameter(DirectContextParameters.ITEM_IN_HAND, item) // .withParameter(DirectContextParameters.ITEM_IN_HAND, item)
); // );
customFurniture.execute(functionContext, EventTrigger.PLACE); // customFurniture.execute(functionContext, EventTrigger.PLACE);
if (dummy.isCancelled()) { // if (dummy.isCancelled()) {
return InteractionResult.SUCCESS_AND_CANCEL; // return InteractionResult.SUCCESS_AND_CANCEL;
} // }
//
if (player != null) { // if (player != null) {
if (!player.canInstabuild()) { // if (!player.canInstabuild()) {
item.count(item.count() - 1); // item.count(item.count() - 1);
} // }
player.swingHand(context.getHand()); // player.swingHand(context.getHand());
} // }
//
context.getLevel().playBlockSound(finalPlacePosition, customFurniture.settings().sounds().placeSound()); // context.getLevel().playBlockSound(finalPlacePosition, customFurniture.settings().sounds().placeSound());
return InteractionResult.SUCCESS; return InteractionResult.SUCCESS;
} }

View File

@@ -7,6 +7,7 @@ import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
import net.momirealms.craftengine.bukkit.block.behavior.BukkitBlockBehaviors; import net.momirealms.craftengine.bukkit.block.behavior.BukkitBlockBehaviors;
import net.momirealms.craftengine.bukkit.block.entity.renderer.element.BukkitBlockEntityElementConfigs; import net.momirealms.craftengine.bukkit.block.entity.renderer.element.BukkitBlockEntityElementConfigs;
import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager; import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager;
import net.momirealms.craftengine.bukkit.entity.furniture.element.BukkitFurnitureElementConfigs;
import net.momirealms.craftengine.bukkit.entity.furniture.hitbox.BukkitHitBoxTypes; import net.momirealms.craftengine.bukkit.entity.furniture.hitbox.BukkitHitBoxTypes;
import net.momirealms.craftengine.bukkit.entity.projectile.BukkitProjectileManager; import net.momirealms.craftengine.bukkit.entity.projectile.BukkitProjectileManager;
import net.momirealms.craftengine.bukkit.entity.seat.BukkitSeatManager; import net.momirealms.craftengine.bukkit.entity.seat.BukkitSeatManager;
@@ -162,6 +163,7 @@ public class BukkitCraftEngine extends CraftEngine {
BukkitItemBehaviors.init(); BukkitItemBehaviors.init();
BukkitHitBoxTypes.init(); BukkitHitBoxTypes.init();
BukkitBlockEntityElementConfigs.init(); BukkitBlockEntityElementConfigs.init();
BukkitFurnitureElementConfigs.init();
// 初始化 onload 阶段的兼容性 // 初始化 onload 阶段的兼容性
super.compatibilityManager().onLoad(); super.compatibilityManager().onLoad();
// 创建网络管理器 // 创建网络管理器

View File

@@ -39,7 +39,7 @@ public class BukkitPlatform implements Platform {
Map<String, Object> map = (Map<String, Object>) MRegistryOps.NBT.convertTo(MRegistryOps.JAVA, tag); Map<String, Object> map = (Map<String, Object>) MRegistryOps.NBT.convertTo(MRegistryOps.JAVA, tag);
return map.get("root"); return map.get("root");
} catch (CommandSyntaxException e) { } catch (CommandSyntaxException e) {
throw new LocalizedResourceConfigException("warning.config.type.snbt.invalid_syntax", e, nbt); throw new LocalizedResourceConfigException("warning.config.id.snbt.invalid_syntax", e, nbt);
} }
} }
@@ -55,7 +55,7 @@ public class BukkitPlatform implements Platform {
CompoundTag map = (CompoundTag) MRegistryOps.NBT.convertTo(MRegistryOps.SPARROW_NBT, tag); CompoundTag map = (CompoundTag) MRegistryOps.NBT.convertTo(MRegistryOps.SPARROW_NBT, tag);
return map.get("root"); return map.get("root");
} catch (CommandSyntaxException e) { } catch (CommandSyntaxException e) {
throw new LocalizedResourceConfigException("warning.config.type.snbt.invalid_syntax", e, nbt); throw new LocalizedResourceConfigException("warning.config.id.snbt.invalid_syntax", e, nbt);
} }
} }

View File

@@ -115,7 +115,7 @@ public class DebugItemDataCommand extends BukkitCommandFeature<CommandSender> {
} else if (nbt instanceof short[]) { } else if (nbt instanceof short[]) {
value = Arrays.toString((short[]) nbt); value = Arrays.toString((short[]) nbt);
} else { } else {
value = "Unknown array type"; value = "Unknown array id";
} }
} else { } else {
value = nbt.toString(); value = nbt.toString();

View File

@@ -5,7 +5,7 @@ import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager
import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature;
import net.momirealms.craftengine.bukkit.util.KeyUtils; import net.momirealms.craftengine.bukkit.util.KeyUtils;
import net.momirealms.craftengine.core.entity.furniture.AnchorType; import net.momirealms.craftengine.core.entity.furniture.AnchorType;
import net.momirealms.craftengine.core.entity.furniture.CustomFurniture; import net.momirealms.craftengine.core.entity.furniture.FurnitureConfig;
import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager;
import net.momirealms.craftengine.core.plugin.command.FlagKeys; import net.momirealms.craftengine.core.plugin.command.FlagKeys;
@@ -42,19 +42,19 @@ public class DebugSpawnFurnitureCommand extends BukkitCommandFeature<CommandSend
return CompletableFuture.completedFuture(plugin().furnitureManager().cachedSuggestions()); return CompletableFuture.completedFuture(plugin().furnitureManager().cachedSuggestions());
} }
})) }))
.optional("anchor-type", EnumParser.enumParser(AnchorType.class)) .optional("anchor-id", EnumParser.enumParser(AnchorType.class))
.flag(FlagKeys.SILENT_FLAG) .flag(FlagKeys.SILENT_FLAG)
.handler(context -> { .handler(context -> {
NamespacedKey namespacedKey = context.get("id"); NamespacedKey namespacedKey = context.get("id");
Key id = KeyUtils.namespacedKey2Key(namespacedKey); Key id = KeyUtils.namespacedKey2Key(namespacedKey);
BukkitFurnitureManager furnitureManager = BukkitFurnitureManager.instance(); BukkitFurnitureManager furnitureManager = BukkitFurnitureManager.instance();
Optional<CustomFurniture> optionalCustomFurniture = furnitureManager.furnitureById(id); Optional<FurnitureConfig> optionalCustomFurniture = furnitureManager.furnitureById(id);
if (optionalCustomFurniture.isEmpty()) { if (optionalCustomFurniture.isEmpty()) {
return; return;
} }
Location location = context.get("location"); Location location = context.get("location");
CustomFurniture customFurniture = optionalCustomFurniture.get(); FurnitureConfig customFurniture = optionalCustomFurniture.get();
AnchorType anchorType = (AnchorType) context.optional("anchor-type").orElse(customFurniture.getAnyAnchorType()); AnchorType anchorType = (AnchorType) context.optional("anchor-id").orElse(customFurniture.getAnyAnchorType());
boolean playSound = context.flags().hasFlag("silent"); boolean playSound = context.flags().hasFlag("silent");
CraftEngineFurniture.place(location, customFurniture, anchorType, playSound); CraftEngineFurniture.place(location, customFurniture, anchorType, playSound);
}); });

View File

@@ -15,7 +15,6 @@ import org.bukkit.entity.Player;
import org.incendo.cloud.Command; import org.incendo.cloud.Command;
import org.incendo.cloud.bukkit.parser.PlayerParser; import org.incendo.cloud.bukkit.parser.PlayerParser;
import org.incendo.cloud.parser.standard.BooleanParser; import org.incendo.cloud.parser.standard.BooleanParser;
import org.incendo.cloud.parser.standard.DoubleParser;
import java.util.Optional; import java.util.Optional;

View File

@@ -59,8 +59,8 @@ import net.momirealms.craftengine.bukkit.world.BukkitWorldManager;
import net.momirealms.craftengine.core.advancement.network.AdvancementHolder; import net.momirealms.craftengine.core.advancement.network.AdvancementHolder;
import net.momirealms.craftengine.core.advancement.network.AdvancementProgress; import net.momirealms.craftengine.core.advancement.network.AdvancementProgress;
import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.entity.furniture.HitBox; import net.momirealms.craftengine.core.entity.furniture.hitbox.HitBox;
import net.momirealms.craftengine.core.entity.furniture.HitBoxPart; import net.momirealms.craftengine.core.entity.furniture.hitbox.HitBoxPart;
import net.momirealms.craftengine.core.entity.player.InteractionHand; import net.momirealms.craftengine.core.entity.player.InteractionHand;
import net.momirealms.craftengine.core.entity.seat.Seat; import net.momirealms.craftengine.core.entity.seat.Seat;
import net.momirealms.craftengine.core.font.FontManager; import net.momirealms.craftengine.core.font.FontManager;
@@ -3711,11 +3711,11 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
if (actionType == 1) { if (actionType == 1) {
// ATTACK // ATTACK
boolean usingSecondaryAction = buf.readBoolean(); boolean usingSecondaryAction = buf.readBoolean();
if (entityId != furniture.baseEntityId()) { if (entityId != furniture.entityId()) {
event.setChanged(true); event.setChanged(true);
buf.clear(); buf.clear();
buf.writeVarInt(event.packetID()); buf.writeVarInt(event.packetID());
buf.writeVarInt(furniture.baseEntityId()); buf.writeVarInt(furniture.entityId());
buf.writeVarInt(actionType); buf.writeVarInt(actionType);
buf.writeBoolean(usingSecondaryAction); buf.writeBoolean(usingSecondaryAction);
} }
@@ -3765,11 +3765,11 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
float z = buf.readFloat(); float z = buf.readFloat();
InteractionHand hand = buf.readVarInt() == 0 ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND; InteractionHand hand = buf.readVarInt() == 0 ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND;
boolean usingSecondaryAction = buf.readBoolean(); boolean usingSecondaryAction = buf.readBoolean();
if (entityId != furniture.baseEntityId()) { if (entityId != furniture.entityId()) {
event.setChanged(true); event.setChanged(true);
buf.clear(); buf.clear();
buf.writeVarInt(event.packetID()); buf.writeVarInt(event.packetID());
buf.writeVarInt(furniture.baseEntityId()); buf.writeVarInt(furniture.entityId());
buf.writeVarInt(actionType); buf.writeVarInt(actionType);
buf.writeFloat(x).writeFloat(y).writeFloat(z); buf.writeFloat(x).writeFloat(y).writeFloat(z);
buf.writeVarInt(hand == InteractionHand.MAIN_HAND ? 0 : 1); buf.writeVarInt(hand == InteractionHand.MAIN_HAND ? 0 : 1);
@@ -3864,11 +3864,11 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
} else if (actionType == 0) { } else if (actionType == 0) {
int hand = buf.readVarInt(); int hand = buf.readVarInt();
boolean usingSecondaryAction = buf.readBoolean(); boolean usingSecondaryAction = buf.readBoolean();
if (entityId != furniture.baseEntityId()) { if (entityId != furniture.entityId()) {
event.setChanged(true); event.setChanged(true);
buf.clear(); buf.clear();
buf.writeVarInt(event.packetID()); buf.writeVarInt(event.packetID());
buf.writeVarInt(furniture.baseEntityId()); buf.writeVarInt(furniture.entityId());
buf.writeVarInt(actionType); buf.writeVarInt(actionType);
buf.writeVarInt(hand); buf.writeVarInt(hand);
buf.writeBoolean(usingSecondaryAction); buf.writeBoolean(usingSecondaryAction);

View File

@@ -63,7 +63,7 @@ public class ProjectilePacketHandler implements EntityPacketHandler {
public void convertAddCustomProjectilePacket(FriendlyByteBuf buf, ByteBufPacketEvent event) { public void convertAddCustomProjectilePacket(FriendlyByteBuf buf, ByteBufPacketEvent event) {
UUID uuid = buf.readUUID(); UUID uuid = buf.readUUID();
buf.readVarInt(); // type buf.readVarInt(); // id
double x = buf.readDouble(); double x = buf.readDouble();
double y = buf.readDouble(); double y = buf.readDouble();
double z = buf.readDouble(); double z = buf.readDouble();

View File

@@ -35,7 +35,7 @@ public class PayloadHelper {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
NetworkCodec<FriendlyByteBuf, ModPacket> codec = (NetworkCodec<FriendlyByteBuf, ModPacket>) BuiltInRegistries.MOD_PACKET.getValue(data.type()); NetworkCodec<FriendlyByteBuf, ModPacket> codec = (NetworkCodec<FriendlyByteBuf, ModPacket>) BuiltInRegistries.MOD_PACKET.getValue(data.type());
if (codec == null) { if (codec == null) {
CraftEngine.instance().logger().warn("Unknown data type class: " + data.getClass().getName()); CraftEngine.instance().logger().warn("Unknown data id class: " + data.getClass().getName());
return; return;
} }
FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer());
@@ -65,7 +65,7 @@ public class PayloadHelper {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
NetworkCodec<FriendlyByteBuf, ModPacket> codec = (NetworkCodec<FriendlyByteBuf, ModPacket>) BuiltInRegistries.MOD_PACKET.getValue(type); NetworkCodec<FriendlyByteBuf, ModPacket> codec = (NetworkCodec<FriendlyByteBuf, ModPacket>) BuiltInRegistries.MOD_PACKET.getValue(type);
if (codec == null) { if (codec == null) {
Debugger.COMMON.debug(() -> "Unknown data type received: " + type); Debugger.COMMON.debug(() -> "Unknown data id received: " + type);
return; return;
} }

View File

@@ -12,12 +12,9 @@ items:
sounds: sounds:
break: minecraft:block.bamboo_wood.break break: minecraft:block.bamboo_wood.break
place: minecraft:block.bamboo_wood.place place: minecraft:block.bamboo_wood.place
placement: variants:
ground: ground:
loot-spawn-offset: 0.5,0.5,0 loot-spawn-offset: 0.5,0.5,0
rules:
rotation: FOUR
alignment: CENTER
elements: elements:
- item: default:bench - item: default:bench
display-transform: NONE display-transform: NONE

View File

@@ -160,8 +160,8 @@ warning.config.sound.missing_name: "<yellow>Problem in Datei <arg:0> gefunden -
warning.config.jukebox_song.duplicate: "<yellow>Problem in Datei <arg:0> gefunden - Doppelter Jukebox-Song '<arg:1>'. Bitte prüfe, ob dieselbe Konfiguration in anderen Dateien vorhanden ist.</yellow>" warning.config.jukebox_song.duplicate: "<yellow>Problem in Datei <arg:0> gefunden - Doppelter Jukebox-Song '<arg:1>'. Bitte prüfe, ob dieselbe Konfiguration in anderen Dateien vorhanden ist.</yellow>"
warning.config.jukebox_song.missing_sound: "<yellow>Problem in Datei <arg:0> gefunden - Beim Jukebox-Song '<arg:1>' fehlt das erforderliche 'sound'-Argument.</yellow>" warning.config.jukebox_song.missing_sound: "<yellow>Problem in Datei <arg:0> gefunden - Beim Jukebox-Song '<arg:1>' fehlt das erforderliche 'sound'-Argument.</yellow>"
warning.config.furniture.duplicate: "<yellow>Problem in Datei <arg:0> gefunden - Doppeltes Furniture '<arg:1>'. Bitte prüfe, ob dieselbe Konfiguration in anderen Dateien vorhanden ist.</yellow>" warning.config.furniture.duplicate: "<yellow>Problem in Datei <arg:0> gefunden - Doppeltes Furniture '<arg:1>'. Bitte prüfe, ob dieselbe Konfiguration in anderen Dateien vorhanden ist.</yellow>"
warning.config.furniture.missing_placement: "<yellow>Problem in Datei <arg:0> gefunden - Beim Furniture '<arg:1>' fehlt das erforderliche 'placement'-Argument.</yellow>" warning.config.furniture.missing_variants: "<yellow>Problem in Datei <arg:0> gefunden - Beim Furniture '<arg:1>' fehlt das erforderliche 'variants'-Argument.</yellow>"
warning.config.furniture.element.missing_item: "<yellow>Problem in Datei <arg:0> gefunden - Beim Furniture '<arg:1>' fehlt das erforderliche 'item'-Argument für eines seiner Elemente.</yellow>" warning.config.furniture.element.item_display.missing_item: "<yellow>Problem in Datei <arg:0> gefunden - Beim Furniture '<arg:1>' fehlt das erforderliche 'item'-Argument für eines seiner Elemente.</yellow>"
warning.config.furniture.settings.unknown: "<yellow>Problem in Datei <arg:0> gefunden - Das Furniture '<arg:1>' verwendet einen unbekannten Einstellungs-Typ '<arg:2>'.</yellow>" warning.config.furniture.settings.unknown: "<yellow>Problem in Datei <arg:0> gefunden - Das Furniture '<arg:1>' verwendet einen unbekannten Einstellungs-Typ '<arg:2>'.</yellow>"
warning.config.furniture.hitbox.invalid_type: "<yellow>Problem in Datei <arg:0> gefunden - Das Furniture '<arg:1>' verwendet einen ungültigen Hitbox-Typ '<arg:2>'.</yellow>" warning.config.furniture.hitbox.invalid_type: "<yellow>Problem in Datei <arg:0> gefunden - Das Furniture '<arg:1>' verwendet einen ungültigen Hitbox-Typ '<arg:2>'.</yellow>"
warning.config.furniture.hitbox.custom.invalid_entity: "<yellow>Problem in Datei <arg:0> gefunden - Das Furniture '<arg:1>' verwendet eine benutzerdefinierte Hitbox mit ungültigem Entity-Typ '<arg:2>'.</yellow>" warning.config.furniture.hitbox.custom.invalid_entity: "<yellow>Problem in Datei <arg:0> gefunden - Das Furniture '<arg:1>' verwendet eine benutzerdefinierte Hitbox mit ungültigem Entity-Typ '<arg:2>'.</yellow>"

View File

@@ -190,8 +190,9 @@ warning.config.sound.missing_name: "<yellow>Issue found in file <arg:0> - The so
warning.config.jukebox_song.duplicate: "<yellow>Issue found in file <arg:0> - Duplicated jukebox song '<arg:1>'. Please check if there is the same configuration in other files.</yellow>" warning.config.jukebox_song.duplicate: "<yellow>Issue found in file <arg:0> - Duplicated jukebox song '<arg:1>'. Please check if there is the same configuration in other files.</yellow>"
warning.config.jukebox_song.missing_sound: "<yellow>Issue found in file <arg:0> - The jukebox song '<arg:1>' is missing the required 'sound' argument.</yellow>" warning.config.jukebox_song.missing_sound: "<yellow>Issue found in file <arg:0> - The jukebox song '<arg:1>' is missing the required 'sound' argument.</yellow>"
warning.config.furniture.duplicate: "<yellow>Issue found in file <arg:0> - Duplicated furniture '<arg:1>'. Please check if there is the same configuration in other files.</yellow>" warning.config.furniture.duplicate: "<yellow>Issue found in file <arg:0> - Duplicated furniture '<arg:1>'. Please check if there is the same configuration in other files.</yellow>"
warning.config.furniture.missing_placement: "<yellow>Issue found in file <arg:0> - The furniture '<arg:1>' is missing the required 'placement' argument.</yellow>" warning.config.furniture.missing_variants: "<yellow>Issue found in file <arg:0> - The furniture '<arg:1>' is missing the required 'variants' argument.</yellow>"
warning.config.furniture.element.missing_item: "<yellow>Issue found in file <arg:0> - The furniture '<arg:1>' is missing the required 'item' argument for one of its elements.</yellow>" warning.config.furniture.element.invalid_type: "<yellow>Issue found in file <arg:0> - The furniture '<arg:1>' is using an invalid element type '<arg:2>'.</yellow>"
warning.config.furniture.element.item_display.missing_item: "<yellow>Issue found in file <arg:0> - The furniture '<arg:1>' is missing the required 'item' argument for 'item_display' element.</yellow>"
warning.config.furniture.settings.unknown: "<yellow>Issue found in file <arg:0> - The furniture '<arg:1>' is using an unknown setting type '<arg:2>'.</yellow>" warning.config.furniture.settings.unknown: "<yellow>Issue found in file <arg:0> - The furniture '<arg:1>' is using an unknown setting type '<arg:2>'.</yellow>"
warning.config.furniture.hitbox.invalid_type: "<yellow>Issue found in file <arg:0> - The furniture '<arg:1>' is using an invalid hitbox type '<arg:2>'.</yellow>" warning.config.furniture.hitbox.invalid_type: "<yellow>Issue found in file <arg:0> - The furniture '<arg:1>' is using an invalid hitbox type '<arg:2>'.</yellow>"
warning.config.furniture.hitbox.custom.invalid_entity: "<yellow>Issue found in file <arg:0> - The furniture '<arg:1>' is using a custom hitbox with invalid entity type '<arg:2>'.</yellow>" warning.config.furniture.hitbox.custom.invalid_entity: "<yellow>Issue found in file <arg:0> - The furniture '<arg:1>' is using a custom hitbox with invalid entity type '<arg:2>'.</yellow>"

View File

@@ -111,8 +111,8 @@ warning.config.sound.missing_name: "<yellow>Problema encontrado en el archivo <a
warning.config.jukebox_song.duplicate: "<yellow>Problema encontrado en el archivo <arg:0> - Canción de tocadiscos duplicada '<arg:1>'. Verifica si hay la misma configuración en otros archivos.</yellow>" warning.config.jukebox_song.duplicate: "<yellow>Problema encontrado en el archivo <arg:0> - Canción de tocadiscos duplicada '<arg:1>'. Verifica si hay la misma configuración en otros archivos.</yellow>"
warning.config.jukebox_song.missing_sound: "<yellow>Problema encontrado en el archivo <arg:0> - La canción de tocadiscos '<arg:1>' carece del argumento requerido 'sound'.</yellow>" warning.config.jukebox_song.missing_sound: "<yellow>Problema encontrado en el archivo <arg:0> - La canción de tocadiscos '<arg:1>' carece del argumento requerido 'sound'.</yellow>"
warning.config.furniture.duplicate: "<yellow>Problema encontrado en el archivo <arg:0> - Mueble duplicado '<arg:1>'. Verifica si hay la misma configuración en otros archivos.</yellow>" warning.config.furniture.duplicate: "<yellow>Problema encontrado en el archivo <arg:0> - Mueble duplicado '<arg:1>'. Verifica si hay la misma configuración en otros archivos.</yellow>"
warning.config.furniture.missing_placement: "<yellow>Problema encontrado en el archivo <arg:0> - El mueble '<arg:1>' carece del argumento requerido 'placement'.</yellow>" warning.config.furniture.missing_variants: "<yellow>Problema encontrado en el archivo <arg:0> - El mueble '<arg:1>' carece del argumento requerido 'variants'.</yellow>"
warning.config.furniture.element.missing_item: "<yellow>Problema encontrado en el archivo <arg:0> - El mueble '<arg:1>' carece del argumento requerido 'item' para uno de sus elementos.</yellow>" warning.config.furniture.element.item_display.missing_item: "<yellow>Problema encontrado en el archivo <arg:0> - El mueble '<arg:1>' carece del argumento requerido 'item' para uno de sus elementos.</yellow>"
warning.config.furniture.settings.unknown: "<yellow>Problema encontrado en el archivo <arg:0> - El mueble '<arg:1>' está usando un tipo de configuración desconocido '<arg:2>'.</yellow>" warning.config.furniture.settings.unknown: "<yellow>Problema encontrado en el archivo <arg:0> - El mueble '<arg:1>' está usando un tipo de configuración desconocido '<arg:2>'.</yellow>"
warning.config.furniture.hitbox.invalid_type: "<yellow>Problema encontrado en el archivo <arg:0> - El mueble '<arg:1>' está usando un tipo de hitbox inválido '<arg:2>'.</yellow>" warning.config.furniture.hitbox.invalid_type: "<yellow>Problema encontrado en el archivo <arg:0> - El mueble '<arg:1>' está usando un tipo de hitbox inválido '<arg:2>'.</yellow>"
warning.config.furniture.hitbox.custom.invalid_entity: "<yellow>Problema encontrado en el archivo <arg:0> - El mueble '<arg:1>' está usando un hitbox personalizado con un tipo de entidad inválido '<arg:2>'.</yellow>" warning.config.furniture.hitbox.custom.invalid_entity: "<yellow>Problema encontrado en el archivo <arg:0> - El mueble '<arg:1>' está usando un hitbox personalizado con un tipo de entidad inválido '<arg:2>'.</yellow>"

View File

@@ -175,8 +175,8 @@ warning.config.sound.missing_name: "<yellow>Problème trouvé dans le fichier <a
warning.config.jukebox_song.duplicate: "<yellow>Problème trouvé dans le fichier <arg:0> - Chanson de jukebox dupliquée '<arg:1>'. Vérifiez sil existe la même configuration dans dautres fichiers.</yellow>" warning.config.jukebox_song.duplicate: "<yellow>Problème trouvé dans le fichier <arg:0> - Chanson de jukebox dupliquée '<arg:1>'. Vérifiez sil existe la même configuration dans dautres fichiers.</yellow>"
warning.config.jukebox_song.missing_sound: "<yellow>Problème trouvé dans le fichier <arg:0> - La chanson de jukebox '<arg:1>' manque largument obligatoire 'sound'.</yellow>" warning.config.jukebox_song.missing_sound: "<yellow>Problème trouvé dans le fichier <arg:0> - La chanson de jukebox '<arg:1>' manque largument obligatoire 'sound'.</yellow>"
warning.config.furniture.duplicate: "<yellow>Problème trouvé dans le fichier <arg:0> - Meuble dupliqué '<arg:1>'. Vérifiez sil existe la même configuration dans dautres fichiers.</yellow>" warning.config.furniture.duplicate: "<yellow>Problème trouvé dans le fichier <arg:0> - Meuble dupliqué '<arg:1>'. Vérifiez sil existe la même configuration dans dautres fichiers.</yellow>"
warning.config.furniture.missing_placement: "<yellow>Problème trouvé dans le fichier <arg:0> - Le meuble '<arg:1>' manque largument obligatoire 'placement'.</yellow>" warning.config.furniture.missing_variants: "<yellow>Problème trouvé dans le fichier <arg:0> - Le meuble '<arg:1>' manque largument obligatoire 'variants'.</yellow>"
warning.config.furniture.element.missing_item: "<yellow>Problème trouvé dans le fichier <arg:0> - Le meuble '<arg:1>' manque largument obligatoire 'item' pour un de ses éléments.</yellow>" warning.config.furniture.element.item_display.missing_item: "<yellow>Problème trouvé dans le fichier <arg:0> - Le meuble '<arg:1>' manque largument obligatoire 'item' pour un de ses éléments.</yellow>"
warning.config.furniture.settings.unknown: "<yellow>Problème trouvé dans le fichier <arg:0> - Le meuble '<arg:1>' utilise un type de paramètre inconnu '<arg:2>'.</yellow>" warning.config.furniture.settings.unknown: "<yellow>Problème trouvé dans le fichier <arg:0> - Le meuble '<arg:1>' utilise un type de paramètre inconnu '<arg:2>'.</yellow>"
warning.config.furniture.hitbox.invalid_type: "<yellow>Problème trouvé dans le fichier <arg:0> - Le meuble '<arg:1>' utilise un type de hitbox invalide '<arg:2>'.</yellow>" warning.config.furniture.hitbox.invalid_type: "<yellow>Problème trouvé dans le fichier <arg:0> - Le meuble '<arg:1>' utilise un type de hitbox invalide '<arg:2>'.</yellow>"
warning.config.furniture.hitbox.custom.invalid_entity: "<yellow>Problème trouvé dans le fichier <arg:0> - Le meuble '<arg:1>' utilise un hitbox personnalisé avec un type dentité invalide '<arg:2>'.</yellow>" warning.config.furniture.hitbox.custom.invalid_entity: "<yellow>Problème trouvé dans le fichier <arg:0> - Le meuble '<arg:1>' utilise un hitbox personnalisé avec un type dentité invalide '<arg:2>'.</yellow>"

View File

@@ -148,8 +148,8 @@ warning.config.sound.missing_name: "<yellow>Проблема найдена в
warning.config.jukebox_song.duplicate: "<yellow>Проблема найдена в файле <arg:0> - Дублированная песня музыкального автомата '<arg:1>'. Проверьте, есть ли такая же конфигурация в других файлах.</yellow>" warning.config.jukebox_song.duplicate: "<yellow>Проблема найдена в файле <arg:0> - Дублированная песня музыкального автомата '<arg:1>'. Проверьте, есть ли такая же конфигурация в других файлах.</yellow>"
warning.config.jukebox_song.missing_sound: "<yellow>Проблема найдена в файле <arg:0> - В песне музыкального автомата '<arg:1>' отсутствует необходимый 'sound' аргумент.</yellow>" warning.config.jukebox_song.missing_sound: "<yellow>Проблема найдена в файле <arg:0> - В песне музыкального автомата '<arg:1>' отсутствует необходимый 'sound' аргумент.</yellow>"
warning.config.furniture.duplicate: "<yellow>Проблема найдена в файле <arg:0> - Дублированная мебель '<arg:1>'. Проверьте, есть ли такая же конфигурация в других файлах.</yellow>" warning.config.furniture.duplicate: "<yellow>Проблема найдена в файле <arg:0> - Дублированная мебель '<arg:1>'. Проверьте, есть ли такая же конфигурация в других файлах.</yellow>"
warning.config.furniture.missing_placement: "<yellow>Проблема найдена в файле <arg:0> - В мебели '<arg:1>' отсутствует необходимый 'placement' аргумент.</yellow>" warning.config.furniture.missing_variants: "<yellow>Проблема найдена в файле <arg:0> - В мебели '<arg:1>' отсутствует необходимый 'variants' аргумент.</yellow>"
warning.config.furniture.element.missing_item: "<yellow>Проблема найдена в файле <arg:0> - В мебели '<arg:1>' отсутствует необходимый 'item' аргумент для одного из его элементов.</yellow>" warning.config.furniture.element.item_display.missing_item: "<yellow>Проблема найдена в файле <arg:0> - В мебели '<arg:1>' отсутствует необходимый 'item' аргумент для одного из его элементов.</yellow>"
warning.config.furniture.settings.unknown: "<yellow>Проблема найдена в файле <arg:0> - Мебель '<arg:1>' использует неизвестный тип настройки '<arg:2>'.</yellow>" warning.config.furniture.settings.unknown: "<yellow>Проблема найдена в файле <arg:0> - Мебель '<arg:1>' использует неизвестный тип настройки '<arg:2>'.</yellow>"
warning.config.furniture.hitbox.invalid_type: "<yellow>Проблема найдена в файле <arg:0> - Мебель '<arg:1>' использует недопустимый тип хитбокса '<arg:2>'.</yellow>" warning.config.furniture.hitbox.invalid_type: "<yellow>Проблема найдена в файле <arg:0> - Мебель '<arg:1>' использует недопустимый тип хитбокса '<arg:2>'.</yellow>"
warning.config.furniture.hitbox.custom.invalid_entity: "<yellow>Проблема найдена в файле <arg:0> - Мебель '<arg:1>' использует пользовательский хитбокс с недопустимым типом сущности '<arg:2>'.</yellow>" warning.config.furniture.hitbox.custom.invalid_entity: "<yellow>Проблема найдена в файле <arg:0> - Мебель '<arg:1>' использует пользовательский хитбокс с недопустимым типом сущности '<arg:2>'.</yellow>"

View File

@@ -110,8 +110,8 @@ warning.config.sound.missing_name: "<yellow><arg:0> dosyasında sorun bulundu -
warning.config.jukebox_song.duplicate: "<yellow><arg:0> dosyasında sorun bulundu - Yinelenen müzik çalar şarkısı '<arg:1>'. Diğer dosyalarda aynı yapılandırmanın olup olmadığını kontrol edin.</yellow>" warning.config.jukebox_song.duplicate: "<yellow><arg:0> dosyasında sorun bulundu - Yinelenen müzik çalar şarkısı '<arg:1>'. Diğer dosyalarda aynı yapılandırmanın olup olmadığını kontrol edin.</yellow>"
warning.config.jukebox_song.missing_sound: "<yellow><arg:0> dosyasında sorun bulundu - '<arg:1>' müzik çalar şarkısı gerekli 'sound' argümanı eksik.</yellow>" warning.config.jukebox_song.missing_sound: "<yellow><arg:0> dosyasında sorun bulundu - '<arg:1>' müzik çalar şarkısı gerekli 'sound' argümanı eksik.</yellow>"
warning.config.furniture.duplicate: "<yellow><arg:0> dosyasında sorun bulundu - Yinelenen mobilya '<arg:1>'. Diğer dosyalarda aynı yapılandırmanın olup olmadığını kontrol edin.</yellow>" warning.config.furniture.duplicate: "<yellow><arg:0> dosyasında sorun bulundu - Yinelenen mobilya '<arg:1>'. Diğer dosyalarda aynı yapılandırmanın olup olmadığını kontrol edin.</yellow>"
warning.config.furniture.missing_placement: "<yellow><arg:0> dosyasında sorun bulundu - '<arg:1>' mobilyası gerekli 'placement' argümanı eksik.</yellow>" warning.config.furniture.missing_variants: "<yellow><arg:0> dosyasında sorun bulundu - '<arg:1>' mobilyası gerekli 'variants' argümanı eksik.</yellow>"
warning.config.furniture.element.missing_item: "<yellow><arg:0> dosyasında sorun bulundu - '<arg:1>' mobilyası, elementlerinden biri için gerekli 'item' argümanı eksik.</yellow>" warning.config.furniture.element.item_display.missing_item: "<yellow><arg:0> dosyasında sorun bulundu - '<arg:1>' mobilyası, elementlerinden biri için gerekli 'item' argümanı eksik.</yellow>"
warning.config.furniture.settings.unknown: "<yellow><arg:0> dosyasında sorun bulundu - '<arg:1>' mobilyası bilinmeyen bir ayar türü '<arg:2>' kullanıyor.</yellow>" warning.config.furniture.settings.unknown: "<yellow><arg:0> dosyasında sorun bulundu - '<arg:1>' mobilyası bilinmeyen bir ayar türü '<arg:2>' kullanıyor.</yellow>"
warning.config.furniture.hitbox.invalid_type: "<yellow><arg:0> dosyasında sorun bulundu - '<arg:1>' mobilyası geçersiz bir hitbox türü '<arg:2>' kullanıyor.</yellow>" warning.config.furniture.hitbox.invalid_type: "<yellow><arg:0> dosyasında sorun bulundu - '<arg:1>' mobilyası geçersiz bir hitbox türü '<arg:2>' kullanıyor.</yellow>"
warning.config.furniture.hitbox.custom.invalid_entity: "<yellow><arg:0> dosyasında sorun bulundu - '<arg:1>' mobilyası, geçersiz varlık türü '<arg:2>' olan özel bir hitbox kullanıyor.</yellow>" warning.config.furniture.hitbox.custom.invalid_entity: "<yellow><arg:0> dosyasında sorun bulundu - '<arg:1>' mobilyası, geçersiz varlık türü '<arg:2>' olan özel bir hitbox kullanıyor.</yellow>"

View File

@@ -183,8 +183,8 @@ warning.config.sound.missing_name: "<yellow>在文件 <arg:0> 发现问题 - 音
warning.config.jukebox_song.duplicate: "<yellow>在文件 <arg:0> 发现问题 - 重复的唱片机歌曲 '<arg:1>' 请检查其他文件中是否存在相同配置</yellow>" warning.config.jukebox_song.duplicate: "<yellow>在文件 <arg:0> 发现问题 - 重复的唱片机歌曲 '<arg:1>' 请检查其他文件中是否存在相同配置</yellow>"
warning.config.jukebox_song.missing_sound: "<yellow>在文件 <arg:0> 发现问题 - 唱片机歌曲 '<arg:1>' 缺少必需的 'sound' 参数</yellow>" warning.config.jukebox_song.missing_sound: "<yellow>在文件 <arg:0> 发现问题 - 唱片机歌曲 '<arg:1>' 缺少必需的 'sound' 参数</yellow>"
warning.config.furniture.duplicate: "<yellow>在文件 <arg:0> 发现问题 - 重复的家具 '<arg:1>' 请检查其他文件中是否存在相同配置</yellow>" warning.config.furniture.duplicate: "<yellow>在文件 <arg:0> 发现问题 - 重复的家具 '<arg:1>' 请检查其他文件中是否存在相同配置</yellow>"
warning.config.furniture.missing_placement: "<yellow>在文件 <arg:0> 发现问题 - 家具 '<arg:1>' 缺少必需的 'placement' 参数</yellow>" warning.config.furniture.missing_variants: "<yellow>在文件 <arg:0> 发现问题 - 家具 '<arg:1>' 缺少必需的 'variants' 参数</yellow>"
warning.config.furniture.element.missing_item: "<yellow>在文件 <arg:0> 发现问题 - 家具 '<arg:1>' 的某个元素缺少必需的 'item' 参数</yellow>" warning.config.furniture.element.item_display.missing_item: "<yellow>在文件 <arg:0> 发现问题 - 家具 '<arg:1>' 的 'item_display' 元素缺少必需的 'item' 参数</yellow>"
warning.config.furniture.settings.unknown: "<yellow>在文件 <arg:0> 发现问题 - 家具 '<arg:1>' 使用了未知的设置类型 '<arg:2>'</yellow>" warning.config.furniture.settings.unknown: "<yellow>在文件 <arg:0> 发现问题 - 家具 '<arg:1>' 使用了未知的设置类型 '<arg:2>'</yellow>"
warning.config.furniture.hitbox.invalid_type: "<yellow>在文件 <arg:0> 发现问题 - 家具 '<arg:1>' 使用了无效的碰撞箱类型 '<arg:2>'</yellow>" warning.config.furniture.hitbox.invalid_type: "<yellow>在文件 <arg:0> 发现问题 - 家具 '<arg:1>' 使用了无效的碰撞箱类型 '<arg:2>'</yellow>"
warning.config.furniture.hitbox.custom.invalid_entity: "<yellow>在文件 <arg:0> 发现问题 - 家具 '<arg:1>' 的自定义碰撞箱使用了无效的实体类型 '<arg:2>'</yellow>" warning.config.furniture.hitbox.custom.invalid_entity: "<yellow>在文件 <arg:0> 发现问题 - 家具 '<arg:1>' 的自定义碰撞箱使用了无效的实体类型 '<arg:2>'</yellow>"

View File

@@ -711,12 +711,8 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
} }
private CullingData parseCullingData(Object arguments) { private CullingData parseCullingData(Object arguments) {
if (arguments instanceof Boolean b && !b) { if (arguments instanceof Boolean b && !b) return null;
return null; if (!(arguments instanceof Map)) return new CullingData(DEFAULT_BLOCK_ENTITY_AABB, Config.entityCullingViewDistance(), 0.5, true);
}
if (!(arguments instanceof Map)) {
return new CullingData(DEFAULT_BLOCK_ENTITY_AABB, Config.entityCullingViewDistance(), 0.5, true);
}
Map<String, Object> argumentsMap = ResourceConfigUtils.getAsMap(arguments, "entity-culling"); Map<String, Object> argumentsMap = ResourceConfigUtils.getAsMap(arguments, "entity-culling");
return new CullingData( return new CullingData(
ResourceConfigUtils.getAsAABB(argumentsMap.getOrDefault("aabb", 1), "aabb"), ResourceConfigUtils.getAsAABB(argumentsMap.getOrDefault("aabb", 1), "aabb"),

View File

@@ -78,7 +78,7 @@ public abstract class BlockBehavior {
return (boolean) superMethod.call(); return (boolean) superMethod.call();
} }
// 1.20-1.20.4 BlockState state, BlockGetter world, BlockPos pos, PathComputationType type // 1.20-1.20.4 BlockState state, BlockGetter world, BlockPos pos, PathComputationType id
// 1.20.5+ BlockState state, PathComputationType pathComputationType // 1.20.5+ BlockState state, PathComputationType pathComputationType
public boolean isPathFindable(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception { public boolean isPathFindable(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
return (boolean) superMethod.call(); return (boolean) superMethod.call();

View File

@@ -41,6 +41,7 @@ public class BlockSettings {
float friction = 0.6f; float friction = 0.6f;
float speedFactor = 1f; float speedFactor = 1f;
float jumpFactor = 1f; float jumpFactor = 1f;
Map<CustomDataType<?>, Object> customData = new IdentityHashMap<>(4);
private BlockSettings() {} private BlockSettings() {}
@@ -107,9 +108,29 @@ public class BlockSettings {
newSettings.speedFactor = settings.speedFactor; newSettings.speedFactor = settings.speedFactor;
newSettings.jumpFactor = settings.jumpFactor; newSettings.jumpFactor = settings.jumpFactor;
newSettings.friction = settings.friction; newSettings.friction = settings.friction;
newSettings.customData = new IdentityHashMap<>(settings.customData);
return newSettings; return newSettings;
} }
@SuppressWarnings("unchecked")
public <T> T getCustomData(CustomDataType<T> type) {
return (T) this.customData.get(type);
}
public void clearCustomData() {
this.customData.clear();
}
@Nullable
@SuppressWarnings("unchecked")
public <T> T removeCustomData(CustomDataType<?> type) {
return (T) this.customData.remove(type);
}
public <T> void addCustomData(CustomDataType<T> key, T value) {
this.customData.put(key, value);
}
public Set<Key> tags() { public Set<Key> tags() {
return tags; return tags;
} }
@@ -542,7 +563,7 @@ public class BlockSettings {
})); }));
} }
private static void registerFactory(String id, Modifier.Factory factory) { public static void registerFactory(String id, Modifier.Factory factory) {
FACTORIES.put(id, factory); FACTORIES.put(id, factory);
} }
} }

View File

@@ -4,7 +4,7 @@ import java.util.concurrent.Callable;
public interface IsPathFindableBlockBehavior { public interface IsPathFindableBlockBehavior {
// 1.20-1.20.4 BlockState state, BlockGetter world, BlockPos pos, PathComputationType type // 1.20-1.20.4 BlockState state, BlockGetter world, BlockPos pos, PathComputationType id
// 1.20.5+ BlockState state, PathComputationType pathComputationType // 1.20.5+ BlockState state, PathComputationType pathComputationType
boolean isPathFindable(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception; boolean isPathFindable(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception;
} }

View File

@@ -24,7 +24,7 @@ public abstract class BlockEntity {
this.type = type; this.type = type;
} }
public final CompoundTag saveAsTag() { public CompoundTag saveAsTag() {
CompoundTag tag = new CompoundTag(); CompoundTag tag = new CompoundTag();
this.saveId(tag); this.saveId(tag);
this.savePos(tag); this.savePos(tag);

View File

@@ -5,6 +5,7 @@ import net.momirealms.craftengine.core.util.Key;
public final class BlockEntityTypeKeys { public final class BlockEntityTypeKeys {
private BlockEntityTypeKeys() {} private BlockEntityTypeKeys() {}
public static final Key INACTIVE = Key.of("craftengine:inactive");
public static final Key UNSAFE_COMPOSITE = Key.of("craftengine:unsafe_composite"); public static final Key UNSAFE_COMPOSITE = Key.of("craftengine:unsafe_composite");
public static final Key SIMPLE_STORAGE = Key.of("craftengine:simple_storage"); public static final Key SIMPLE_STORAGE = Key.of("craftengine:simple_storage");
public static final Key SIMPLE_PARTICLE = Key.of("craftengine:simple_particle"); public static final Key SIMPLE_PARTICLE = Key.of("craftengine:simple_particle");

View File

@@ -7,6 +7,7 @@ import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.ResourceKey; import net.momirealms.craftengine.core.util.ResourceKey;
public abstract class BlockEntityTypes { public abstract class BlockEntityTypes {
public static final BlockEntityType<InactiveBlockEntity> INACTIVE = register(BlockEntityTypeKeys.INACTIVE);
public static <T extends BlockEntity> BlockEntityType<T> register(Key id) { public static <T extends BlockEntity> BlockEntityType<T> register(Key id) {
BlockEntityType<T> type = new BlockEntityType<>(id); BlockEntityType<T> type = new BlockEntityType<>(id);

View File

@@ -0,0 +1,21 @@
package net.momirealms.craftengine.core.block.entity;
import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.world.BlockPos;
import net.momirealms.sparrow.nbt.CompoundTag;
public class InactiveBlockEntity extends BlockEntity {
private final CompoundTag tag;
public InactiveBlockEntity(BlockPos pos,
ImmutableBlockState blockState,
CompoundTag tag) {
super(BlockEntityTypes.INACTIVE, pos, blockState);
this.tag = tag;
}
@Override
public CompoundTag saveAsTag() {
return this.tag;
}
}

View File

@@ -0,0 +1,96 @@
package net.momirealms.craftengine.core.entity;
import net.momirealms.craftengine.core.world.CEWorld;
import net.momirealms.craftengine.core.world.Cullable;
import net.momirealms.craftengine.core.world.WorldPosition;
import net.momirealms.sparrow.nbt.CompoundTag;
import java.util.UUID;
public abstract class CustomEntity implements Cullable {
protected final CustomEntityType<?> type;
protected final UUID uuid;
protected WorldPosition position;
protected boolean valid = true;
protected CustomEntity(CustomEntityType<?> type, WorldPosition position, UUID uuid) {
this.position = position;
this.type = type;
this.uuid = uuid;
}
public CompoundTag saveAsTag() {
CompoundTag tag = new CompoundTag();
this.saveId(tag);
this.savePos(tag);
this.saveCustomData(tag);
return tag;
}
private void savePos(CompoundTag tag) {
tag.putDouble("x", this.position.x());
tag.putDouble("y", this.position.y());
tag.putDouble("z", this.position.z());
tag.putFloat("x_rot", this.position.xRot());
tag.putFloat("y_rot", this.position.yRot());
}
public boolean isValid() {
return this.valid;
}
public UUID uuid() {
return uuid;
}
public double x() {
return this.position.x();
}
public double y() {
return this.position.y();
}
public double z() {
return this.position.z();
}
public float yRot() {
return this.position.yRot();
}
public float xRot() {
return this.position.xRot();
}
public CustomEntityType<?> entityType() {
return this.type;
}
protected void saveCustomData(CompoundTag tag) {
}
public void loadCustomData(CompoundTag tag) {
}
private void saveId(CompoundTag tag) {
tag.putString("id", this.type.id().asString());
}
public void destroy() {
this.valid = false;
}
public static UUID readUUID(CompoundTag tag) {
return tag.getUUID("uuid");
}
public static WorldPosition readPos(CEWorld world, CompoundTag tag) {
double x = tag.getDouble("x");
double y = tag.getDouble("y");
double z = tag.getDouble("z");
float xRot = tag.getFloat("x_rot");
float yRot = tag.getFloat("y_rot");
return new WorldPosition(world.world, x, y, z, xRot, yRot);
}
}

View File

@@ -0,0 +1,14 @@
package net.momirealms.craftengine.core.entity;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.world.WorldPosition;
import java.util.UUID;
public record CustomEntityType<T extends CustomEntity>(Key id, Factory<T> factory) {
public interface Factory<T extends CustomEntity> {
T create(UUID uuid, WorldPosition position);
}
}

View File

@@ -0,0 +1,10 @@
package net.momirealms.craftengine.core.entity;
import net.momirealms.craftengine.core.util.Key;
public final class CustomEntityTypeKeys {
private CustomEntityTypeKeys() {}
public static final Key FURNITURE = Key.of("craftengine:furniture");
public static final Key INACTIVE = Key.of("craftengine:inactive");
}

View File

@@ -0,0 +1,18 @@
package net.momirealms.craftengine.core.entity;
import net.momirealms.craftengine.core.registry.BuiltInRegistries;
import net.momirealms.craftengine.core.registry.Registries;
import net.momirealms.craftengine.core.registry.WritableRegistry;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.ResourceKey;
public class CustomEntityTypes {
public static final CustomEntityType<InactiveCustomEntity> INACTIVE = register(CustomEntityTypeKeys.INACTIVE, InactiveCustomEntity::new);
public static <T extends CustomEntity> CustomEntityType<T> register(Key id, CustomEntityType.Factory<T> factory) {
CustomEntityType<T> type = new CustomEntityType<>(id, factory);
((WritableRegistry<CustomEntityType<?>>) BuiltInRegistries.ENTITY_TYPE)
.register(ResourceKey.create(Registries.ENTITY_TYPE.location(), id), type);
return type;
}
}

View File

@@ -0,0 +1,54 @@
package net.momirealms.craftengine.core.entity;
import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.plugin.entityculling.CullingData;
import net.momirealms.craftengine.core.world.WorldPosition;
import net.momirealms.sparrow.nbt.CompoundTag;
import net.momirealms.sparrow.nbt.NBT;
import org.jetbrains.annotations.Nullable;
import java.util.Map;
import java.util.UUID;
public class InactiveCustomEntity extends CustomEntity {
public static final CompoundTag INVALID_TAG = new CompoundTag(Map.of("type", NBT.createString(CustomEntityTypes.INACTIVE.id().asMinimalString())));
private final CompoundTag data;
public InactiveCustomEntity(UUID uuid, WorldPosition position) {
super(CustomEntityTypes.INACTIVE, position, uuid);
this.data = INVALID_TAG;
}
public InactiveCustomEntity(UUID uuid, WorldPosition position, CompoundTag data) {
super(CustomEntityTypes.INACTIVE, position, uuid);
this.data = data;
}
@Override
public CompoundTag saveAsTag() {
return this.data;
}
@Override
public boolean isValid() {
// 不正常的数据不要存储
return this.data != INVALID_TAG;
}
@Override
public void destroy() {
}
@Override
public void show(Player player) {
}
@Override
public void hide(Player player) {
}
@Override
public @Nullable CullingData cullingData() {
return null;
}
}

View File

@@ -1,4 +1,4 @@
package net.momirealms.craftengine.core.entity; package net.momirealms.craftengine.core.entity.display;
public enum Billboard { public enum Billboard {
FIXED(0), FIXED(0),

View File

@@ -1,4 +1,4 @@
package net.momirealms.craftengine.core.entity; package net.momirealms.craftengine.core.entity.display;
public enum ItemDisplayContext { public enum ItemDisplayContext {
NONE(0), NONE(0),

View File

@@ -1,89 +0,0 @@
package net.momirealms.craftengine.core.entity.furniture;
import net.momirealms.craftengine.core.loot.LootTable;
import net.momirealms.craftengine.core.plugin.context.Context;
import net.momirealms.craftengine.core.plugin.context.event.EventTrigger;
import net.momirealms.craftengine.core.plugin.context.function.Function;
import net.momirealms.craftengine.core.util.Key;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
public abstract class AbstractCustomFurniture implements CustomFurniture {
private final Key id;
private final FurnitureSettings settings;
private final Map<AnchorType, Placement> placements;
private final Map<EventTrigger, List<Function<Context>>> events;
@Nullable
private final LootTable<?> lootTable;
private final AnchorType anyType;
protected AbstractCustomFurniture(@NotNull Key id,
@NotNull FurnitureSettings settings,
@NotNull Map<AnchorType, Placement> placements,
@NotNull Map<EventTrigger, List<Function<Context>>> events,
@Nullable LootTable<?> lootTable) {
this.id = id;
this.settings = settings;
this.placements = placements;
this.lootTable = lootTable;
this.events = events;
this.anyType = placements.keySet().stream().findFirst().orElse(null);
}
@Override
public void execute(Context context, EventTrigger trigger) {
for (Function<Context> function : Optional.ofNullable(this.events.get(trigger)).orElse(Collections.emptyList())) {
function.run(context);
}
}
@Override
public Key id() {
return this.id;
}
@Override
public Map<AnchorType, Placement> placements() {
return this.placements;
}
@Override
public FurnitureSettings settings() {
return this.settings;
}
@Override
public @Nullable LootTable<?> lootTable() {
return this.lootTable;
}
@Override
public AnchorType getAnyAnchorType() {
return this.anyType;
}
@Override
public boolean isAllowedPlacement(AnchorType anchorType) {
return this.placements.containsKey(anchorType);
}
@Override
public Placement getPlacement(AnchorType anchorType) {
return this.placements.get(anchorType);
}
@Override
public Placement getValidPlacement(AnchorType anchorType) {
Placement placement = this.placements.get(anchorType);
if (placement == null) {
return this.placements.get(getAnyAnchorType());
}
return placement;
}
}

View File

@@ -1,92 +0,0 @@
package net.momirealms.craftengine.core.entity.furniture;
import net.momirealms.craftengine.core.entity.Billboard;
import net.momirealms.craftengine.core.entity.ItemDisplayContext;
import net.momirealms.craftengine.core.util.Key;
import org.joml.Quaternionf;
import org.joml.Vector3f;
public abstract class AbstractFurnitureElement implements FurnitureElement {
private final Key item;
private final Billboard billboard;
private final ItemDisplayContext transform;
private final Vector3f scale;
private final Vector3f translation;
private final Vector3f position;
private final Quaternionf rotation;
private final boolean applyDyedColor;
private final float shadowRadius;
private final float shadowStrength;
public AbstractFurnitureElement(Key item,
Billboard billboard,
ItemDisplayContext transform,
Vector3f scale,
Vector3f translation,
Vector3f position,
Quaternionf rotation,
float shadowRadius,
float shadowStrength,
boolean applyDyedColor) {
this.billboard = billboard;
this.transform = transform;
this.scale = scale;
this.translation = translation;
this.item = item;
this.rotation = rotation;
this.position = position;
this.applyDyedColor = applyDyedColor;
this.shadowRadius = shadowRadius;
this.shadowStrength = shadowStrength;
}
@Override
public float shadowRadius() {
return shadowRadius;
}
@Override
public float shadowStrength() {
return shadowStrength;
}
@Override
public boolean applyDyedColor() {
return applyDyedColor;
}
@Override
public Quaternionf rotation() {
return rotation;
}
@Override
public Key item() {
return item;
}
@Override
public Billboard billboard() {
return billboard;
}
@Override
public ItemDisplayContext transform() {
return transform;
}
@Override
public Vector3f scale() {
return scale;
}
@Override
public Vector3f translation() {
return translation;
}
@Override
public Vector3f position() {
return position;
}
}

View File

@@ -1,19 +1,24 @@
package net.momirealms.craftengine.core.entity.furniture; package net.momirealms.craftengine.core.entity.furniture;
import net.momirealms.craftengine.core.entity.Billboard; import net.momirealms.craftengine.core.entity.furniture.element.FurnitureElementConfig;
import net.momirealms.craftengine.core.entity.ItemDisplayContext; import net.momirealms.craftengine.core.entity.furniture.element.FurnitureElementConfigs;
import net.momirealms.craftengine.core.entity.furniture.hitbox.HitBoxConfig;
import net.momirealms.craftengine.core.entity.furniture.hitbox.HitBoxTypes;
import net.momirealms.craftengine.core.loot.LootTable; import net.momirealms.craftengine.core.loot.LootTable;
import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.LoadingSequence;
import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.pack.Pack;
import net.momirealms.craftengine.core.pack.PendingConfigSection; import net.momirealms.craftengine.core.pack.PendingConfigSection;
import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.config.Config;
import net.momirealms.craftengine.core.plugin.config.IdSectionConfigParser; import net.momirealms.craftengine.core.plugin.config.IdSectionConfigParser;
import net.momirealms.craftengine.core.plugin.context.event.EventFunctions; import net.momirealms.craftengine.core.plugin.context.event.EventFunctions;
import net.momirealms.craftengine.core.plugin.entityculling.CullingData;
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
import net.momirealms.craftengine.core.util.GsonHelper; import net.momirealms.craftengine.core.util.GsonHelper;
import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.MiscUtils;
import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import net.momirealms.craftengine.core.world.collision.AABB;
import org.incendo.cloud.suggestion.Suggestion; import org.incendo.cloud.suggestion.Suggestion;
import org.joml.Vector3f; import org.joml.Vector3f;
@@ -21,7 +26,7 @@ import java.nio.file.Path;
import java.util.*; import java.util.*;
public abstract class AbstractFurnitureManager implements FurnitureManager { public abstract class AbstractFurnitureManager implements FurnitureManager {
protected final Map<Key, CustomFurniture> byId = new HashMap<>(); protected final Map<Key, FurnitureConfig> byId = new HashMap<>();
private final CraftEngine plugin; private final CraftEngine plugin;
private final FurnitureParser furnitureParser; private final FurnitureParser furnitureParser;
// Cached command suggestions // Cached command suggestions
@@ -56,12 +61,12 @@ public abstract class AbstractFurnitureManager implements FurnitureManager {
} }
@Override @Override
public Optional<CustomFurniture> furnitureById(Key id) { public Optional<FurnitureConfig> furnitureById(Key id) {
return Optional.ofNullable(this.byId.get(id)); return Optional.ofNullable(this.byId.get(id));
} }
@Override @Override
public Map<Key, CustomFurniture> loadedFurniture() { public Map<Key, FurnitureConfig> loadedFurniture() {
return Collections.unmodifiableMap(this.byId); return Collections.unmodifiableMap(this.byId);
} }
@@ -72,10 +77,6 @@ public abstract class AbstractFurnitureManager implements FurnitureManager {
protected abstract HitBoxConfig defaultHitBox(); protected abstract HitBoxConfig defaultHitBox();
protected abstract FurnitureElement.Builder furnitureElementBuilder();
protected abstract CustomFurniture.Builder furnitureBuilder();
public class FurnitureParser extends IdSectionConfigParser { public class FurnitureParser extends IdSectionConfigParser {
public static final String[] CONFIG_SECTION_NAME = new String[] { "furniture" }; public static final String[] CONFIG_SECTION_NAME = new String[] { "furniture" };
private final List<PendingConfigSection> pendingConfigSections = new ArrayList<>(); private final List<PendingConfigSection> pendingConfigSections = new ArrayList<>();
@@ -107,91 +108,72 @@ public abstract class AbstractFurnitureManager implements FurnitureManager {
return LoadingSequence.FURNITURE; return LoadingSequence.FURNITURE;
} }
@SuppressWarnings("unchecked")
@Override @Override
public void parseSection(Pack pack, Path path, String node, Key id, Map<String, Object> section) { public void parseSection(Pack pack, Path path, String node, Key id, Map<String, Object> section) {
if (AbstractFurnitureManager.this.byId.containsKey(id)) { if (AbstractFurnitureManager.this.byId.containsKey(id)) {
throw new LocalizedResourceConfigException("warning.config.furniture.duplicate"); throw new LocalizedResourceConfigException("warning.config.furniture.duplicate");
} }
EnumMap<AnchorType, CustomFurniture.Placement> placements = new EnumMap<>(AnchorType.class);
Object placementObj = section.get("placement");
Map<String, Object> placementMap = MiscUtils.castToMap(ResourceConfigUtils.requireNonNullOrThrow(placementObj, "warning.config.furniture.missing_placement"), false);
if (placementMap.isEmpty()) {
throw new LocalizedResourceConfigException("warning.config.furniture.missing_placement");
}
for (Map.Entry<String, Object> entry : placementMap.entrySet()) {
// anchor type
AnchorType anchorType = AnchorType.valueOf(entry.getKey().toUpperCase(Locale.ENGLISH));
Map<String, Object> placementArguments = MiscUtils.castToMap(entry.getValue(), false);
Optional<Vector3f> optionalLootSpawnOffset = Optional.ofNullable(placementArguments.get("loot-spawn-offset")).map(it -> ResourceConfigUtils.getAsVector3f(it, "loot-spawn-offset"));
// furniture display elements
List<FurnitureElement> elements = new ArrayList<>();
List<Map<String, Object>> elementConfigs = (List<Map<String, Object>>) placementArguments.getOrDefault("elements", List.of());
for (Map<String, Object> element : elementConfigs) {
FurnitureElement furnitureElement = furnitureElementBuilder()
.item(Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(element.get("item"), "warning.config.furniture.element.missing_item")))
.applyDyedColor(ResourceConfigUtils.getAsBoolean(element.getOrDefault("apply-dyed-color", true), "apply-dyed-color"))
.billboard(ResourceConfigUtils.getOrDefault(element.get("billboard"), o -> Billboard.valueOf(o.toString().toUpperCase(Locale.ENGLISH)), Billboard.FIXED))
.transform(ResourceConfigUtils.getOrDefault(ResourceConfigUtils.get(element, "transform", "display-transform"), o -> ItemDisplayContext.valueOf(o.toString().toUpperCase(Locale.ENGLISH)), ItemDisplayContext.NONE))
.scale(ResourceConfigUtils.getAsVector3f(element.getOrDefault("scale", "1"), "scale"))
.position(ResourceConfigUtils.getAsVector3f(element.getOrDefault("position", "0"), "position"))
.translation(ResourceConfigUtils.getAsVector3f(element.getOrDefault("translation", "0"), "translation"))
.rotation(ResourceConfigUtils.getAsQuaternionf(element.getOrDefault("rotation", "0"), "rotation"))
.shadowRadius(ResourceConfigUtils.getAsFloat(element.getOrDefault("shadow-radius", 0f), "shadow-radius"))
.shadowStrength(ResourceConfigUtils.getAsFloat(element.getOrDefault("shadow-strength", 1f), "shadow-strength"))
.build();
elements.add(furnitureElement);
}
// external model providers Map<String, Object> variantsMap = ResourceConfigUtils.getAsMap(ResourceConfigUtils.requireNonNullOrThrow(ResourceConfigUtils.get(section, "variants", "placement", "variant"), "warning.config.furniture.missing_variants"), "variants");
if (variantsMap.isEmpty()) {
throw new LocalizedResourceConfigException("warning.config.furniture.missing_variants");
}
Map<String, FurnitureVariant> variants = new HashMap<>();
for (Map.Entry<String, Object> e0 : variantsMap.entrySet()) {
String variantName = e0.getKey();
Map<String, Object> variantArguments = ResourceConfigUtils.getAsMap(e0.getValue(), variantName);
Optional<Vector3f> optionalLootSpawnOffset = Optional.ofNullable(variantArguments.get("loot-spawn-offset")).map(it -> ResourceConfigUtils.getAsVector3f(it, "loot-spawn-offset"));
List<FurnitureElementConfig<?>> elements = ResourceConfigUtils.parseConfigAsList(variantArguments.get("elements"), FurnitureElementConfigs::fromMap);
// fixme 外部模型不应该在这
Optional<ExternalModel> externalModel; Optional<ExternalModel> externalModel;
if (placementArguments.containsKey("model-engine")) { if (variantArguments.containsKey("model-engine")) {
externalModel = Optional.of(plugin.compatibilityManager().createModel("ModelEngine", placementArguments.get("model-engine").toString())); externalModel = Optional.of(plugin.compatibilityManager().createModel("ModelEngine", variantArguments.get("model-engine").toString()));
} else if (placementArguments.containsKey("better-model")) { } else if (variantArguments.containsKey("better-model")) {
externalModel = Optional.of(plugin.compatibilityManager().createModel("BetterModel", placementArguments.get("better-model").toString())); externalModel = Optional.of(plugin.compatibilityManager().createModel("BetterModel", variantArguments.get("better-model").toString()));
} else { } else {
externalModel = Optional.empty(); externalModel = Optional.empty();
} }
// add hitboxes List<HitBoxConfig> hitboxes = ResourceConfigUtils.parseConfigAsList(variantArguments.get("hitboxes"), HitBoxTypes::fromMap);
List<HitBoxConfig> hitboxes = ResourceConfigUtils.parseConfigAsList(placementArguments.get("hitboxes"), HitBoxTypes::fromMap);
if (hitboxes.isEmpty() && externalModel.isEmpty()) { if (hitboxes.isEmpty() && externalModel.isEmpty()) {
hitboxes = List.of(defaultHitBox()); hitboxes = List.of(defaultHitBox());
} }
// rules variants.put(variantName, new FurnitureVariant(
Map<String, Object> ruleSection = MiscUtils.castToMap(placementArguments.get("rules"), true); elements.toArray(new FurnitureElementConfig[0]),
if (ruleSection != null) { hitboxes.toArray(new HitBoxConfig[0]),
placements.put(anchorType, new CustomFurniture.Placement( externalModel,
anchorType, optionalLootSpawnOffset
elements.toArray(new FurnitureElement[0]), ));
hitboxes.toArray(new HitBoxConfig[0]),
ResourceConfigUtils.getOrDefault(ruleSection.get("rotation"), o -> RotationRule.valueOf(o.toString().toUpperCase(Locale.ENGLISH)), RotationRule.ANY),
ResourceConfigUtils.getOrDefault(ruleSection.get("alignment"), o -> AlignmentRule.valueOf(o.toString().toUpperCase(Locale.ENGLISH)), AlignmentRule.CENTER),
externalModel,
optionalLootSpawnOffset
));
} else {
placements.put(anchorType, new CustomFurniture.Placement(
anchorType,
elements.toArray(new FurnitureElement[0]),
hitboxes.toArray(new HitBoxConfig[0]),
RotationRule.ANY,
AlignmentRule.CENTER,
externalModel,
optionalLootSpawnOffset
));
}
} }
CustomFurniture furniture = furnitureBuilder() AABB maxAABB = null;
FurnitureConfig furniture = FurnitureConfig.builder()
.id(id) .id(id)
.settings(FurnitureSettings.fromMap(MiscUtils.castToMap(section.get("settings"), true))) .settings(FurnitureSettings.fromMap(MiscUtils.castToMap(section.get("settings"), true)))
.placement(placements) .variants(variants)
.events(EventFunctions.parseEvents(ResourceConfigUtils.get(section, "events", "event"))) .events(EventFunctions.parseEvents(ResourceConfigUtils.get(section, "events", "event")))
.lootTable(LootTable.fromMap(MiscUtils.castToMap(section.get("loot"), true))) .lootTable(LootTable.fromMap(MiscUtils.castToMap(section.get("loot"), true)))
.cullingData(parseCullingData(section.get("entity-culling"), maxAABB))
.build(); .build();
AbstractFurnitureManager.this.byId.put(id, furniture); AbstractFurnitureManager.this.byId.put(id, furniture);
} }
private CullingData parseCullingData(Object arguments, AABB maxHitbox) {
if (arguments instanceof Boolean b && !b)
return null;
if (!(arguments instanceof Map))
return new CullingData(maxHitbox, Config.entityCullingViewDistance(), 0.5, true);
Map<String, Object> argumentsMap = ResourceConfigUtils.getAsMap(arguments, "entity-culling");
return new CullingData(
ResourceConfigUtils.getAsAABB(argumentsMap.getOrDefault("aabb", maxHitbox), "aabb"),
ResourceConfigUtils.getAsInt(argumentsMap.getOrDefault("view-distance", Config.entityCullingViewDistance()), "view-distance"),
ResourceConfigUtils.getAsDouble(argumentsMap.getOrDefault("aabb-expansion", 0.5), "aabb-expansion"),
ResourceConfigUtils.getAsBoolean(argumentsMap.getOrDefault("ray-tracing", true), "ray-tracing")
);
}
} }
} }

View File

@@ -1,5 +1,6 @@
package net.momirealms.craftengine.core.entity.furniture; package net.momirealms.craftengine.core.entity.furniture;
@Deprecated(since = "0.0.66", forRemoval = true)
public enum AnchorType { public enum AnchorType {
GROUND(0), GROUND(0),
WALL(1), WALL(1),

View File

@@ -1,60 +0,0 @@
package net.momirealms.craftengine.core.entity.furniture;
import net.momirealms.craftengine.core.loot.LootTable;
import net.momirealms.craftengine.core.plugin.context.Context;
import net.momirealms.craftengine.core.plugin.context.event.EventTrigger;
import net.momirealms.craftengine.core.plugin.context.function.Function;
import net.momirealms.craftengine.core.util.Key;
import org.jetbrains.annotations.Nullable;
import org.joml.Vector3f;
import java.util.List;
import java.util.Map;
import java.util.Optional;
// TODO 家具的设计存在问题。家具也应该存在不同的状态,而不是根据放置规则直接决定状态类型
public interface CustomFurniture {
void execute(Context context, EventTrigger trigger);
Key id();
Map<AnchorType, Placement> placements();
FurnitureSettings settings();
@Nullable
LootTable<?> lootTable();
AnchorType getAnyAnchorType();
boolean isAllowedPlacement(AnchorType anchorType);
Placement getPlacement(AnchorType anchorType);
Placement getValidPlacement(AnchorType anchorType);
interface Builder {
Builder id(Key id);
Builder placement(Map<AnchorType, Placement> placements);
Builder settings(FurnitureSettings settings);
Builder lootTable(LootTable<?> lootTable);
Builder events(Map<EventTrigger, List<Function<Context>>> events);
CustomFurniture build();
}
record Placement(AnchorType anchorType,
FurnitureElement[] elements,
HitBoxConfig[] hitBoxConfigs,
RotationRule rotationRule,
AlignmentRule alignmentRule,
Optional<ExternalModel> externalModel,
Optional<Vector3f> dropOffset) {
}
}

View File

@@ -1,48 +1,28 @@
package net.momirealms.craftengine.core.entity.furniture; package net.momirealms.craftengine.core.entity.furniture;
import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.entity.CustomEntity;
import net.momirealms.craftengine.core.entity.CustomEntityType;
import net.momirealms.craftengine.core.world.WorldPosition; import net.momirealms.craftengine.core.world.WorldPosition;
import net.momirealms.sparrow.nbt.CompoundTag;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.UUID; public abstract class Furniture extends CustomEntity {
protected final FurnitureConfig config;
protected final FurnitureDataAccessor dataAccessor;
public interface Furniture { public Furniture(CustomEntityType<?> type, WorldPosition position, FurnitureConfig config, CompoundTag data) {
void initializeColliders(); super(type, position);
this.dataAccessor = new FurnitureDataAccessor(data);
WorldPosition position(); this.config = config;
}
boolean isValid();
void destroy();
void destroyColliders();
void destroySeats();
UUID uuid();
int baseEntityId();
@Nullable
HitBox hitBoxByEntityId(int id);
@Nullable HitBoxPart hitBoxPartByEntityId(int id);
@NotNull @NotNull
AnchorType anchorType(); public FurnitureConfig config() {
return this.config;
}
@NotNull @NotNull
Key id(); public FurnitureDataAccessor dataAccessor() {
return this.dataAccessor;
@NotNull }
CustomFurniture config();
boolean hasExternalModel();
FurnitureExtraData extraData();
void setExtraData(FurnitureExtraData extraData);
void save();
} }

View File

@@ -0,0 +1,67 @@
package net.momirealms.craftengine.core.entity.furniture;
import net.momirealms.craftengine.core.entity.furniture.behavior.FurnitureBehavior;
import net.momirealms.craftengine.core.loot.LootTable;
import net.momirealms.craftengine.core.plugin.context.Context;
import net.momirealms.craftengine.core.plugin.context.event.EventTrigger;
import net.momirealms.craftengine.core.plugin.context.function.Function;
import net.momirealms.craftengine.core.plugin.entityculling.CullingData;
import net.momirealms.craftengine.core.util.Key;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Map;
public interface FurnitureConfig {
void execute(Context context, EventTrigger trigger);
Key id();
FurnitureSettings settings();
@Nullable
LootTable<?> lootTable();
Map<String, FurnitureVariant> variants();
default FurnitureVariant anyVariant() {
return variants().values().stream().findFirst().get();
}
default String anyVariantName() {
return variants().keySet().stream().findFirst().get();
}
@Nullable
FurnitureVariant getVariant(String variantName);
@NotNull
FurnitureBehavior behavior();
CullingData cullingData();
static Builder builder() {
return new FurnitureConfigImpl.BuilderImpl();
}
interface Builder {
Builder id(Key id);
Builder variants(Map<String, FurnitureVariant> variants);
Builder settings(FurnitureSettings settings);
Builder lootTable(LootTable<?> lootTable);
Builder events(Map<EventTrigger, List<Function<Context>>> events);
Builder behavior(FurnitureBehavior behavior);
Builder cullingData(CullingData cullingData);
FurnitureConfig build();
}
}

View File

@@ -0,0 +1,145 @@
package net.momirealms.craftengine.core.entity.furniture;
import com.google.common.collect.ImmutableMap;
import net.momirealms.craftengine.core.entity.furniture.behavior.EmptyFurnitureBehavior;
import net.momirealms.craftengine.core.entity.furniture.behavior.FurnitureBehavior;
import net.momirealms.craftengine.core.loot.LootTable;
import net.momirealms.craftengine.core.plugin.context.Context;
import net.momirealms.craftengine.core.plugin.context.event.EventTrigger;
import net.momirealms.craftengine.core.plugin.context.function.Function;
import net.momirealms.craftengine.core.plugin.entityculling.CullingData;
import net.momirealms.craftengine.core.util.Key;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
class FurnitureConfigImpl implements FurnitureConfig {
private final Key id;
private final FurnitureSettings settings;
private final Map<String, FurnitureVariant> variants;
private final Map<EventTrigger, List<Function<Context>>> events;
private final FurnitureBehavior behavior;
private final CullingData cullingData;
@Nullable
private final LootTable<?> lootTable;
private FurnitureConfigImpl(@NotNull Key id,
@NotNull FurnitureSettings settings,
@NotNull Map<String, FurnitureVariant> variants,
@NotNull Map<EventTrigger, List<Function<Context>>> events,
@NotNull FurnitureBehavior behavior,
@Nullable CullingData cullingData,
@Nullable LootTable<?> lootTable) {
this.id = id;
this.settings = settings;
this.variants = ImmutableMap.copyOf(variants);
this.lootTable = lootTable;
this.behavior = behavior;
this.cullingData = cullingData;
this.events = events;
}
@Override
public void execute(Context context, EventTrigger trigger) {
for (Function<Context> function : Optional.ofNullable(this.events.get(trigger)).orElse(Collections.emptyList())) {
function.run(context);
}
}
@Override
public Key id() {
return this.id;
}
@Override
public FurnitureSettings settings() {
return this.settings;
}
@Override
public @Nullable LootTable<?> lootTable() {
return this.lootTable;
}
@Override
public Map<String, FurnitureVariant> variants() {
return this.variants;
}
@Override
public @NotNull FurnitureBehavior behavior() {
return this.behavior;
}
@Override
public CullingData cullingData() {
return this.cullingData;
}
@Nullable
@Override
public FurnitureVariant getVariant(String variantName) {
return this.variants.get(variantName);
}
public static class BuilderImpl implements Builder {
private Key id;
private Map<String, FurnitureVariant> variants;
private FurnitureSettings settings;
private Map<EventTrigger, List<Function<Context>>> events;
private LootTable<?> lootTable;
private FurnitureBehavior behavior = EmptyFurnitureBehavior.INSTANCE;
private CullingData cullingData;
@Override
public FurnitureConfig build() {
return new FurnitureConfigImpl(this.id, this.settings, this.variants, this.events, this.behavior, this.cullingData, this.lootTable);
}
@Override
public Builder id(Key id) {
this.id = id;
return this;
}
@Override
public Builder variants(Map<String, FurnitureVariant> variants) {
this.variants = variants;
return this;
}
@Override
public Builder settings(FurnitureSettings settings) {
this.settings = settings;
return this;
}
@Override
public Builder lootTable(LootTable<?> lootTable) {
this.lootTable = lootTable;
return this;
}
@Override
public Builder events(Map<EventTrigger, List<Function<Context>>> events) {
this.events = events;
return this;
}
@Override
public Builder cullingData(CullingData cullingData) {
this.cullingData = cullingData;
return this;
}
@Override
public Builder behavior(FurnitureBehavior behavior) {
this.behavior = behavior;
return this;
}
}
}

View File

@@ -6,34 +6,53 @@ import net.momirealms.craftengine.core.plugin.logger.Debugger;
import net.momirealms.craftengine.core.util.Color; import net.momirealms.craftengine.core.util.Color;
import net.momirealms.sparrow.nbt.CompoundTag; import net.momirealms.sparrow.nbt.CompoundTag;
import net.momirealms.sparrow.nbt.NBT; import net.momirealms.sparrow.nbt.NBT;
import net.momirealms.sparrow.nbt.Tag;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
import java.io.IOException; import java.io.IOException;
import java.util.Optional; import java.util.Optional;
public class FurnitureExtraData { public class FurnitureDataAccessor {
public static final String ITEM = "item"; public static final String ITEM = "item";
public static final String DYED_COLOR = "dyed_color"; public static final String DYED_COLOR = "dyed_color";
public static final String FIREWORK_EXPLOSION_COLORS = "firework_explosion_colors"; public static final String FIREWORK_EXPLOSION_COLORS = "firework_explosion_colors";
public static final String VARIANT = "variant";
@ApiStatus.Obsolete
public static final String ANCHOR_TYPE = "anchor_type"; public static final String ANCHOR_TYPE = "anchor_type";
private final CompoundTag data; private final CompoundTag data;
public FurnitureExtraData(CompoundTag data) { public FurnitureDataAccessor(CompoundTag data) {
this.data = data; this.data = data;
} }
public static FurnitureExtraData of(CompoundTag data) { public static FurnitureDataAccessor of(CompoundTag data) {
return new FurnitureExtraData(data); return new FurnitureDataAccessor(data);
} }
public CompoundTag copyTag() { public CompoundTag copyTag() {
return this.data.copy(); return this.data.copy();
} }
@ApiStatus.Internal
public CompoundTag unsafeTag() { public CompoundTag unsafeTag() {
return this.data; return this.data;
} }
public void addCustomData(String key, Tag value) {
this.data.put(key, value);
}
@Nullable
public Tag getCustomData(String key) {
return this.data.get(key);
}
public void removeCustomData(String key) {
this.data.remove(key);
}
public Optional<Item<?>> item() { public Optional<Item<?>> item() {
byte[] data = this.data.getByteArray(ITEM); byte[] data = this.data.getByteArray(ITEM);
if (data == null) return Optional.empty(); if (data == null) return Optional.empty();
@@ -45,73 +64,57 @@ public class FurnitureExtraData {
} }
} }
public void setItem(Item<?> item) {
this.data.putByteArray(ITEM, item.toByteArray());
}
public Optional<int[]> fireworkExplosionColors() { public Optional<int[]> fireworkExplosionColors() {
if (this.data.containsKey(FIREWORK_EXPLOSION_COLORS)) return Optional.of(this.data.getIntArray(FIREWORK_EXPLOSION_COLORS)); if (this.data.containsKey(FIREWORK_EXPLOSION_COLORS)) return Optional.of(this.data.getIntArray(FIREWORK_EXPLOSION_COLORS));
return Optional.empty(); return Optional.empty();
} }
public void setFireworkExplosionColors(int[] colors) {
this.data.putIntArray(FIREWORK_EXPLOSION_COLORS, colors);
}
public Optional<Color> dyedColor() { public Optional<Color> dyedColor() {
if (this.data.containsKey(DYED_COLOR)) return Optional.of(Color.fromDecimal(this.data.getInt(DYED_COLOR))); if (this.data.containsKey(DYED_COLOR)) return Optional.of(Color.fromDecimal(this.data.getInt(DYED_COLOR)));
return Optional.empty(); return Optional.empty();
} }
public void setDyedColor(Color color) {
this.data.putInt(DYED_COLOR, color.color());
}
public Optional<String> variant() {
return Optional.ofNullable(this.data.getString(VARIANT));
}
public void setVariant(String variant) {
this.data.putString(VARIANT, variant);
}
@ApiStatus.Obsolete
public Optional<AnchorType> anchorType() { public Optional<AnchorType> anchorType() {
if (this.data.containsKey(ANCHOR_TYPE)) return Optional.of(AnchorType.byId(this.data.getInt(ANCHOR_TYPE))); if (this.data.containsKey(ANCHOR_TYPE)) return Optional.of(AnchorType.byId(this.data.getInt(ANCHOR_TYPE)));
return Optional.empty(); return Optional.empty();
} }
public FurnitureExtraData anchorType(AnchorType type) { @ApiStatus.Obsolete
public FurnitureDataAccessor anchorType(AnchorType type) {
this.data.putInt(ANCHOR_TYPE, type.getId()); this.data.putInt(ANCHOR_TYPE, type.getId());
return this; return this;
} }
public static Builder builder() { public static FurnitureDataAccessor fromBytes(final byte[] data) throws IOException {
return new Builder(); return new FurnitureDataAccessor(NBT.fromBytes(data));
} }
public static FurnitureExtraData fromBytes(final byte[] data) throws IOException { public static byte[] toBytes(final FurnitureDataAccessor data) throws IOException {
return new FurnitureExtraData(NBT.fromBytes(data));
}
public static byte[] toBytes(final FurnitureExtraData data) throws IOException {
return NBT.toBytes(data.data); return NBT.toBytes(data.data);
} }
public byte[] toBytes() throws IOException { public byte[] toBytes() throws IOException {
return toBytes(this); return toBytes(this);
} }
public static class Builder {
private final CompoundTag data;
public Builder() {
this.data = new CompoundTag();
}
public Builder item(Item<?> item) {
this.data.putByteArray(ITEM, item.toByteArray());
return this;
}
public Builder dyedColor(Color color) {
if (color == null) return this;
this.data.putInt(DYED_COLOR, color.color());
return this;
}
public Builder fireworkExplosionColors(int[] colors) {
if (colors == null) return this;
this.data.putIntArray(FIREWORK_EXPLOSION_COLORS, colors);
return this;
}
public Builder anchorType(AnchorType type) {
this.data.putInt(ANCHOR_TYPE, type.getId());
return this;
}
public FurnitureExtraData build() {
return new FurnitureExtraData(data);
}
}
} }

View File

@@ -1,59 +0,0 @@
package net.momirealms.craftengine.core.entity.furniture;
import net.momirealms.craftengine.core.entity.Billboard;
import net.momirealms.craftengine.core.entity.ItemDisplayContext;
import net.momirealms.craftengine.core.util.Key;
import org.jetbrains.annotations.NotNull;
import org.joml.Quaternionf;
import org.joml.Vector3f;
import java.util.function.Consumer;
public interface FurnitureElement {
Quaternionf rotation();
Key item();
Billboard billboard();
ItemDisplayContext transform();
float shadowRadius();
float shadowStrength();
boolean applyDyedColor();
Vector3f scale();
Vector3f translation();
Vector3f position();
void initPackets(Furniture furniture, int entityId, @NotNull Quaternionf conjugated, Consumer<Object> packets);
interface Builder {
Builder item(Key item);
Builder billboard(Billboard billboard);
Builder transform(ItemDisplayContext transform);
Builder scale(Vector3f scale);
Builder translation(Vector3f translation);
Builder position(Vector3f position);
Builder rotation(Quaternionf rotation);
Builder applyDyedColor(boolean applyDyedColor);
Builder shadowStrength(float shadowStrength);
Builder shadowRadius(float shadowRadius);
FurnitureElement build();
}
}

View File

@@ -25,11 +25,11 @@ public interface FurnitureManager extends Manageable {
Collection<Suggestion> cachedSuggestions(); Collection<Suggestion> cachedSuggestions();
Furniture place(WorldPosition position, CustomFurniture furniture, FurnitureExtraData extraData, boolean playSound); Furniture place(WorldPosition position, FurnitureConfig furniture, FurnitureDataAccessor extraData, boolean playSound);
Optional<CustomFurniture> furnitureById(Key id); Optional<FurnitureConfig> furnitureById(Key id);
Map<Key, CustomFurniture> loadedFurniture(); Map<Key, FurnitureConfig> loadedFurniture();
boolean isFurnitureRealEntity(int entityId); boolean isFurnitureRealEntity(int entityId);

View File

@@ -1,11 +1,13 @@
package net.momirealms.craftengine.core.entity.furniture; package net.momirealms.craftengine.core.entity.furniture;
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
import net.momirealms.craftengine.core.util.CustomDataType;
import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.MiscUtils;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.HashMap; import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Map; import java.util.Map;
public class FurnitureSettings { public class FurnitureSettings {
@@ -13,6 +15,7 @@ public class FurnitureSettings {
FurnitureSounds sounds = FurnitureSounds.EMPTY; FurnitureSounds sounds = FurnitureSounds.EMPTY;
@Nullable @Nullable
Key itemId; Key itemId;
Map<CustomDataType<?>, Object> customData = new IdentityHashMap<>(4);
private FurnitureSettings() {} private FurnitureSettings() {}
@@ -29,6 +32,7 @@ public class FurnitureSettings {
newSettings.sounds = settings.sounds; newSettings.sounds = settings.sounds;
newSettings.itemId = settings.itemId; newSettings.itemId = settings.itemId;
newSettings.minimized = settings.minimized; newSettings.minimized = settings.minimized;
newSettings.customData = new IdentityHashMap<>(settings.customData);
return newSettings; return newSettings;
} }
@@ -45,6 +49,25 @@ public class FurnitureSettings {
return settings; return settings;
} }
@SuppressWarnings("unchecked")
public <T> T getCustomData(CustomDataType<T> type) {
return (T) this.customData.get(type);
}
public void clearCustomData() {
this.customData.clear();
}
@Nullable
@SuppressWarnings("unchecked")
public <T> T removeCustomData(CustomDataType<?> type) {
return (T) this.customData.remove(type);
}
public <T> void addCustomData(CustomDataType<T> key, T value) {
this.customData.put(key, value);
}
public FurnitureSounds sounds() { public FurnitureSounds sounds() {
return sounds; return sounds;
} }
@@ -103,7 +126,7 @@ public class FurnitureSettings {
})); }));
} }
private static void registerFactory(String id, FurnitureSettings.Modifier.Factory factory) { public static void registerFactory(String id, FurnitureSettings.Modifier.Factory factory) {
FACTORIES.put(id, factory); FACTORIES.put(id, factory);
} }
} }

View File

@@ -0,0 +1,13 @@
package net.momirealms.craftengine.core.entity.furniture;
import net.momirealms.craftengine.core.entity.furniture.element.FurnitureElementConfig;
import net.momirealms.craftengine.core.entity.furniture.hitbox.HitBoxConfig;
import org.joml.Vector3f;
import java.util.Optional;
public record FurnitureVariant(FurnitureElementConfig<?>[] elements,
HitBoxConfig[] hitBoxConfigs,
Optional<ExternalModel> externalModel,
Optional<Vector3f> dropOffset) {
}

View File

@@ -1,34 +0,0 @@
package net.momirealms.craftengine.core.entity.furniture;
import net.momirealms.craftengine.core.entity.seat.SeatConfig;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.world.WorldPosition;
import net.momirealms.craftengine.core.world.collision.AABB;
import org.joml.Quaternionf;
import org.joml.Vector3f;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Supplier;
public interface HitBoxConfig {
Key type();
void initPacketsAndColliders(int[] entityId, WorldPosition position, Quaternionf conjugated,
BiConsumer<Object, Boolean> packets, Consumer<Collider> collider, Consumer<HitBoxPart> aabb);
void initShapeForPlacement(double x, double y, double z, float yaw, Quaternionf conjugated, Consumer<AABB> aabbs);
int[] acquireEntityIds(Supplier<Integer> entityIdSupplier);
SeatConfig[] seats();
Vector3f position();
boolean blocksBuilding();
boolean canBeHitByProjectile();
boolean canUseItemOn();
}

View File

@@ -0,0 +1,7 @@
package net.momirealms.craftengine.core.entity.furniture.behavior;
public final class EmptyFurnitureBehavior implements FurnitureBehavior {
private EmptyFurnitureBehavior() {}
public static final EmptyFurnitureBehavior INSTANCE = new EmptyFurnitureBehavior();
}

View File

@@ -0,0 +1,15 @@
package net.momirealms.craftengine.core.entity.furniture.behavior;
import net.momirealms.craftengine.core.entity.furniture.Furniture;
import net.momirealms.craftengine.core.entity.furniture.tick.FurnitureTicker;
public interface FurnitureBehavior {
default <T extends Furniture> FurnitureTicker<T> createSyncFurnitureTicker(T furniture) {
return null;
}
default <T extends Furniture> FurnitureTicker<T> createAsyncBlockEntityTicker(T furniture) {
return null;
}
}

View File

@@ -0,0 +1,14 @@
package net.momirealms.craftengine.core.entity.furniture.element;
import net.momirealms.craftengine.core.entity.player.Player;
public interface FurnitureElement {
void show(Player player);
void hide(Player player);
default void deactivate() {}
default void activate() {}
}

View File

@@ -0,0 +1,9 @@
package net.momirealms.craftengine.core.entity.furniture.element;
import net.momirealms.craftengine.core.world.WorldPosition;
import org.jetbrains.annotations.NotNull;
public interface FurnitureElementConfig<E extends FurnitureElement> {
E create(@NotNull WorldPosition position);
}

View File

@@ -0,0 +1,8 @@
package net.momirealms.craftengine.core.entity.furniture.element;
import java.util.Map;
public interface FurnitureElementConfigFactory {
<E extends FurnitureElement> FurnitureElementConfig<E> create(Map<String, Object> args);
}

View File

@@ -0,0 +1,31 @@
package net.momirealms.craftengine.core.entity.furniture.element;
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
import net.momirealms.craftengine.core.registry.BuiltInRegistries;
import net.momirealms.craftengine.core.registry.Registries;
import net.momirealms.craftengine.core.registry.WritableRegistry;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.ResourceKey;
import java.util.Map;
import java.util.Optional;
public class FurnitureElementConfigs {
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, FurnitureElementConfigFactory type) {
((WritableRegistry<FurnitureElementConfigFactory>) BuiltInRegistries.FURNITURE_ELEMENT_TYPE)
.register(ResourceKey.create(Registries.FURNITURE_ELEMENT_TYPE.location(), key), type);
}
public static <E extends FurnitureElement> FurnitureElementConfig<E> fromMap(Map<String, Object> arguments) {
Key type = Optional.ofNullable(arguments.get("type")).map(String::valueOf).map(it -> Key.withDefaultNamespace(it, "craftengine")).orElse(ITEM_DISPLAY);
FurnitureElementConfigFactory factory = BuiltInRegistries.FURNITURE_ELEMENT_TYPE.getValue(type);
if (factory == null) {
throw new LocalizedResourceConfigException("warning.config.furniture.element.invalid_type", type.toString());
}
return factory.create(arguments);
}
}

View File

@@ -1,40 +1,26 @@
package net.momirealms.craftengine.bukkit.entity.furniture; package net.momirealms.craftengine.core.entity.furniture.hitbox;
import net.momirealms.craftengine.bukkit.entity.seat.BukkitSeat;
import net.momirealms.craftengine.core.entity.furniture.Furniture; import net.momirealms.craftengine.core.entity.furniture.Furniture;
import net.momirealms.craftengine.core.entity.furniture.HitBox;
import net.momirealms.craftengine.core.entity.furniture.HitBoxConfig;
import net.momirealms.craftengine.core.entity.furniture.HitBoxPart;
import net.momirealms.craftengine.core.entity.seat.Seat; import net.momirealms.craftengine.core.entity.seat.Seat;
import net.momirealms.craftengine.core.entity.seat.SeatConfig;
import net.momirealms.craftengine.core.world.EntityHitResult; import net.momirealms.craftengine.core.world.EntityHitResult;
import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.core.world.Vec3d;
import net.momirealms.sparrow.nbt.CompoundTag; import net.momirealms.sparrow.nbt.CompoundTag;
import java.util.Optional; import java.util.Optional;
public class BukkitHitBox implements HitBox { public abstract class AbstractHitBox implements HitBox {
private final Furniture furniture; private final Furniture furniture;
private final HitBoxConfig config; private final HitBoxConfig config;
private final HitBoxPart[] parts; private final HitBoxPart[] parts;
private final Seat<HitBox>[] seats; private Seat<HitBox>[] seats;
public BukkitHitBox(Furniture furniture, HitBoxConfig config, HitBoxPart[] parts) { public AbstractHitBox(Furniture furniture, HitBoxConfig config, HitBoxPart[] parts) {
this.parts = parts; this.parts = parts;
this.config = config; this.config = config;
this.furniture = furniture; this.furniture = furniture;
this.seats = createSeats(config);
} }
@SuppressWarnings("unchecked") protected abstract void createSeats(HitBoxConfig config);
private Seat<HitBox>[] createSeats(HitBoxConfig config) {
SeatConfig[] seatConfigs = config.seats();
Seat<HitBox>[] seats = new Seat[seatConfigs.length];
for (int i = 0; i < seatConfigs.length; i++) {
seats[i] = new BukkitSeat<>(this, seatConfigs[i]);
}
return seats;
}
@Override @Override
public HitBoxPart[] parts() { public HitBoxPart[] parts() {
@@ -65,6 +51,6 @@ public class BukkitHitBox implements HitBox {
@Override @Override
public void saveCustomData(CompoundTag data) { public void saveCustomData(CompoundTag data) {
data.putString("type", "furniture"); data.putString("type", "furniture");
data.putInt("entity_id", this.furniture.baseEntityId()); data.putInt("entity_id", this.furniture.entityId());
} }
} }

View File

@@ -1,4 +1,4 @@
package net.momirealms.craftengine.core.entity.furniture; package net.momirealms.craftengine.core.entity.furniture.hitbox;
import net.momirealms.craftengine.core.entity.seat.SeatConfig; import net.momirealms.craftengine.core.entity.seat.SeatConfig;
import org.joml.Vector3f; import org.joml.Vector3f;
@@ -30,16 +30,16 @@ public abstract class AbstractHitBoxConfig implements HitBoxConfig {
@Override @Override
public boolean blocksBuilding() { public boolean blocksBuilding() {
return blocksBuilding; return this.blocksBuilding;
} }
@Override @Override
public boolean canBeHitByProjectile() { public boolean canBeHitByProjectile() {
return canBeHitByProjectile; return this.canBeHitByProjectile;
} }
@Override @Override
public boolean canUseItemOn() { public boolean canUseItemOn() {
return canUseItemOn; return this.canUseItemOn;
} }
} }

View File

@@ -1,4 +1,4 @@
package net.momirealms.craftengine.core.entity.furniture; package net.momirealms.craftengine.core.entity.furniture.hitbox;
import net.momirealms.craftengine.core.entity.seat.Seat; import net.momirealms.craftengine.core.entity.seat.Seat;
import net.momirealms.craftengine.core.entity.seat.SeatOwner; import net.momirealms.craftengine.core.entity.seat.SeatOwner;

View File

@@ -0,0 +1,20 @@
package net.momirealms.craftengine.core.entity.furniture.hitbox;
import net.momirealms.craftengine.core.entity.seat.SeatConfig;
import net.momirealms.craftengine.core.util.Key;
import org.joml.Vector3f;
public interface HitBoxConfig {
Key type();
SeatConfig[] seats();
Vector3f position();
boolean blocksBuilding();
boolean canBeHitByProjectile();
boolean canUseItemOn();
}

View File

@@ -1,4 +1,4 @@
package net.momirealms.craftengine.core.entity.furniture; package net.momirealms.craftengine.core.entity.furniture.hitbox;
import java.util.Map; import java.util.Map;

View File

@@ -1,4 +1,4 @@
package net.momirealms.craftengine.core.entity.furniture; package net.momirealms.craftengine.core.entity.furniture.hitbox;
import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.core.world.Vec3d;
import net.momirealms.craftengine.core.world.collision.AABB; import net.momirealms.craftengine.core.world.collision.AABB;

View File

@@ -1,4 +1,4 @@
package net.momirealms.craftengine.core.entity.furniture; package net.momirealms.craftengine.core.entity.furniture.hitbox;
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.BuiltInRegistries;
@@ -14,6 +14,7 @@ public class HitBoxTypes {
public static final Key INTERACTION = Key.of("minecraft:interaction"); public static final Key INTERACTION = Key.of("minecraft:interaction");
public static final Key SHULKER = Key.of("minecraft:shulker"); public static final Key SHULKER = Key.of("minecraft:shulker");
public static final Key HAPPY_GHAST = Key.of("minecraft:happy_ghast"); public static final Key HAPPY_GHAST = Key.of("minecraft:happy_ghast");
public static final Key VIRTUAL = Key.of("minecraft:virtual");
public static final Key CUSTOM = Key.of("minecraft:custom"); public static final Key CUSTOM = Key.of("minecraft:custom");
public static void register(Key key, HitBoxConfigFactory factory) { public static void register(Key key, HitBoxConfigFactory factory) {

View File

@@ -0,0 +1,8 @@
package net.momirealms.craftengine.core.entity.furniture.tick;
import net.momirealms.craftengine.core.entity.furniture.Furniture;
public interface FurnitureTicker<T extends Furniture> {
void tick(T furniture);
}

View File

@@ -1,4 +1,4 @@
package net.momirealms.craftengine.core.entity; package net.momirealms.craftengine.core.entity.item;
import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.Item;

View File

@@ -1,7 +1,7 @@
package net.momirealms.craftengine.core.entity.projectile; package net.momirealms.craftengine.core.entity.projectile;
import net.momirealms.craftengine.core.entity.Billboard; import net.momirealms.craftengine.core.entity.display.Billboard;
import net.momirealms.craftengine.core.entity.ItemDisplayContext; import net.momirealms.craftengine.core.entity.display.ItemDisplayContext;
import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.Key;
import org.joml.Quaternionf; import org.joml.Quaternionf;
import org.joml.Vector3f; import org.joml.Vector3f;

View File

@@ -28,7 +28,7 @@ import java.util.Optional;
* This interface provides methods for managing item properties such as custom model data, * This interface provides methods for managing item properties such as custom model data,
* damage, display name, lore, enchantments, and tags. * damage, display name, lore, enchantments, and tags.
* *
* @param <I> the type of the item implementation * @param <I> the id of the item implementation
*/ */
public interface Item<I> { public interface Item<I> {

View File

@@ -1,7 +1,7 @@
package net.momirealms.craftengine.core.item; package net.momirealms.craftengine.core.item;
import net.momirealms.craftengine.core.entity.Billboard; import net.momirealms.craftengine.core.entity.display.Billboard;
import net.momirealms.craftengine.core.entity.ItemDisplayContext; import net.momirealms.craftengine.core.entity.display.ItemDisplayContext;
import net.momirealms.craftengine.core.entity.projectile.ProjectileMeta; import net.momirealms.craftengine.core.entity.projectile.ProjectileMeta;
import net.momirealms.craftengine.core.item.equipment.ComponentBasedEquipment; import net.momirealms.craftengine.core.item.equipment.ComponentBasedEquipment;
import net.momirealms.craftengine.core.item.equipment.Equipment; import net.momirealms.craftengine.core.item.equipment.Equipment;
@@ -134,6 +134,12 @@ public class ItemSettings {
this.customData.clear(); this.customData.clear();
} }
@Nullable
@SuppressWarnings("unchecked")
public <T> T removeCustomData(CustomDataType<?> type) {
return (T) this.customData.remove(type);
}
public <T> void addCustomData(CustomDataType<T> key, T value) { public <T> void addCustomData(CustomDataType<T> key, T value) {
this.customData.put(key, value); this.customData.put(key, value);
} }

View File

@@ -190,7 +190,7 @@ public class CustomSmithingTransformRecipe<T> extends AbstractedFixedResultRecip
@Override @Override
public CustomSmithingTransformRecipe<A> readMap(Key id, Map<String, Object> arguments) { public CustomSmithingTransformRecipe<A> readMap(Key id, Map<String, Object> arguments) {
List<String> base = MiscUtils.getAsStringList(arguments.get("base")); List<String> base = MiscUtils.getAsStringList(arguments.get("base"));
List<String> template = MiscUtils.getAsStringList(arguments.get("template-type")); List<String> template = MiscUtils.getAsStringList(arguments.get("template-id"));
List<String> addition = MiscUtils.getAsStringList(arguments.get("addition")); List<String> addition = MiscUtils.getAsStringList(arguments.get("addition"));
boolean mergeComponents = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("merge-components", true), "merge-components"); boolean mergeComponents = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("merge-components", true), "merge-components");
boolean mergeEnchantments = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("merge-enchantments", false), "merge-enchantments"); boolean mergeEnchantments = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("merge-enchantments", false), "merge-enchantments");

View File

@@ -141,7 +141,7 @@ public class CustomSmithingTrimRecipe<T> extends AbstractRecipe<T>
@Override @Override
public CustomSmithingTrimRecipe<A> readMap(Key id, Map<String, Object> arguments) { public CustomSmithingTrimRecipe<A> readMap(Key id, Map<String, Object> arguments) {
List<String> base = MiscUtils.getAsStringList(arguments.get("base")); List<String> base = MiscUtils.getAsStringList(arguments.get("base"));
List<String> template = MiscUtils.getAsStringList(arguments.get("template-type")); List<String> template = MiscUtils.getAsStringList(arguments.get("template-id"));
List<String> addition = MiscUtils.getAsStringList(arguments.get("addition")); List<String> addition = MiscUtils.getAsStringList(arguments.get("addition"));
Key pattern = VersionHelper.isOrAbove1_21_5() ? Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("pattern"), "warning.config.recipe.smithing_trim.missing_pattern")) : null; Key pattern = VersionHelper.isOrAbove1_21_5() ? Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("pattern"), "warning.config.recipe.smithing_trim.missing_pattern")) : null;
return new CustomSmithingTrimRecipe<>(id, return new CustomSmithingTrimRecipe<>(id,

View File

@@ -87,12 +87,12 @@ public class ApplyBonusCountFunction<T> extends AbstractLootConditionalFunction<
public static Formula fromMap(Map<String, Object> map) { public static Formula fromMap(Map<String, Object> map) {
String type = (String) map.get("type"); String type = (String) map.get("type");
if (type == null) { if (type == null) {
throw new NullPointerException("number type cannot be null"); throw new NullPointerException("number id cannot be null");
} }
Key key = Key.withDefaultNamespace(type, Key.DEFAULT_NAMESPACE); Key key = Key.withDefaultNamespace(type, Key.DEFAULT_NAMESPACE);
FormulaFactory factory = BuiltInRegistries.FORMULA_FACTORY.getValue(key); FormulaFactory factory = BuiltInRegistries.FORMULA_FACTORY.getValue(key);
if (factory == null) { if (factory == null) {
throw new IllegalArgumentException("Unknown formula type: " + type); throw new IllegalArgumentException("Unknown formula id: " + type);
} }
return factory.create(map); return factory.create(map);
} }

View File

@@ -75,7 +75,7 @@ public class ItemModels {
Key key = Key.withDefaultNamespace(type, "minecraft"); Key key = Key.withDefaultNamespace(type, "minecraft");
ItemModelReader reader = BuiltInRegistries.ITEM_MODEL_READER.getValue(key); ItemModelReader reader = BuiltInRegistries.ITEM_MODEL_READER.getValue(key);
if (reader == null) { if (reader == null) {
throw new IllegalArgumentException("Invalid item model type: " + key); throw new IllegalArgumentException("Invalid item model id: " + key);
} }
return reader.read(json); return reader.read(json);
} }

View File

@@ -80,7 +80,7 @@ public class ConditionProperties {
Key key = Key.withDefaultNamespace(type, "minecraft"); Key key = Key.withDefaultNamespace(type, "minecraft");
ConditionPropertyReader reader = BuiltInRegistries.CONDITION_PROPERTY_READER.getValue(key); ConditionPropertyReader reader = BuiltInRegistries.CONDITION_PROPERTY_READER.getValue(key);
if (reader == null) { if (reader == null) {
throw new IllegalArgumentException("Invalid condition property type: " + key); throw new IllegalArgumentException("Invalid condition property id: " + key);
} }
return reader.read(json); return reader.read(json);
} }

View File

@@ -71,7 +71,7 @@ public class RangeDispatchProperties {
Key key = Key.withDefaultNamespace(type, "minecraft"); Key key = Key.withDefaultNamespace(type, "minecraft");
RangeDispatchPropertyReader reader = BuiltInRegistries.RANGE_DISPATCH_PROPERTY_READER.getValue(key); RangeDispatchPropertyReader reader = BuiltInRegistries.RANGE_DISPATCH_PROPERTY_READER.getValue(key);
if (reader == null) { if (reader == null) {
throw new IllegalArgumentException("Invalid range dispatch property type: " + key); throw new IllegalArgumentException("Invalid range dispatch property id: " + key);
} }
return reader.read(json); return reader.read(json);
} }

View File

@@ -71,7 +71,7 @@ public class SelectProperties {
Key key = Key.withDefaultNamespace(type, "minecraft"); Key key = Key.withDefaultNamespace(type, "minecraft");
SelectPropertyReader reader = BuiltInRegistries.SELECT_PROPERTY_READER.getValue(key); SelectPropertyReader reader = BuiltInRegistries.SELECT_PROPERTY_READER.getValue(key);
if (reader == null) { if (reader == null) {
throw new IllegalArgumentException("Invalid select property type: " + key); throw new IllegalArgumentException("Invalid select property id: " + key);
} }
return reader.read(json); return reader.read(json);
} }

View File

@@ -45,7 +45,7 @@ public class SignSpecialModel implements SpecialModel {
@Override @Override
public SpecialModel create(Map<String, Object> arguments) { public SpecialModel create(Map<String, Object> arguments) {
Key type = Key.of(arguments.get("type").toString()); Key type = Key.of(arguments.get("type").toString());
String woodType = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("wood-type"), "warning.config.item.model.special.sign.missing_wood_type"); String woodType = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("wood-id"), "warning.config.item.model.special.sign.missing_wood_type");
String texture = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("texture"), "warning.config.item.model.special.sign.missing_texture"); String texture = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("texture"), "warning.config.item.model.special.sign.missing_texture");
return new SignSpecialModel(type, woodType, texture); return new SignSpecialModel(type, woodType, texture);
} }

View File

@@ -80,7 +80,7 @@ public class SpecialModels {
Key key = Key.withDefaultNamespace(type, "minecraft"); Key key = Key.withDefaultNamespace(type, "minecraft");
SpecialModelReader reader = BuiltInRegistries.SPECIAL_MODEL_READER.getValue(key); SpecialModelReader reader = BuiltInRegistries.SPECIAL_MODEL_READER.getValue(key);
if (reader == null) { if (reader == null) {
throw new IllegalArgumentException("Invalid special model type: " + key); throw new IllegalArgumentException("Invalid special model id: " + key);
} }
return reader.read(json); return reader.read(json);
} }

View File

@@ -65,7 +65,7 @@ public class Tints {
Key key = Key.withDefaultNamespace(type, "minecraft"); Key key = Key.withDefaultNamespace(type, "minecraft");
TintReader reader = BuiltInRegistries.TINT_READER.getValue(key); TintReader reader = BuiltInRegistries.TINT_READER.getValue(key);
if (reader == null) { if (reader == null) {
throw new IllegalArgumentException("Invalid tint type: " + type); throw new IllegalArgumentException("Invalid tint id: " + type);
} }
return reader.read(json); return reader.read(json);
} }

View File

@@ -36,7 +36,7 @@ public enum ObfA {
return type; return type;
} }
} }
throw new IllegalArgumentException("Unknown resource type: " + xclf); throw new IllegalArgumentException("Unknown resource id: " + xclf);
} }
public static final byte[] VALUES = new byte[] { public static final byte[] VALUES = new byte[] {

View File

@@ -9,7 +9,7 @@ import java.util.UUID;
/** /**
* Simple implementation of {@link Sender} using a {@link SenderFactory} * Simple implementation of {@link Sender} using a {@link SenderFactory}
* *
* @param <T> the command sender type * @param <T> the command sender id
*/ */
public final class AbstractSender<T> implements Sender { public final class AbstractSender<T> implements Sender {
private final Plugin plugin; private final Plugin plugin;

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