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

支持注册固定的方块实体渲染

This commit is contained in:
XiaoMoMi
2025-09-11 04:33:18 +08:00
parent c13c86a745
commit ae85ccdf23
31 changed files with 358 additions and 249 deletions

View File

@@ -7,8 +7,6 @@ import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import net.momirealms.craftengine.bukkit.block.entity.renderer.BukkitBlockEntityElement;
import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
import net.momirealms.craftengine.bukkit.plugin.injector.BlockGenerator;
@@ -25,10 +23,7 @@ import net.momirealms.craftengine.bukkit.util.RegistryUtils;
import net.momirealms.craftengine.bukkit.util.TagUtils;
import net.momirealms.craftengine.core.block.*;
import net.momirealms.craftengine.core.block.behavior.EmptyBlockBehavior;
import net.momirealms.craftengine.core.block.entity.render.BlockEntityElement;
import net.momirealms.craftengine.core.block.parser.BlockStateParser;
import net.momirealms.craftengine.core.entity.Billboard;
import net.momirealms.craftengine.core.entity.ItemDisplayContext;
import net.momirealms.craftengine.core.plugin.config.StringKeyConstructor;
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
import net.momirealms.craftengine.core.registry.BuiltInRegistries;
@@ -689,20 +684,4 @@ public final class BukkitBlockManager extends AbstractBlockManager {
}
return FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.BLOCK, KeyUtils.toResourceLocation(id)) != MBlocks.AIR;
}
@Override
protected BlockEntityElement createBlockEntityElement(Map<String, Object> arguments) {
Key itemId = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("item"), ""));
return new BukkitBlockEntityElement(
LazyReference.lazyReference(() -> BukkitItemManager.instance().createWrappedItem(itemId, 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"),
ItemDisplayContext.valueOf(arguments.getOrDefault("display-context", "none").toString().toUpperCase(Locale.ROOT)),
Billboard.valueOf(arguments.getOrDefault("billboard", "fixed").toString().toUpperCase(Locale.ROOT))
);
}
}

View File

@@ -1,106 +0,0 @@
package net.momirealms.craftengine.bukkit.block.entity.renderer;
import net.momirealms.craftengine.bukkit.entity.data.ItemDisplayEntityData;
import net.momirealms.craftengine.core.block.entity.render.BlockEntityElement;
import net.momirealms.craftengine.core.entity.Billboard;
import net.momirealms.craftengine.core.entity.ItemDisplayContext;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.util.LazyReference;
import org.joml.Quaternionf;
import org.joml.Vector3f;
import java.util.ArrayList;
import java.util.List;
public class BukkitBlockEntityElement implements BlockEntityElement {
private final LazyReference<List<Object>> lazyMetadataPacket;
private final LazyReference<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;
public BukkitBlockEntityElement(LazyReference<Item<?>> item,
Vector3f scale,
Vector3f position,
Vector3f translation,
float xRot,
float yRot,
Quaternionf rotation,
ItemDisplayContext displayContext,
Billboard billboard) {
this.item = item;
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.lazyMetadataPacket = LazyReference.lazyReference(() -> {
List<Object> dataValues = new ArrayList<>();
ItemDisplayEntityData.DisplayedItem.addEntityDataIfNotDefaultValue(item.get().getLiteralObject(), dataValues);
ItemDisplayEntityData.Scale.addEntityDataIfNotDefaultValue(this.scale, dataValues);
ItemDisplayEntityData.RotationLeft.addEntityDataIfNotDefaultValue(this.rotation, dataValues);
ItemDisplayEntityData.BillboardConstraints.addEntityDataIfNotDefaultValue(this.billboard.id(), dataValues);
ItemDisplayEntityData.Translation.addEntityDataIfNotDefaultValue(this.translation, dataValues);
ItemDisplayEntityData.DisplayType.addEntityDataIfNotDefaultValue(this.displayContext.id(), dataValues);
return dataValues;
});
}
@Override
public Item<?> item() {
return this.item.get();
}
@Override
public Vector3f scale() {
return this.scale;
}
@Override
public Vector3f translation() {
return this.translation;
}
@Override
public Vector3f position() {
return this.position;
}
@Override
public float yRot() {
return this.yRot;
}
@Override
public float xRot() {
return this.xRot;
}
@Override
public Billboard billboard() {
return billboard;
}
@Override
public ItemDisplayContext displayContext() {
return displayContext;
}
@Override
public Quaternionf rotation() {
return rotation;
}
@Override
public LazyReference<List<Object>> metadataValues() {
return this.lazyMetadataPacket;
}
}

