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

refactor furniture framework

This commit is contained in:
XiaoMoMi
2025-03-31 04:02:28 +08:00
parent a820cbc2c2
commit 31a6f490e3
24 changed files with 431 additions and 182 deletions

View File

@@ -0,0 +1,67 @@
package net.momirealms.craftengine.bukkit.entity.furniture;
import net.momirealms.craftengine.bukkit.entity.DisplayEntityData;
import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
import net.momirealms.craftengine.bukkit.util.Reflections;
import net.momirealms.craftengine.core.entity.furniture.AbstractFurnitureElement;
import net.momirealms.craftengine.core.entity.furniture.Billboard;
import net.momirealms.craftengine.core.entity.furniture.ItemDisplayContext;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.QuaternionUtils;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
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 List<Object> cachedValues;
public BukkitFurnitureElement(Key item,
Billboard billboard,
ItemDisplayContext transform,
Vector3f scale,
Vector3f translation,
Vector3f offset,
Quaternionf rotation) {
super(item, billboard, transform, scale, translation, offset, rotation);
}
@Override
public void addSpawnPackets(int entityId, double x, double y, double z, float yaw, Consumer<Object> packets) {
try {
Vector3f offset = QuaternionUtils.toQuaternionf(0, Math.toRadians(180 - yaw), 0).conjugate().transform(new Vector3f(position()));
packets.accept(Reflections.constructor$ClientboundAddEntityPacket.newInstance(
entityId, UUID.randomUUID(), x + offset.x, y + offset.y, z - offset.z, 0, yaw,
Reflections.instance$EntityType$ITEM_DISPLAY, 0, Reflections.instance$Vec3$Zero, 0
));
packets.accept(Reflections.constructor$ClientboundSetEntityDataPacket.newInstance(entityId, getCachedValues()));
} catch (ReflectiveOperationException e) {
throw new RuntimeException("Failed to construct element spawn packet", e);
}
}
private synchronized List<Object> getCachedValues() {
if (this.cachedValues == null) {
this.cachedValues = new ArrayList<>();
Item<ItemStack> item = BukkitItemManager.instance().createWrappedItem(item(), null);
if (item == null) {
CraftEngine.instance().logger().warn("Failed to create furniture element for " + item() + " because item " + item() + " not found");
item = BukkitItemManager.instance().wrap(new ItemStack(Material.STONE));
}
DisplayEntityData.DisplayedItem.addEntityDataIfNotDefaultValue(item.getLiteralObject(), this.cachedValues);
DisplayEntityData.Scale.addEntityDataIfNotDefaultValue(scale(), this.cachedValues);
DisplayEntityData.RotationLeft.addEntityDataIfNotDefaultValue(rotation(), this.cachedValues);
DisplayEntityData.BillboardConstraints.addEntityDataIfNotDefaultValue(billboard().id(), this.cachedValues);
DisplayEntityData.Translation.addEntityDataIfNotDefaultValue(translation(), this.cachedValues);
DisplayEntityData.DisplayType.addEntityDataIfNotDefaultValue(transform().id(), this.cachedValues);
}
return this.cachedValues;
}
}

View File

