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

添加 item 渲染

This commit is contained in:
XiaoMoMi
2025-11-08 21:40:17 +08:00
parent 1565d342db
commit b834e981c2
9 changed files with 169 additions and 2 deletions

View File

@@ -290,6 +290,10 @@ public final class BukkitBlockManager extends AbstractBlockManager {
this.burnOdds.put(nmsBlock, settings.fireSpreadChance());
this.burnableBlocks.add(nmsBlock);
}
Key vanillaBlockId = state.vanillaBlockState().ownerId();
BlockGenerator.field$CraftEngineBlock$isNoteBlock().set(nmsBlock, vanillaBlockId.equals(BlockKeys.NOTE_BLOCK));
BlockGenerator.field$CraftEngineBlock$isTripwire().set(nmsBlock, vanillaBlockId.equals(BlockKeys.TRIPWIRE));
} catch (ReflectiveOperationException e) {
this.plugin.logger().warn("Failed to apply platform block settings for block state " + state, e);
}

View File

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

View File

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

View File

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

View File

@@ -42,7 +42,7 @@ public class ItemDisplayBlockEntityElement implements BlockEntityElement {
@Override
public void show(Player player) {
player.sendPackets(List.of(this.cachedSpawnPacket, FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(this.entityId, this.config.metadataValues(player))), true);
player.sendPackets(List.of(this.cachedSpawnPacket, FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(this.entityId, this.config.metadataValues(player))), false);
}
@Override

View File

@@ -42,7 +42,7 @@ public class TextDisplayBlockEntityElement implements BlockEntityElement {
@Override
public void show(Player player) {
player.sendPackets(List.of(this.cachedSpawnPacket, FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(this.entityId, this.config.metadataValues(player))), true);
player.sendPackets(List.of(this.cachedSpawnPacket, FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(this.entityId, this.config.metadataValues(player))), false);
}
@Override

View File

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

View File

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

View File

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