View File

@@ -1,48 +1,22 @@
package net.momirealms.craftengine.bukkit.block.entity.renderer;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
import net.momirealms.craftengine.bukkit.api.BukkitAdaptors;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MEntityTypes;
import net.momirealms.craftengine.core.block.entity.render.BlockEntityElement;
import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer;
import net.momirealms.craftengine.core.block.entity.render.BlockEntityRenderer;
import net.momirealms.craftengine.core.block.entity.render.BlockEntityRendererConfig;
import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElement;
import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.world.BlockPos;
import org.joml.Vector3f;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class BukkitBlockEntityRenderer extends BlockEntityRenderer {
private final Object cachedSpawnPacket;
private final Object cachedDespawnPacket;
private final BlockEntityElement[] elements;
private final WeakReference<Object> chunkHolder;
public BukkitBlockEntityRenderer(WeakReference<Object> chunkHolder,
BlockEntityRendererConfig config,
BlockPos pos) {
public BukkitBlockEntityRenderer(WeakReference<Object> chunkHolder, BlockEntityElement[] elements) {
this.chunkHolder = chunkHolder;
BlockEntityElement[] elements = config.elements();
IntList ids = new IntArrayList(elements.length);
List<Object> spawnPackets = new ArrayList<>(elements.length);
for (BlockEntityElement element : elements) {
int entityId = CoreReflections.instance$Entity$ENTITY_COUNTER.incrementAndGet();
Vector3f position = element.position();
spawnPackets.add(FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket(
entityId, UUID.randomUUID(), pos.x() + position.x, pos.y() + position.y, pos.z() + position.z,
element.xRot(), element.yRot(), MEntityTypes.ITEM_DISPLAY, 0, CoreReflections.instance$Vec3$Zero, 0
));
spawnPackets.add(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(
entityId, element.metadataValues().get()
));
ids.add(entityId);
}
this.cachedSpawnPacket = FastNMS.INSTANCE.constructor$ClientboundBundlePacket(spawnPackets);
this.cachedDespawnPacket = FastNMS.INSTANCE.constructor$ClientboundRemoveEntitiesPacket(ids);
this.elements = elements;
}
@Override
@@ -50,10 +24,10 @@ public class BukkitBlockEntityRenderer extends BlockEntityRenderer {
List<Object> players = FastNMS.INSTANCE.method$ChunkHolder$getPlayers(this.chunkHolder.get());
if (players.isEmpty()) return;
for (Object player : players) {
FastNMS.INSTANCE.method$ServerPlayerConnection$send(
FastNMS.INSTANCE.field$Player$connection(player),
this.cachedDespawnPacket
);
org.bukkit.entity.Player bkPlayer = FastNMS.INSTANCE.method$ServerPlayer$getBukkitEntity(player);
BukkitServerPlayer serverPlayer = BukkitAdaptors.adapt(bkPlayer);
if (serverPlayer == null) continue;
despawn(serverPlayer);
}
}
@@ -62,20 +36,43 @@ public class BukkitBlockEntityRenderer extends BlockEntityRenderer {
List<Object> players = FastNMS.INSTANCE.method$ChunkHolder$getPlayers(this.chunkHolder.get());
if (players.isEmpty()) return;
for (Object player : players) {
FastNMS.INSTANCE.method$ServerPlayerConnection$send(
FastNMS.INSTANCE.field$Player$connection(player),
this.cachedSpawnPacket
);
org.bukkit.entity.Player bkPlayer = FastNMS.INSTANCE.method$ServerPlayer$getBukkitEntity(player);
BukkitServerPlayer serverPlayer = BukkitAdaptors.adapt(bkPlayer);
if (serverPlayer == null) continue;
spawn(serverPlayer);
}
}
@Override
public void update() {
List<Object> players = FastNMS.INSTANCE.method$ChunkHolder$getPlayers(this.chunkHolder.get());
if (players.isEmpty()) return;
for (Object player : players) {
org.bukkit.entity.Player bkPlayer = FastNMS.INSTANCE.method$ServerPlayer$getBukkitEntity(player);
BukkitServerPlayer serverPlayer = BukkitAdaptors.adapt(bkPlayer);
if (serverPlayer == null) continue;
update(serverPlayer);
}
}
@Override
public void update(Player player) {
for (BlockEntityElement element : this.elements) {
element.update(player);
}
}
@Override
public void spawn(Player player) {
player.sendPacket(this.cachedSpawnPacket, false);
for (BlockEntityElement element : this.elements) {
element.spawn(player);
}
}
@Override
public void despawn(Player player) {
player.sendPacket(this.cachedDespawnPacket, false);
for (BlockEntityElement element : this.elements) {
element.despawn(player);
}
}
}

View File

@@ -0,0 +1,13 @@
package net.momirealms.craftengine.bukkit.block.entity.renderer.element;
import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElementConfigs;
public class BukkitBlockEntityElementConfigs extends BlockEntityElementConfigs {
static {
register(ITEM_DISPLAY, ItemDisplayBlockEntityElementConfig.FACTORY);
}
public static void init() {
}
}

View File

@@ -0,0 +1,47 @@
package net.momirealms.craftengine.bukkit.block.entity.renderer.element;
import it.unimi.dsi.fastutil.ints.IntList;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MEntityTypes;
import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElement;
import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.world.BlockPos;
import org.joml.Vector3f;
import java.util.List;
import java.util.UUID;
public class ItemDisplayBlockEntityElement implements BlockEntityElement {
private final Object cachedSpawnPacket;
private final Object cachedDespawnPacket;
public ItemDisplayBlockEntityElement(ItemDisplayBlockEntityElementConfig config, BlockPos pos) {
int entityId = CoreReflections.instance$Entity$ENTITY_COUNTER.incrementAndGet();
Vector3f position = config.position();
this.cachedSpawnPacket = FastNMS.INSTANCE.constructor$ClientboundBundlePacket(List.of(
FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket(
entityId, UUID.randomUUID(), pos.x() + position.x, pos.y() + position.y, pos.z() + position.z,
config.xRot(), config.yRot(), MEntityTypes.ITEM_DISPLAY, 0, CoreReflections.instance$Vec3$Zero, 0
),
FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(
entityId, config.metadataValues().get()
)
));
this.cachedDespawnPacket = FastNMS.INSTANCE.constructor$ClientboundRemoveEntitiesPacket(IntList.of(entityId));
}
@Override
public void despawn(Player player) {
player.sendPacket(this.cachedDespawnPacket, false);
}
@Override
public void spawn(Player player) {
player.sendPacket(this.cachedSpawnPacket, true);
}
@Override
public void update(Player player) {
}
}

View File

@@ -0,0 +1,131 @@
package net.momirealms.craftengine.bukkit.block.entity.renderer.element;
import net.momirealms.craftengine.bukkit.entity.data.ItemDisplayEntityData;
import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElement;
import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElementConfig;
import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElementConfigFactory;
import net.momirealms.craftengine.core.entity.Billboard;
import net.momirealms.craftengine.core.entity.ItemDisplayContext;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.LazyReference;
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import net.momirealms.craftengine.core.world.BlockPos;
import org.joml.Quaternionf;
import org.joml.Vector3f;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
public class ItemDisplayBlockEntityElementConfig implements BlockEntityElementConfig<ItemDisplayBlockEntityElement> {
public static final Factory FACTORY = new Factory();
private final LazyReference<List<Object>> lazyMetadataPacket;
private final LazyReference<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;
public ItemDisplayBlockEntityElementConfig(LazyReference<Item<?>> item,
Vector3f scale,
Vector3f position,
Vector3f translation,
float xRot,
float yRot,
Quaternionf rotation,
ItemDisplayContext displayContext,
Billboard billboard) {
this.item = item;
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.lazyMetadataPacket = LazyReference.lazyReference(() -> {
List<Object> dataValues = new ArrayList<>();
ItemDisplayEntityData.DisplayedItem.addEntityDataIfNotDefaultValue(item.get().getLiteralObject(), dataValues);
ItemDisplayEntityData.Scale.addEntityDataIfNotDefaultValue(this.scale, dataValues);
ItemDisplayEntityData.RotationLeft.addEntityDataIfNotDefaultValue(this.rotation, dataValues);
ItemDisplayEntityData.BillboardConstraints.addEntityDataIfNotDefaultValue(this.billboard.id(), dataValues);
ItemDisplayEntityData.Translation.addEntityDataIfNotDefaultValue(this.translation, dataValues);
ItemDisplayEntityData.DisplayType.addEntityDataIfNotDefaultValue(this.displayContext.id(), dataValues);
return dataValues;
});
}
@Override
public ItemDisplayBlockEntityElement create(BlockPos pos) {
return new ItemDisplayBlockEntityElement(this, pos);
}
public Item<?> item() {
return this.item.get();
}
public Vector3f scale() {
return this.scale;
}
public Vector3f translation() {
return this.translation;
}
public Vector3f position() {
return this.position;
}
public float yRot() {
return this.yRot;
}
public float xRot() {
return this.xRot;
}
public Billboard billboard() {
return billboard;
}
public ItemDisplayContext displayContext() {
return displayContext;
}
public Quaternionf rotation() {
return rotation;
}
public LazyReference<List<Object>> metadataValues() {
return this.lazyMetadataPacket;
}
public static class Factory implements BlockEntityElementConfigFactory {
@SuppressWarnings("unchecked")
@Override
public <E extends BlockEntityElement> BlockEntityElementConfig<E> create(Map<String, Object> arguments) {
// todo item should not be null
Key itemId = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("item"), ""));
return (BlockEntityElementConfig<E>) new ItemDisplayBlockEntityElementConfig(
LazyReference.lazyReference(() -> BukkitItemManager.instance().createWrappedItem(itemId, 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"),
ItemDisplayContext.valueOf(arguments.getOrDefault("display-context", "none").toString().toUpperCase(Locale.ROOT)),
Billboard.valueOf(arguments.getOrDefault("billboard", "fixed").toString().toUpperCase(Locale.ROOT))
);
}
}
}

View File

@@ -5,6 +5,7 @@ import net.momirealms.craftengine.bukkit.advancement.BukkitAdvancementManager;
import net.momirealms.craftengine.bukkit.api.event.CraftEngineReloadEvent;
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
import net.momirealms.craftengine.bukkit.block.behavior.BukkitBlockBehaviors;
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.hitbox.BukkitHitBoxTypes;
import net.momirealms.craftengine.bukkit.entity.projectile.BukkitProjectileManager;
@@ -189,6 +190,7 @@ public class BukkitCraftEngine extends CraftEngine {
BukkitBlockBehaviors.init();
BukkitItemBehaviors.init();
BukkitHitBoxTypes.init();
BukkitBlockEntityElementConfigs.init();
PacketConsumers.initEntities(RegistryUtils.currentEntityTypeRegistrySize());
super.packManager = new BukkitPackManager(this);
super.senderFactory = new BukkitSenderFactory(this);

View File

@@ -4,7 +4,7 @@ import net.momirealms.craftengine.bukkit.block.entity.renderer.BukkitBlockEntity
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.util.LightUtils;
import net.momirealms.craftengine.core.block.entity.render.BlockEntityRenderer;
import net.momirealms.craftengine.core.block.entity.render.BlockEntityRendererConfig;
import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElement;
import net.momirealms.craftengine.core.plugin.config.Config;
import net.momirealms.craftengine.core.util.SectionPosUtils;
import net.momirealms.craftengine.core.world.*;
@@ -45,11 +45,11 @@ public class BukkitCEWorld extends CEWorld {
}
@Override
public BlockEntityRenderer createBlockEntityRenderer(BlockEntityRendererConfig config, BlockPos pos) {
public BlockEntityRenderer createBlockEntityRenderer(BlockEntityElement[] elements, BlockPos pos) {
Object serverLevel = this.world.serverWorld();
Object chunkSource = FastNMS.INSTANCE.method$ServerLevel$getChunkSource(serverLevel);
long chunkKey = ChunkPos.asLong(pos.x() >> 4, pos.z() >> 4);
Object chunkHolder = FastNMS.INSTANCE.method$ServerChunkCache$getVisibleChunkIfPresent(chunkSource, chunkKey);
return new BukkitBlockEntityRenderer(new WeakReference<>(chunkHolder), config, pos);
return new BukkitBlockEntityRenderer(new WeakReference<>(chunkHolder), elements);
}
}