@@ -1,5 +1,6 @@
package net.momirealms.craftengine.bukkit.entity.furniture;
import net.momirealms.craftengine.bukkit.nms.CollisionEntity;
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
import net.momirealms.craftengine.bukkit.util.EntityUtils;
import net.momirealms.craftengine.core.entity.furniture.*;
@@ -115,7 +116,7 @@ public class BukkitFurnitureManager implements FurnitureManager {
}
ItemDisplayContext transform = ItemDisplayContext.valueOf(element.getOrDefault("transform", "NONE").toString().toUpperCase(Locale.ENGLISH));
Billboard billboard = Billboard.valueOf(element.getOrDefault("billboard", "FIXED").toString().toUpperCase(Locale.ENGLISH));
FurnitureElement furnitureElement = new FurnitureElement(Key.of(key), billboard, transform,
FurnitureElement furnitureElement = new BukkitFurnitureElement(Key.of(key), billboard, transform,
MiscUtils.getVector3f(element.getOrDefault("scale", "1")),
MiscUtils.getVector3f(element.getOrDefault("translation", "0")),
MiscUtils.getVector3f(element.getOrDefault("position", "0")),
@@ -126,32 +127,10 @@ public class BukkitFurnitureManager implements FurnitureManager {
List<Map<String, Object>> hitboxConfigs = (List<Map<String, Object>>) placementArguments.getOrDefault("hitboxes", List.of());
List<HitBox> hitboxes = new ArrayList<>();
for (Map<String, Object> config : hitboxConfigs) {
List<String> seats = (List<String>) config.getOrDefault("seats", List.of());
Seat[] seatArray = seats.stream()
.map(arg -> {
String[] split = arg.split(" ");
if (split.length == 1) return new Seat(MiscUtils.getVector3f(split[0]), 0, false);
return new Seat(MiscUtils.getVector3f(split[0]), Float.parseFloat(split[1]), true);
})
.toArray(Seat[]::new);
Vector3f position = MiscUtils.getVector3f(config.getOrDefault("position", "0"));
float width = MiscUtils.getAsFloat(config.getOrDefault("width", "1"));
float height = MiscUtils.getAsFloat(config.getOrDefault("height", "1"));
HitBox hitBox = new HitBox(
position,
new Vector3f(width, height, width),
seatArray,
(boolean) config.getOrDefault("interactive", true)
);
hitboxes.add(hitBox);
hitboxes.add(HitBoxTypes.fromMap(config));
}
if (hitboxes.isEmpty()) {
hitboxes.add(new HitBox(
new Vector3f(),
new Vector3f(1,1,1),
new Seat[0],
true
));
hitboxes.add(InteractionHitBox.DEFAULT);
}
Map<String, Object> ruleSection = MiscUtils.castToMap(placementArguments.get("rules"), true);
if (ruleSection != null) {
@@ -164,6 +143,7 @@ public class BukkitFurnitureManager implements FurnitureManager {
placements.put(anchorType, new CustomFurniture.Placement(
elements.toArray(new FurnitureElement[0]),
hitboxes.toArray(new HitBox[0]),
new Collider[0],
rotationRule,
alignmentRule
));
@@ -171,6 +151,7 @@ public class BukkitFurnitureManager implements FurnitureManager {
placements.put(anchorType, new CustomFurniture.Placement(
elements.toArray(new FurnitureElement[0]),
hitboxes.toArray(new HitBox[0]),
new Collider[0],
RotationRule.ANY,
AlignmentRule.CENTER
));
@@ -222,6 +203,13 @@ public class BukkitFurnitureManager implements FurnitureManager {
tryLeavingSeat(player, vehicle);
}
}
// for (World world : Bukkit.getWorlds()) {
// for (Entity entity : world.getEntities()) {
// if (entity instanceof CollisionEntity) {
// entity.remove();
// }
// }
// }
}
@Override
@@ -252,6 +240,10 @@ public class BukkitFurnitureManager implements FurnitureManager {
for (int sub : furniture.interactionEntityIds()) {
this.furnitureByInteractionEntityId.remove(sub);
}
} else if (entity instanceof Interaction interaction) {
if (interaction instanceof CollisionEntity) {
entity.remove();
}
}
}

View File

@@ -0,0 +1,12 @@
package net.momirealms.craftengine.bukkit.entity.furniture;
import net.momirealms.craftengine.core.entity.furniture.HitBoxTypes;
public class BukkitHitBoxTypes extends HitBoxTypes {
public static void init() {}
static {
register(INTERACTION, InteractionHitBox.FACTORY);
}
}

View File

@@ -0,0 +1,81 @@
package net.momirealms.craftengine.bukkit.entity.furniture;
import net.momirealms.craftengine.bukkit.entity.InteractionEntityData;
import net.momirealms.craftengine.bukkit.util.Reflections;
import net.momirealms.craftengine.core.entity.furniture.*;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.MiscUtils;
import net.momirealms.craftengine.core.util.QuaternionUtils;
import org.joml.Vector3f;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.function.Consumer;
public class InteractionHitBox extends AbstractHitBox {
public static final Factory FACTORY = new Factory();
public static final InteractionHitBox DEFAULT = new InteractionHitBox(new Seat[0], new Vector3f(), new Vector3f(1,1,1), true);
private final Vector3f position;
private final Vector3f size;
private final boolean responsive;
private final List<Object> cachedValues = new ArrayList<>();
public InteractionHitBox(Seat[] seats, Vector3f position, Vector3f size, boolean responsive) {
super(seats);
this.position = position;
this.size = size;
this.responsive = responsive;
InteractionEntityData.Height.addEntityDataIfNotDefaultValue(size.y, cachedValues);
InteractionEntityData.Width.addEntityDataIfNotDefaultValue(size.x, cachedValues);
InteractionEntityData.Responsive.addEntityDataIfNotDefaultValue(responsive, cachedValues);
}
public boolean responsive() {
return responsive;
}
public Vector3f position() {
return position;
}
public Vector3f size() {
return size;
}
@Override
public Key type() {
return HitBoxTypes.INTERACTION;
}
@Override
public void addSpawnPackets(int entityId, double x, double y, double z, float yaw, Consumer<Object> packets) {
Vector3f offset = QuaternionUtils.toQuaternionf(0f, Math.toRadians(180f - yaw), 0f).conjugate().transform(new Vector3f(position()));
try {
packets.accept(Reflections.constructor$ClientboundAddEntityPacket.newInstance(
entityId, UUID.randomUUID(), x + offset.x, y + offset.y, z - offset.z, 0, yaw,
Reflections.instance$EntityType$INTERACTION, 0, Reflections.instance$Vec3$Zero, 0
));
packets.accept(Reflections.constructor$ClientboundSetEntityDataPacket.newInstance(entityId, List.copyOf(this.cachedValues)));
} catch (ReflectiveOperationException e) {
throw new RuntimeException("Failed to construct hitbox spawn packet", e);
}
}
public static class Factory implements HitBoxFactory {
@Override
public HitBox create(Map<String, Object> arguments) {
Vector3f position = MiscUtils.getVector3f(arguments.getOrDefault("position", "0"));
float width = MiscUtils.getAsFloat(arguments.getOrDefault("width", "1"));
float height = MiscUtils.getAsFloat(arguments.getOrDefault("height", "1"));
return new InteractionHitBox(
HitBoxFactory.getSeats(arguments),
position,
new Vector3f(width, height, width),
(boolean) arguments.getOrDefault("interactive", true)
);
}
}
}

View File

@@ -1,13 +1,9 @@
package net.momirealms.craftengine.bukkit.entity.furniture;
import net.momirealms.craftengine.bukkit.entity.DisplayEntityData;
import net.momirealms.craftengine.bukkit.entity.InteractionEntityData;
import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
import net.momirealms.craftengine.bukkit.util.EntityUtils;
import net.momirealms.craftengine.bukkit.util.LegacyAttributeUtils;
import net.momirealms.craftengine.bukkit.util.Reflections;
import net.momirealms.craftengine.core.entity.furniture.*;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.util.ArrayUtils;
import net.momirealms.craftengine.core.util.Key;
@@ -19,7 +15,6 @@ import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.ItemDisplay;
import org.bukkit.inventory.ItemStack;
import org.bukkit.persistence.PersistentDataType;
import org.jetbrains.annotations.NotNull;
import org.joml.Vector3f;
@@ -35,8 +30,6 @@ public class LoadedFurniture {
private final Map<Integer, HitBox> hitBoxes;
// location
private Location location;
// cached spawn packet
private Object cachedSpawnPacket;
// base entity
private final WeakReference<Entity> baseEntity;
private final int baseEntityId;
@@ -48,6 +41,9 @@ public class LoadedFurniture {
private final Set<Vector3f> occupiedSeats = Collections.synchronizedSet(new HashSet<>());
private final Vector<Entity> seats = new Vector<>();
// cached spawn packet
private Object cachedSpawnPacket;
public LoadedFurniture(Entity baseEntity,
CustomFurniture furniture,
AnchorType anchorType) {
@@ -60,77 +56,39 @@ public class LoadedFurniture {
this.hitBoxes = new HashMap<>();
this.elements = new HashMap<>();
List<Integer> entityIds = new ArrayList<>();
List<Integer> interactionEntityIds = new ArrayList<>();
List<Integer> hitBoxEntityIds = new ArrayList<>();
CustomFurniture.Placement placement = furniture.getPlacement(anchorType);
for (FurnitureElement element : placement.elements()) {
int entityId = Reflections.instance$Entity$ENTITY_COUNTER.incrementAndGet();
entityIds.add(entityId);
this.elements.put(entityId, element);
}
for (HitBox hitBox : placement.hitbox()) {
for (HitBox hitBox : placement.hitboxes()) {
int entityId = Reflections.instance$Entity$ENTITY_COUNTER.incrementAndGet();
entityIds.add(entityId);
interactionEntityIds.add(entityId);
hitBoxEntityIds.add(entityId);
this.hitBoxes.put(entityId, hitBox);
}
this.subEntityIds = entityIds;
this.interactionEntityIds = interactionEntityIds;
this.resetSpawnPackets();
this.interactionEntityIds = hitBoxEntityIds;
}
private void resetSpawnPackets() {
try {
List<Object> packets = new ArrayList<>();
for (Map.Entry<Integer, FurnitureElement> entry : elements.entrySet()) {
int entityId = entry.getKey();
FurnitureElement element = entry.getValue();
Item<ItemStack> item = BukkitItemManager.instance().createWrappedItem(element.item(), null);
if (item == null) {
CraftEngine.instance().logger().warn("Failed to create furniture element for " + id + " because item " + element.item() + " not found");
continue;
public synchronized Object spawnPacket() {
if (this.cachedSpawnPacket == null) {
try {
List<Object> packets = new ArrayList<>();
for (Map.Entry<Integer, FurnitureElement> entry : this.elements.entrySet()) {
entry.getValue().addSpawnPackets(entry.getKey(), this.location.getX(), this.location.getY(), this.location.getZ(), this.location.getYaw(), packets::add);
}
item.load();
Vector3f offset = QuaternionUtils.toQuaternionf(0, Math.toRadians(180 - this.location.getYaw()), 0).conjugate().transform(new Vector3f(element.offset()));
Object addEntityPacket = Reflections.constructor$ClientboundAddEntityPacket.newInstance(
entityId, UUID.randomUUID(), this.location.getX() + offset.x, this.location.getY() + offset.y, this.location.getZ() - offset.z, 0, this.location.getYaw(),
Reflections.instance$EntityType$ITEM_DISPLAY, 0, Reflections.instance$Vec3$Zero, 0
);
ArrayList<Object> values = new ArrayList<>();
DisplayEntityData.DisplayedItem.addEntityDataIfNotDefaultValue(item.getLiteralObject(), values);
DisplayEntityData.Scale.addEntityDataIfNotDefaultValue(element.scale(), values);
DisplayEntityData.RotationLeft.addEntityDataIfNotDefaultValue(element.rotation(), values);
DisplayEntityData.BillboardConstraints.addEntityDataIfNotDefaultValue(element.billboard().id(), values);
DisplayEntityData.Translation.addEntityDataIfNotDefaultValue(element.translation(), values);
DisplayEntityData.DisplayType.addEntityDataIfNotDefaultValue(element.transform().id(), values);
Object setDataPacket = Reflections.constructor$ClientboundSetEntityDataPacket.newInstance(entityId, values);
packets.add(addEntityPacket);
packets.add(setDataPacket);
for (Map.Entry<Integer, HitBox> entry : this.hitBoxes.entrySet()) {
entry.getValue().addSpawnPackets(entry.getKey(), this.location.getX(), this.location.getY(), this.location.getZ(), this.location.getYaw(), packets::add);
}
this.cachedSpawnPacket = Reflections.constructor$ClientboundBundlePacket.newInstance(packets);
} catch (Exception e) {
CraftEngine.instance().logger().warn("Failed to init spawn packets for furniture " + id, e);
}
for (Map.Entry<Integer, HitBox> entry : hitBoxes.entrySet()) {
int entityId = entry.getKey();
HitBox hitBox = entry.getValue();
Vector3f offset = QuaternionUtils.toQuaternionf(0, Math.toRadians(180 - this.location.getYaw()), 0).conjugate().transform(new Vector3f(hitBox.offset()));
Object addEntityPacket = Reflections.constructor$ClientboundAddEntityPacket.newInstance(
entityId, UUID.randomUUID(), this.location.getX() + offset.x, this.location.getY() + offset.y, this.location.getZ() - offset.z, 0, this.location.getYaw(),
Reflections.instance$EntityType$INTERACTION, 0, Reflections.instance$Vec3$Zero, 0
);
ArrayList<Object> values = new ArrayList<>();
InteractionEntityData.Height.addEntityDataIfNotDefaultValue(hitBox.size().y, values);
InteractionEntityData.Width.addEntityDataIfNotDefaultValue(hitBox.size().x, values);
InteractionEntityData.Responsive.addEntityDataIfNotDefaultValue(hitBox.responsive(), values);
Object setDataPacket = Reflections.constructor$ClientboundSetEntityDataPacket.newInstance(entityId, values);
packets.add(addEntityPacket);
packets.add(setDataPacket);
}
this.cachedSpawnPacket = Reflections.constructor$ClientboundBundlePacket.newInstance(packets);
} catch (Exception e) {
CraftEngine.instance().logger().warn("Failed to init spawn packets for furniture " + id, e);
}
return this.cachedSpawnPacket;
}
@NotNull
@@ -274,8 +232,4 @@ public class LoadedFurniture {
this.addSeatEntity(seatEntity);
seatEntity.addPassenger(player);
}
public @NotNull Object spawnPacket() {
return cachedSpawnPacket;
}
}

View File

@@ -15,7 +15,6 @@ import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.item.behavior.ItemBehavior;
import net.momirealms.craftengine.core.item.context.UseOnContext;
import net.momirealms.craftengine.core.util.Direction;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.world.BlockHitResult;
import net.momirealms.craftengine.core.world.BlockPos;
import net.momirealms.craftengine.core.world.Vec3d;

View File

@@ -6,6 +6,7 @@ import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
import net.momirealms.craftengine.bukkit.block.behavior.BukkitBlockBehaviors;
import net.momirealms.craftengine.bukkit.compatibility.papi.PlaceholderAPIUtils;
import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager;
import net.momirealms.craftengine.bukkit.entity.furniture.BukkitHitBoxTypes;
import net.momirealms.craftengine.bukkit.font.BukkitImageManager;
import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
import net.momirealms.craftengine.bukkit.item.behavior.BukkitItemBehaviors;
@@ -142,6 +143,7 @@ public class BukkitCraftEngine extends CraftEngine {
}
BukkitBlockBehaviors.init();
BukkitItemBehaviors.init();
BukkitHitBoxTypes.init();
super.packManager = new BukkitPackManager(this);
super.senderFactory = new BukkitSenderFactory(this);
super.itemManager = new BukkitItemManager(this);

View File

@@ -1,15 +1,16 @@
package net.momirealms.craftengine.bukkit.plugin.command.feature;
import net.momirealms.craftengine.bukkit.nms.CollisionEntity;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature;
import net.momirealms.craftengine.bukkit.util.Reflections;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager;
import net.momirealms.craftengine.core.registry.Holder;
import net.momirealms.craftengine.core.util.Key;
import org.bukkit.Location;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.incendo.cloud.Command;
import java.util.List;
public class TestCommand extends BukkitCommandFeature<CommandSender> {
public TestCommand(CraftEngineCommandManager<CommandSender> commandManager, CraftEngine plugin) {
@@ -19,10 +20,18 @@ public class TestCommand extends BukkitCommandFeature<CommandSender> {
@Override
public Command.Builder<? extends CommandSender> assembleCommand(org.incendo.cloud.CommandManager<CommandSender> manager, Command.Builder<CommandSender> builder) {
return builder
.senderType(Player.class)
.handler(context -> {
List<Holder<Key>> holders = plugin().itemManager().tagToItems(Key.of("minecraft:planks"));
for (Holder<Key> holder : holders) {
context.sender().sendMessage(holder.registeredName());
Player player = context.sender();
Location location = player.getLocation();
try {
Object level = Reflections.field$CraftWorld$ServerLevel.get(player.getWorld());
Object aabb = FastNMS.INSTANCE.constructor$AABB(location.getBlockX(), location.getBlockY(), location.getBlockZ(),
location.getBlockX() + 1, location.getBlockY() + 1, location.getBlockZ() + 1);
CollisionEntity nmsEntity = FastNMS.INSTANCE.createCollisionEntity(level, aabb, location.getBlockX() + 0.5, location.getBlockY(), location.getBlockZ() + 0.5, true, false);
FastNMS.INSTANCE.method$LevelWriter$addFreshEntity(level, nmsEntity);
} catch (Exception e) {
e.printStackTrace();
}
});
}

View File

@@ -2426,6 +2426,12 @@ public class Reflections {
)
);
public static final Constructor<?> constructor$AABB = requireNonNull(
ReflectionUtils.getConstructor(
clazz$AABB, double.class, double.class, double.class, double.class, double.class, double.class
)
);
public static final Class<?> clazz$BlockGetter = requireNonNull(
ReflectionUtils.getClazz(
BukkitReflectionUtils.assembleMCClass("world.level.BlockGetter"),
@@ -5753,22 +5759,27 @@ public class Reflections {
)
);
public static final Field field$Level$random = requireNonNull(
ReflectionUtils.getDeclaredField(
clazz$Level, clazz$RandomSource, 0
public static final Field field$Entity$boundingBox = requireNonNull(
ReflectionUtils.getInstanceDeclaredField(
clazz$Entity, clazz$AABB, 0
)
);
public static final Class<?> clazz$Mth = requireNonNull(
public static final Class<?> clazz$CraftShulker = requireNonNull(
ReflectionUtils.getClazz(
BukkitReflectionUtils.assembleMCClass("util.Mth"),
BukkitReflectionUtils.assembleMCClass("util.MathHelper")
BukkitReflectionUtils.assembleCBClass("entity.CraftShulker")
)
);
public static final Method method$nextInt = requireNonNull(
public static final Class<?> clazz$Shulker = requireNonNull(
ReflectionUtils.getClazz(
BukkitReflectionUtils.assembleMCClass("world.entity.monster.Shulker")
)
);
public static final Method method$CraftShulker$getHandle = requireNonNull(
ReflectionUtils.getMethod(
clazz$Mth, int.class, clazz$RandomSource, int.class, int.class
clazz$CraftShulker, clazz$Shulker, 0
)
);
}

View File

@@ -395,6 +395,4 @@ public class BukkitWorldManager implements WorldManager, Listener {
}
ceChunk.load();
}
}

View File

@@ -0,0 +1,60 @@
package net.momirealms.craftengine.core.entity.furniture;
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 offset;
private final Quaternionf rotation;
public AbstractFurnitureElement(Key item, Billboard billboard, ItemDisplayContext transform, Vector3f scale, Vector3f translation, Vector3f offset, Quaternionf rotation) {
this.billboard = billboard;
this.transform = transform;
this.scale = scale;
this.translation = translation;
this.item = item;
this.rotation = rotation;
this.offset = offset;
}
@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 offset;
}
}

View File

@@ -0,0 +1,15 @@
package net.momirealms.craftengine.core.entity.furniture;
public abstract class AbstractHitBox implements HitBox {
protected final Seat[] seats;
public AbstractHitBox(Seat[] seats) {
this.seats = seats;
}
@Override
public Seat[] seats() {
return seats;
}
}

View File

@@ -0,0 +1,33 @@
package net.momirealms.craftengine.core.entity.furniture;
import org.joml.Vector3f;
public class Collider {
private final Vector3f position;
private final double width;
private final double height;
private final boolean canBeHitByProjectile;
public Collider(boolean canBeHitByProjectile, double height, Vector3f position, double width) {
this.canBeHitByProjectile = canBeHitByProjectile;
this.height = height;
this.position = position;
this.width = width;
}
public boolean canBeHitByProjectile() {
return canBeHitByProjectile;
}
public double height() {
return height;
}
public Vector3f position() {
return position;
}
public double width() {
return width;
}
}

View File

@@ -11,6 +11,7 @@ public class CustomFurniture {
private final Key id;
private final FurnitureSettings settings;
private final EnumMap<AnchorType, Placement> placements;
private final AnchorType anyType;
@Nullable
private final LootTable<?> lootTable;
@@ -22,6 +23,7 @@ public class CustomFurniture {
this.settings = settings;
this.placements = placements;
this.lootTable = lootTable;
this.anyType = placements.keySet().stream().findFirst().orElse(null);
}
public Key id() {
@@ -42,7 +44,7 @@ public class CustomFurniture {
}
public AnchorType getAnyPlacement() {
return placements.keySet().stream().findFirst().orElse(null);
return this.anyType;
}
public boolean isAllowedPlacement(AnchorType anchorType) {
@@ -55,19 +57,25 @@ public class CustomFurniture {
public static class Placement {
private final FurnitureElement[] elements;
private final HitBox[] hitbox;
private final HitBox[] hitboxes;
private final Collider[] colliders;
private final RotationRule rotationRule;
private final AlignmentRule alignmentRule;
public Placement(FurnitureElement[] elements, HitBox[] hitbox, RotationRule rotationRule, AlignmentRule alignmentRule) {
public Placement(FurnitureElement[] elements, HitBox[] hitboxes, Collider[] colliders, RotationRule rotationRule, AlignmentRule alignmentRule) {
this.elements = elements;
this.hitbox = hitbox;
this.hitboxes = hitboxes;
this.colliders = colliders;
this.rotationRule = rotationRule;
this.alignmentRule = alignmentRule;
}
public HitBox[] hitbox() {
return hitbox;
public HitBox[] hitboxes() {
return hitboxes;
}
public Collider[] colliders() {
return colliders;
}
public FurnitureElement[] elements() {

View File

@@ -4,50 +4,22 @@ import net.momirealms.craftengine.core.util.Key;
import org.joml.Quaternionf;
import org.joml.Vector3f;
public class FurnitureElement {
private final Key item;
private final Billboard billboard;
private final ItemDisplayContext transform;
private final Vector3f scale;
private final Vector3f translation;
private final Vector3f offset;
private final Quaternionf rotation;
import java.util.function.Consumer;
public FurnitureElement(Key item, Billboard billboard, ItemDisplayContext transform, Vector3f scale, Vector3f translation, Vector3f offset, Quaternionf rotation) {
this.billboard = billboard;
this.transform = transform;
this.scale = scale;
this.translation = translation;
this.item = item;
this.rotation = rotation;
this.offset = offset;
}
public interface FurnitureElement {
Quaternionf rotation();
public Quaternionf rotation() {
return rotation;
}
Key item();
public Key item() {
return item;
}
Billboard billboard();
public Billboard billboard() {
return billboard;
}
ItemDisplayContext transform();
public ItemDisplayContext transform() {
return transform;
}
Vector3f scale();
public Vector3f scale() {
return scale;
}
Vector3f translation();
public Vector3f translation() {
return translation;
}
Vector3f position();
public Vector3f offset() {
return offset;
}
void addSpawnPackets(int entityId, double x, double y, double z, float yaw, Consumer<Object> packets);
}

View File

@@ -1,33 +1,14 @@
package net.momirealms.craftengine.core.entity.furniture;
import org.joml.Vector3f;
import net.momirealms.craftengine.core.util.Key;
public class HitBox {
private final Vector3f position;
private final Vector3f size;
private final Seat[] seats;
private final boolean responsive;
import java.util.function.Consumer;
public HitBox(Vector3f position, Vector3f size, Seat[] seats, boolean responsive) {
this.position = position;
this.size = size;
this.seats = seats;
this.responsive = responsive;
}
public interface HitBox {
public boolean responsive() {
return responsive;
}
Key type();
public Seat[] seats() {
return seats;
}
void addSpawnPackets(int entityId, double x, double y, double z, float yaw, Consumer<Object> packets);
public Vector3f offset() {
return position;
}
public Vector3f size() {
return size;
}
Seat[] seats();
}

View File

@@ -0,0 +1,23 @@
package net.momirealms.craftengine.core.entity.furniture;
import net.momirealms.craftengine.core.util.MiscUtils;
import java.util.List;
import java.util.Map;
public interface HitBoxFactory {
HitBox create(Map<String, Object> arguments);
@SuppressWarnings("unchecked")
static Seat[] getSeats(Map<String, Object> arguments) {
List<String> seats = (List<String>) arguments.getOrDefault("seats", List.of());
return seats.stream()
.map(arg -> {
String[] split = arg.split(" ");
if (split.length == 1) return new Seat(MiscUtils.getVector3f(split[0]), 0, false);
return new Seat(MiscUtils.getVector3f(split[0]), Float.parseFloat(split[1]), true);
})
.toArray(Seat[]::new);
}
}

View File

@@ -0,0 +1,31 @@
package net.momirealms.craftengine.core.entity.furniture;
import net.momirealms.craftengine.core.registry.BuiltInRegistries;
import net.momirealms.craftengine.core.registry.Holder;
import net.momirealms.craftengine.core.registry.Registries;
import net.momirealms.craftengine.core.registry.WritableRegistry;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.ResourceKey;
import java.util.Map;
import java.util.Optional;
public class HitBoxTypes {
public static final Key INTERACTION = Key.of("minecraft:interaction");
public static final Key SHULKER = Key.of("minecraft:shulker");
public static void register(Key key, HitBoxFactory factory) {
Holder.Reference<HitBoxFactory> holder = ((WritableRegistry<HitBoxFactory>) BuiltInRegistries.HITBOX_FACTORY)
.registerForHolder(new ResourceKey<>(Registries.HITBOX_FACTORY.location(), key));
holder.bindValue(factory);
}
public static HitBox fromMap(Map<String, Object> arguments) {
Key type = Optional.ofNullable((String) arguments.get("type")).map(Key::of).orElse(HitBoxTypes.INTERACTION);
HitBoxFactory factory = BuiltInRegistries.HITBOX_FACTORY.getValue(type);
if (factory == null) {
throw new IllegalArgumentException("Unknown hitbox type: " + type);
}
return factory.create(arguments);
}
}

View File

@@ -1,7 +1,6 @@
package net.momirealms.craftengine.core.plugin.locale;
import net.momirealms.craftengine.core.pack.Pack;
import net.momirealms.craftengine.core.plugin.Plugin;
import net.momirealms.craftengine.core.util.Key;
import java.nio.file.Path;

View File

@@ -1,7 +1,6 @@
package net.momirealms.craftengine.core.plugin.locale;
import net.momirealms.craftengine.core.block.BlockStateParser;
import net.momirealms.craftengine.core.block.BlockStateVariantProvider;
import net.momirealms.craftengine.core.block.CustomBlock;
import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.plugin.CraftEngine;

View File

@@ -3,7 +3,6 @@ package net.momirealms.craftengine.core.plugin.locale;
import net.kyori.adventure.key.Key;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.translation.Translator;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import org.jetbrains.annotations.NotNull;
import java.util.Locale;

View File

@@ -3,6 +3,7 @@ package net.momirealms.craftengine.core.registry;
import net.momirealms.craftengine.core.block.CustomBlock;
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
import net.momirealms.craftengine.core.block.properties.PropertyFactory;
import net.momirealms.craftengine.core.entity.furniture.HitBoxFactory;
import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory;
import net.momirealms.craftengine.core.item.recipe.CustomSmithingTransformRecipe;
import net.momirealms.craftengine.core.item.recipe.RecipeFactory;
@@ -45,6 +46,7 @@ public class BuiltInRegistries {
public static final Registry<PathMatcherFactory> PATH_MATCHER_FACTORY = createRegistry(Registries.PATH_MATCHER_FACTORY);
public static final Registry<ResolutionFactory> RESOLUTION_FACTORY = createRegistry(Registries.RESOLUTION_FACTORY);
public static final Registry<CustomSmithingTransformRecipe.ItemDataProcessor.Factory> SMITHING_RESULT_PROCESSOR_FACTORY = createRegistry(Registries.SMITHING_RESULT_PROCESSOR_FACTORY);
public static final Registry<HitBoxFactory> HITBOX_FACTORY = createRegistry(Registries.HITBOX_FACTORY);
private static <T> Registry<T> createRegistry(ResourceKey<? extends Registry<T>> key) {
return new MappedRegistry<>(key);

View File

@@ -3,6 +3,7 @@ package net.momirealms.craftengine.core.registry;
import net.momirealms.craftengine.core.block.CustomBlock;
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
import net.momirealms.craftengine.core.block.properties.PropertyFactory;
import net.momirealms.craftengine.core.entity.furniture.HitBoxFactory;
import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory;
import net.momirealms.craftengine.core.item.recipe.CustomSmithingTransformRecipe;
import net.momirealms.craftengine.core.item.recipe.RecipeFactory;
@@ -46,4 +47,5 @@ public class Registries {
public static final ResourceKey<Registry<PathMatcherFactory>> PATH_MATCHER_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("path_matcher_factory"));
public static final ResourceKey<Registry<ResolutionFactory>> RESOLUTION_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("resolution_factory"));
public static final ResourceKey<Registry<CustomSmithingTransformRecipe.ItemDataProcessor.Factory>> SMITHING_RESULT_PROCESSOR_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("smithing_result_processor_factory"));
public static final ResourceKey<Registry<HitBoxFactory>> HITBOX_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("hitbox_factory"));
}

View File

@@ -49,7 +49,7 @@ mojang_brigadier_version=1.0.18
byte_buddy_version=1.15.11
snake_yaml_version=2.3
anti_grief_version=0.13
nms_helper_version=0.12
nms_helper_version=0.19
# Ignite Dependencies
mixinextras_version=0.4.1
mixin_version=0.15.2+mixin.0.8.7