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

添加堆肥物品

This commit is contained in:
XiaoMoMi
2025-06-12 17:57:43 +08:00
parent 034182fb61
commit 76787a92f6
25 changed files with 167 additions and 54 deletions

View File

@@ -52,7 +52,7 @@ public final class CraftEngineFurniture {
public static BukkitFurniture place(Location location, Key furnitureId) {
CustomFurniture furniture = byId(furnitureId);
if (furniture == null) return null;
return place(location, furnitureId, furniture.getAnyPlacement());
return place(location, furnitureId, furniture.getAnyAnchorType());
}
/**

View File

@@ -65,7 +65,7 @@ public abstract class AbstractCanSurviveBlockBehavior extends BukkitBlockBehavio
public void onPlace(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
Object world = args[1];
Object blockPos = args[2];
CoreReflections.method$LevelAccessor$scheduleTick.invoke(world, blockPos, thisBlock, 2);
FastNMS.INSTANCE.method$LevelAccessor$scheduleTick(world, blockPos, thisBlock, 2);
}
@Override
@@ -86,7 +86,7 @@ public abstract class AbstractCanSurviveBlockBehavior extends BukkitBlockBehavio
return state;
}
if (this.delay != 0) {
CoreReflections.method$LevelAccessor$scheduleTick.invoke(level, blockPos, thisBlock, this.delay);
FastNMS.INSTANCE.method$LevelAccessor$scheduleTick(level, blockPos, thisBlock, this.delay);
return state;
}
if (!canSurvive(thisBlock, new Object[] {state, level, blockPos}, () -> true)) {

View File

@@ -36,7 +36,7 @@ public class FallingBlockBehavior extends BukkitBlockBehavior {
public void onPlace(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
Object world = args[1];
Object blockPos = args[2];
CoreReflections.method$LevelAccessor$scheduleTick.invoke(world, blockPos, thisBlock, 2);
FastNMS.INSTANCE.method$LevelAccessor$scheduleTick(world, blockPos, thisBlock, 2);
}
@Override
@@ -50,7 +50,7 @@ public class FallingBlockBehavior extends BukkitBlockBehavior {
world = args[3];
blockPos = args[4];
}
CoreReflections.method$LevelAccessor$scheduleTick.invoke(world, blockPos, thisBlock, 2);
FastNMS.INSTANCE.method$LevelAccessor$scheduleTick(world, blockPos, thisBlock, 2);
return args[0];
}

View File

@@ -62,7 +62,7 @@ public class LampBlockBehavior extends BukkitBlockBehavior {
boolean lit = state.get(this.litProperty);
if (lit != FastNMS.INSTANCE.method$SignalGetter$hasNeighborSignal(world, blockPos)) {
if (lit) {
CoreReflections.method$LevelAccessor$scheduleTick.invoke(world, blockPos, thisBlock, 4);
FastNMS.INSTANCE.method$LevelAccessor$scheduleTick(world, blockPos, thisBlock, 4);
} else {
// TODO Call Event
FastNMS.INSTANCE.method$LevelWriter$setBlock(world, blockPos, state.cycle(this.litProperty).customBlockState().handle(), 2);

View File

@@ -85,7 +85,7 @@ public class LeavesBlockBehavior extends WaterLoggedBlockBehavior {
LeavesBlockBehavior behavior = optionalBehavior.get();
int distance = behavior.getDistanceAt(neighborState) + 1;
if (distance != 1 || behavior.getDistance(thisState) != distance) {
CoreReflections.method$LevelAccessor$scheduleTick.invoke(world, blockPos, thisBlock, 1);
FastNMS.INSTANCE.method$LevelAccessor$scheduleTick(world, blockPos, thisBlock, 1);
}
}
}

View File

@@ -32,7 +32,7 @@ import java.util.*;
public class BukkitFurniture implements Furniture {
private final Key id;
private final CustomFurniture furniture;
private final AnchorType anchorType;
private final CustomFurniture.Placement placement;
private FurnitureExtraData extraData;
// location
private final Location location;
@@ -61,7 +61,7 @@ public class BukkitFurniture implements Furniture {
this.id = furniture.id();
this.extraData = extraData;
this.baseEntityId = baseEntity.getEntityId();
this.anchorType = extraData.anchorType().orElse(furniture.getAnyPlacement());
this.location = baseEntity.getLocation();
this.baseEntity = new WeakReference<>(baseEntity);
this.furniture = furniture;
@@ -70,7 +70,7 @@ public class BukkitFurniture implements Furniture {
List<Integer> mainEntityIds = new IntArrayList();
mainEntityIds.add(this.baseEntityId);
CustomFurniture.Placement placement = furniture.getPlacement(anchorType);
this.placement = furniture.getValidPlacement(extraData.anchorType().orElseGet(furniture::getAnyAnchorType));
// bind external furniture
Optional<ExternalModel> optionalExternal = placement.externalModel();
if (optionalExternal.isPresent()) {
@@ -171,7 +171,7 @@ public class BukkitFurniture implements Furniture {
@NotNull
public Location dropLocation() {
Optional<Vector3f> dropOffset = config().getPlacement(this.anchorType).dropOffset();
Optional<Vector3f> dropOffset = this.placement.dropOffset();
if (dropOffset.isEmpty()) {
return location();
}
@@ -275,7 +275,7 @@ public class BukkitFurniture implements Furniture {
@Override
public @NotNull AnchorType anchorType() {
return this.anchorType;
return this.placement.anchorType();
}
@Override

View File

@@ -70,7 +70,7 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
public BukkitFurniture place(Location location, CustomFurniture furniture, FurnitureExtraData extraData, boolean playSound) {
Optional<AnchorType> optionalAnchorType = extraData.anchorType();
if (optionalAnchorType.isEmpty() || !furniture.isAllowedPlacement(optionalAnchorType.get())) {
extraData.anchorType(furniture.getAnyPlacement());
extraData.anchorType(furniture.getAnyAnchorType());
}
Entity furnitureEntity = EntityUtils.spawnEntity(location.getWorld(), location, EntityType.ITEM_DISPLAY, entity -> {
ItemDisplay display = (ItemDisplay) entity;

View File

@@ -165,4 +165,9 @@ public class ComponentItemWrapper implements ItemWrapper<ItemStack> {
public void count(int amount) {
this.item.setAmount(Math.max(amount, 0));
}
@Override
public void shrink(int amount) {
count(count() - amount);
}
}

View File

@@ -8,18 +8,9 @@ import org.bukkit.inventory.ItemStack;
public class LegacyItemWrapper implements ItemWrapper<ItemStack> {
private final RtagItem rtagItem;
private int count;
public LegacyItemWrapper(RtagItem rtagItem, int count) {
public LegacyItemWrapper(RtagItem rtagItem) {
this.rtagItem = rtagItem;
this.count = count;
}
@Override
public ItemStack getItem() {
ItemStack itemStack = this.rtagItem.getItem();
itemStack.setAmount(this.count);
return itemStack;
}
public boolean setTag(Object value, Object... path) {
@@ -49,12 +40,12 @@ public class LegacyItemWrapper implements ItemWrapper<ItemStack> {
}
public int count() {
return this.count;
return getItem().getAmount();
}
public void count(int amount) {
if (amount < 0) amount = 0;
this.count = amount;
getItem().setAmount(amount);
}
public Object getExactTag(Object... path) {
@@ -75,9 +66,12 @@ public class LegacyItemWrapper implements ItemWrapper<ItemStack> {
@Override
public ItemStack load() {
ItemStack itemStack = this.rtagItem.load();
itemStack.setAmount(Math.max(this.count, 0));
return itemStack;
return this.rtagItem.load();
}
@Override
public ItemStack getItem() {
return this.rtagItem.getItem();
}
@Override
@@ -87,6 +81,13 @@ public class LegacyItemWrapper implements ItemWrapper<ItemStack> {
@Override
public ItemWrapper<ItemStack> copyWithCount(int count) {
return new LegacyItemWrapper(new RtagItem(this.rtagItem.loadCopy()), count);
ItemStack copied = this.rtagItem.loadCopy();
copied.setAmount(count);
return new LegacyItemWrapper(new RtagItem(copied));
}
@Override
public void shrink(int amount) {
this.count(count() - amount);
}
}

View File

@@ -11,6 +11,7 @@ public class BukkitItemBehaviors extends ItemBehaviors {
public static final Key WATER_BUCKET_ITEM = Key.from("craftengine:water_bucket_item");
public static final Key BUCKET_ITEM = Key.from("craftengine:bucket_item");
public static final Key FLINT_AND_STEEL_ITEM = Key.from("craftengine:flint_and_steel_item");
public static final Key COMPOSTABLE_ITEM = Key.from("craftengine:compostable_item");
public static void init() {
register(EMPTY, EmptyItemBehavior.FACTORY);
@@ -20,5 +21,6 @@ public class BukkitItemBehaviors extends ItemBehaviors {
register(WATER_BUCKET_ITEM, WaterBucketItemBehavior.FACTORY);
register(BUCKET_ITEM, BucketItemBehavior.FACTORY);
register(FLINT_AND_STEEL_ITEM, FlintAndSteelItemBehavior.FACTORY);
register(COMPOSTABLE_ITEM, CompostableItemBehavior.FACTORY);
}
}

View File

@@ -0,0 +1,80 @@
package net.momirealms.craftengine.bukkit.item.behavior;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlocks;
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
import net.momirealms.craftengine.bukkit.util.EventUtils;
import net.momirealms.craftengine.bukkit.util.LocationUtils;
import net.momirealms.craftengine.bukkit.world.BukkitBlockInWorld;
import net.momirealms.craftengine.core.entity.player.InteractionResult;
import net.momirealms.craftengine.core.item.behavior.ItemBehavior;
import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory;
import net.momirealms.craftengine.core.item.context.UseOnContext;
import net.momirealms.craftengine.core.pack.Pack;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.RandomUtils;
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import net.momirealms.craftengine.core.world.WorldEvents;
import org.bukkit.GameEvent;
import org.bukkit.World;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Levelled;
import org.bukkit.entity.Entity;
import org.bukkit.event.entity.EntityChangeBlockEvent;
import org.bukkit.util.Vector;
import java.nio.file.Path;
import java.util.Map;
public class CompostableItemBehavior extends ItemBehavior {
public static final Factory FACTORY = new Factory();
private final double chance;
public CompostableItemBehavior(double chance) {
this.chance = chance;
}
@Override
public InteractionResult useOnBlock(UseOnContext context) {
BukkitBlockInWorld block = (BukkitBlockInWorld) context.getLevel().getBlockAt(context.getClickedPos());
BlockData blockData = block.block().getBlockData();
Object blockOwner = BlockStateUtils.getBlockOwner(BlockStateUtils.blockDataToBlockState(blockData));
if (blockOwner != MBlocks.COMPOSTER) return InteractionResult.PASS;
if (!(blockData instanceof Levelled levelled)) {
return InteractionResult.PASS;
}
int maxLevel = levelled.getMaximumLevel();
int currentLevel = levelled.getLevel();
if (currentLevel >= maxLevel) return InteractionResult.PASS;
boolean willRaise = (currentLevel == 0) && (this.chance > 0) || (RandomUtils.generateRandomDouble(0, 1) < this.chance);
if (willRaise) {
levelled.setLevel(currentLevel + 1);
EntityChangeBlockEvent event = new EntityChangeBlockEvent((Entity) context.getPlayer().platformPlayer(), block.block(), levelled);
if (EventUtils.fireAndCheckCancel(event)) {
return InteractionResult.FAIL;
}
block.block().setBlockData(levelled);
}
context.getLevel().levelEvent(WorldEvents.COMPOSTER_COMPOSTS, context.getClickedPos(), willRaise ? 1 : 0);
((World) context.getLevel().platformWorld()).sendGameEvent((Entity) context.getPlayer().platformPlayer(), GameEvent.BLOCK_CHANGE, new Vector(block.x() + 0.5, block.y() + 0.5, block.z() + 0.5));
if (currentLevel + 1 == 7) {
FastNMS.INSTANCE.method$LevelAccessor$scheduleTick(context.getLevel().serverWorld(), LocationUtils.toBlockPos(context.getClickedPos()), blockOwner, 20);
}
if (!context.getPlayer().canInstabuild()) {
context.getItem().shrink(1);
}
context.getPlayer().swingHand(context.getHand());
return InteractionResult.SUCCESS;
}
public static class Factory implements ItemBehaviorFactory {
@Override
public ItemBehavior create(Pack pack, Path path, Key key, Map<String, Object> arguments) {
double chance = ResourceConfigUtils.getAsDouble(arguments.getOrDefault("chance", 0.55), "chance");
return new CompostableItemBehavior(chance);
}
}
}

View File

@@ -32,7 +32,7 @@ public class UniversalItemFactory extends BukkitItemFactory<LegacyItemWrapper> {
@Override
protected LegacyItemWrapper wrapInternal(ItemStack item) {
return new LegacyItemWrapper(new RtagItem(item), item.getAmount());
return new LegacyItemWrapper(new RtagItem(item));
}
@Override
@@ -308,10 +308,10 @@ public class UniversalItemFactory extends BukkitItemFactory<LegacyItemWrapper> {
@Override
protected LegacyItemWrapper mergeCopy(LegacyItemWrapper item1, LegacyItemWrapper item2) {
Object itemStack = ItemObject.copy(item2.getLiteralObject());
ItemObject.setCustomDataTag(itemStack, TagCompound.clone(ItemObject.getCustomDataTag(item1.getLiteralObject())));
ItemObject.setCustomDataTag(itemStack, TagCompound.clone(FastNMS.INSTANCE.field$ItemStack$getOrCreateTag(item1.getLiteralObject())));
// one more step than vanilla
TagCompound.merge(ItemObject.getCustomDataTag(itemStack), ItemObject.getCustomDataTag(item2.getLiteralObject()), true, true);
return new LegacyItemWrapper(new RtagItem(ItemObject.asCraftMirror(itemStack)), item2.count());
TagCompound.merge(FastNMS.INSTANCE.field$ItemStack$getOrCreateTag(itemStack), FastNMS.INSTANCE.field$ItemStack$getOrCreateTag(item2.getLiteralObject()), true, true);
return new LegacyItemWrapper(new RtagItem(FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(itemStack)));
}
@Override
@@ -326,7 +326,7 @@ public class UniversalItemFactory extends BukkitItemFactory<LegacyItemWrapper> {
@Override
protected LegacyItemWrapper transmuteCopy(LegacyItemWrapper item, Key newItem, int amount) {
Object newItemStack = FastNMS.INSTANCE.constructor$ItemStack(FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.ITEM, KeyUtils.toResourceLocation(newItem)), amount);
ItemObject.setCustomDataTag(newItemStack, TagCompound.clone(ItemObject.getCustomDataTag(item.getLiteralObject())));
return new LegacyItemWrapper(new RtagItem(ItemObject.asCraftMirror(newItemStack)), amount);
ItemObject.setCustomDataTag(newItemStack, TagCompound.clone(FastNMS.INSTANCE.field$ItemStack$getOrCreateTag(item.getLiteralObject())));
return new LegacyItemWrapper(new RtagItem(ItemObject.asCraftMirror(newItemStack)));
}
}

View File

@@ -73,7 +73,7 @@ public class DebugStickListener implements Listener {
ComponentUtils.adventureToMinecraft(Component.translatable("item.minecraft.debug_stick.empty").arguments(Component.text(blockId))), true);
player.sendPacket(systemChatPacket, false);
} else {
LegacyItemWrapper wrapped = new LegacyItemWrapper(new RtagItem(itemInHand), itemInHand.getAmount());
LegacyItemWrapper wrapped = new LegacyItemWrapper(new RtagItem(itemInHand));
Object storedData = wrapped.getJavaTag("craftengine:debug_stick_state");
if (storedData == null) storedData = new HashMap<>();
if (storedData instanceof Map<?,?> map) {

View File

@@ -54,7 +54,7 @@ public class DebugSpawnFurnitureCommand extends BukkitCommandFeature<CommandSend
}
Location location = context.get("location");
CustomFurniture customFurniture = optionalCustomFurniture.get();
AnchorType anchorType = (AnchorType) context.optional("anchor-type").orElse(customFurniture.getAnyPlacement());
AnchorType anchorType = (AnchorType) context.optional("anchor-type").orElse(customFurniture.getAnyAnchorType());
boolean playSound = context.flags().hasFlag("silent");
CraftEngineFurniture.place(location, customFurniture, anchorType, playSound);
});

View File

@@ -1356,10 +1356,6 @@ public final class CoreReflections {
ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, clazz$VoxelShape, new String[]{"getBlockSupportShape", "b_"}, clazz$BlockState, clazz$BlockGetter, CoreReflections.clazz$BlockPos)
);
public static final Method method$LevelAccessor$scheduleTick = requireNonNull(
ReflectionUtils.getMethod(clazz$LevelAccessor, void.class, CoreReflections.clazz$BlockPos, clazz$Block, int.class)
);
public static final Field field$BlockBehaviour$properties = requireNonNull(
ReflectionUtils.getInstanceDeclaredField(clazz$BlockBehaviour, clazz$BlockBehaviour$Properties, 0)
);

View File

@@ -17,6 +17,7 @@ public final class MBlocks {
public static final Object SHORT_GRASS;
public static final Object SHORT_GRASS$defaultState;
public static final Object SHULKER_BOX;
public static final Object COMPOSTER;
private static Object getById(String id) throws ReflectiveOperationException {
Object rl = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", id);
@@ -35,6 +36,7 @@ public final class MBlocks {
SHORT_GRASS = getById(VersionHelper.isOrAbove1_20_3() ? "short_grass" : "grass");
SHORT_GRASS$defaultState = CoreReflections.method$Block$defaultBlockState.invoke(SHORT_GRASS);
SHULKER_BOX = getById("shulker_box");
COMPOSTER = getById("composter");
} catch (ReflectiveOperationException e) {
throw new ReflectionInitException("Failed to init Blocks", e);
}

View File

@@ -1,20 +1,14 @@
package net.momirealms.craftengine.bukkit.world;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.util.EntityUtils;
import net.momirealms.craftengine.bukkit.util.ItemUtils;
import net.momirealms.craftengine.bukkit.util.ParticleUtils;
import net.momirealms.craftengine.bukkit.util.SoundUtils;
import net.momirealms.craftengine.bukkit.util.*;
import net.momirealms.craftengine.core.block.BlockStateWrapper;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.plugin.context.Context;
import net.momirealms.craftengine.core.sound.SoundSource;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.VersionHelper;
import net.momirealms.craftengine.core.world.BlockInWorld;
import net.momirealms.craftengine.core.world.Position;
import net.momirealms.craftengine.core.world.World;
import net.momirealms.craftengine.core.world.WorldHeight;
import net.momirealms.craftengine.core.world.*;
import net.momirealms.craftengine.core.world.particle.ParticleData;
import org.bukkit.Location;
import org.bukkit.Particle;
@@ -124,4 +118,9 @@ public class BukkitWorld implements World {
Object blockPos = FastNMS.INSTANCE.constructor$BlockPos(x, y, z);
FastNMS.INSTANCE.method$LevelWriter$setBlock(worldServer, blockPos, blockState.handle(), flags);
}
@Override
public void levelEvent(int id, BlockPos pos, int data) {
FastNMS.INSTANCE.method$Level$levelEvent(serverWorld(), id, LocationUtils.toBlockPos(pos), data);
}
}