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

Merge branch 'Xiao-MoMi:dev' into dev

This commit is contained in:
jhqwqmc
2025-04-27 15:03:40 +08:00
committed by GitHub
22 changed files with 670 additions and 55 deletions

View File

@@ -15,7 +15,6 @@ import net.momirealms.craftengine.bukkit.compatibility.viaversion.ViaVersionUtil
import net.momirealms.craftengine.bukkit.compatibility.worldedit.WorldEditBlockRegister;
import net.momirealms.craftengine.bukkit.font.BukkitFontManager;
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.core.entity.furniture.AbstractExternalModel;
import net.momirealms.craftengine.core.entity.player.Player;
@@ -25,7 +24,6 @@ import net.momirealms.craftengine.core.util.VersionHelper;
import net.momirealms.craftengine.core.world.WorldManager;
import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
import org.bukkit.scheduler.BukkitTask;
import java.util.UUID;
@@ -55,18 +53,19 @@ public class BukkitCompatibilityManager implements CompatibilityManager {
SkriptHook.register();
logHook("Skript");
Plugin skriptPlugin = getPlugin("Skript");
for (BukkitTask task : Bukkit.getScheduler().getPendingTasks()) {
if (task.getOwner() == skriptPlugin) {
task.cancel();
if (VersionHelper.isFolia()) {
Bukkit.getGlobalRegionScheduler().run(skriptPlugin, (t) -> {
FastNMS.INSTANCE.getBukkitTaskRunnable(task).run();
});
} else {
Bukkit.getScheduler().runTask(skriptPlugin, FastNMS.INSTANCE.getBukkitTaskRunnable(task));
}
}
}
// This can cause bugs, needs to find a better way
// for (BukkitTask task : Bukkit.getScheduler().getPendingTasks()) {
// if (task.getOwner() == skriptPlugin) {
// task.cancel();
// if (VersionHelper.isFolia()) {
// Bukkit.getGlobalRegionScheduler().run(skriptPlugin, (t) -> {
// FastNMS.INSTANCE.getBukkitTaskRunnable(task).run();
// });
// } else {
// Bukkit.getScheduler().runTask(skriptPlugin, FastNMS.INSTANCE.getBukkitTaskRunnable(task));
// }
// }
// }
}
}

View File

@@ -2,24 +2,30 @@ package net.momirealms.craftengine.bukkit.compatibility.skript;
import net.momirealms.craftengine.bukkit.compatibility.skript.clazz.CraftEngineClasses;
import net.momirealms.craftengine.bukkit.compatibility.skript.condition.CondIsCustomBlock;
import net.momirealms.craftengine.bukkit.compatibility.skript.condition.CondIsCustomItem;
import net.momirealms.craftengine.bukkit.compatibility.skript.condition.CondIsFurniture;
import net.momirealms.craftengine.bukkit.compatibility.skript.effect.EffPlaceCustomBlock;
import net.momirealms.craftengine.bukkit.compatibility.skript.effect.EffPlaceFurniture;
import net.momirealms.craftengine.bukkit.compatibility.skript.effect.EffRemoveFurniture;
import net.momirealms.craftengine.bukkit.compatibility.skript.event.EvtCustomBlock;
import net.momirealms.craftengine.bukkit.compatibility.skript.expression.ExprBlockCustomBlockID;
import net.momirealms.craftengine.bukkit.compatibility.skript.expression.ExprBlockCustomBlockState;
import net.momirealms.craftengine.bukkit.compatibility.skript.expression.ExprEntityFurnitureID;
import net.momirealms.craftengine.bukkit.compatibility.skript.event.EvtCustomClick;
import net.momirealms.craftengine.bukkit.compatibility.skript.event.EvtCustomFurniture;
import net.momirealms.craftengine.bukkit.compatibility.skript.expression.*;
public class SkriptHook {
public static void register() {
CraftEngineClasses.register();
EvtCustomBlock.register();
EvtCustomFurniture.register();
EvtCustomClick.register();
CondIsCustomBlock.register();
CondIsFurniture.register();
CondIsCustomItem.register();
ExprBlockCustomBlockID.register();
ExprItemCustomItemID.register();
ExprBlockCustomBlockState.register();
ExprCustomItem.register();
ExprEntityFurnitureID.register();
EffPlaceCustomBlock.register();
EffPlaceFurniture.register();

View File

@@ -8,6 +8,7 @@ import ch.njol.skript.registrations.Classes;
import ch.njol.yggdrasil.Fields;
import net.momirealms.craftengine.core.block.BlockStateParser;
import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.block.UnsafeBlockStateMatcher;
import org.jetbrains.annotations.Nullable;
import java.io.StreamCorruptedException;
@@ -68,5 +69,59 @@ public class CraftEngineClasses {
}
})
);
Classes.registerClass(new ClassInfo<>(UnsafeBlockStateMatcher.class, "unsafeblockstatematcher")
.user("unsafe block state matcher")
.name("Unsafe Block State Matcher")
.serializer(new Serializer<>() {
@Override
public Fields serialize(UnsafeBlockStateMatcher o) {
Fields f = new Fields();
f.putObject("unsafeblockstatematcher", o.toString());
return f;
}
@Override
public void deserialize(UnsafeBlockStateMatcher o, Fields f) {
}
@Override
public UnsafeBlockStateMatcher deserialize(Fields f) throws StreamCorruptedException {
String data = f.getObject("unsafeblockstatematcher", String.class);
assert data != null;
try {
return UnsafeBlockStateMatcher.deserialize(data);
} catch (IllegalArgumentException ex) {
throw new StreamCorruptedException("Invalid block matcher: " + data);
}
}
@Override
public boolean mustSyncDeserialization() {
return true;
}
@Override
protected boolean canBeInstantiated() {
return false;
}
})
.parser(new Parser<>() {
@Override
public String toString(UnsafeBlockStateMatcher o, int flags) {
return o.toString();
}
@Override
public String toVariableNameString(UnsafeBlockStateMatcher o) {
return "unsafeblockstatematcher:" + o.toString();
}
@Override
public @Nullable UnsafeBlockStateMatcher parse(String s, ParseContext context) {
return UnsafeBlockStateMatcher.deserialize(s);
}
})
);
}
}

View File

@@ -0,0 +1,41 @@
package net.momirealms.craftengine.bukkit.compatibility.skript.condition;
import ch.njol.skript.Skript;
import ch.njol.skript.conditions.base.PropertyCondition;
import ch.njol.skript.lang.Condition;
import ch.njol.skript.lang.Expression;
import ch.njol.skript.lang.SkriptParser;
import ch.njol.util.Kleenean;
import net.momirealms.craftengine.bukkit.api.CraftEngineItems;
import org.bukkit.event.Event;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.Nullable;
public class CondIsCustomItem extends Condition {
public static void register() {
Skript.registerCondition(CondIsCustomItem.class,
"%itemstacks% (is|are) custom item(s)",
"%itemstacks% (is|are)(n't| not) custom item(s)");
}
private Expression<ItemStack> items;
@Override
public boolean check(Event event) {
return items.check(event, CraftEngineItems::isCustomItem, isNegated());
}
@Override
public String toString(@Nullable Event event, boolean debug) {
return PropertyCondition.toString(this, PropertyCondition.PropertyType.BE, event, debug, items, "itemstack");
}
@SuppressWarnings("unchecked")
@Override
public boolean init(Expression<?>[] expressions, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) {
items = (Expression<ItemStack>) expressions[0];
setNegated(matchedPattern > 1);
return true;
}
}

View File

@@ -4,12 +4,9 @@ import ch.njol.skript.Skript;
import ch.njol.skript.lang.Effect;
import ch.njol.skript.lang.Expression;
import ch.njol.skript.lang.SkriptParser;
import ch.njol.skript.util.Direction;
import ch.njol.util.Kleenean;
import net.momirealms.craftengine.bukkit.api.CraftEngineFurniture;
import net.momirealms.craftengine.bukkit.entity.furniture.LoadedFurniture;
import net.momirealms.craftengine.core.util.Key;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.bukkit.event.Event;
import org.jetbrains.annotations.Nullable;

View File

@@ -4,10 +4,11 @@ import ch.njol.skript.Skript;
import ch.njol.skript.lang.Literal;
import ch.njol.skript.lang.SkriptEvent;
import ch.njol.skript.lang.SkriptParser;
import ch.njol.util.StringUtils;
import net.momirealms.craftengine.bukkit.api.event.CustomBlockBreakEvent;
import net.momirealms.craftengine.bukkit.api.event.CustomBlockPlaceEvent;
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.block.UnsafeBlockStateMatcher;
import net.momirealms.craftengine.core.entity.player.InteractionHand;
import org.bukkit.event.Event;
import org.jetbrains.annotations.Nullable;
@@ -18,21 +19,21 @@ import java.util.Arrays;
public class EvtCustomBlock extends SkriptEvent {
public static void register() {
Skript.registerEvent("Break Custom Block", EvtCustomBlock.class, CustomBlockBreakEvent.class, "[customblock] (break[ing]|1¦min(e|ing)) [[of] %-strings%]")
Skript.registerEvent("Break Custom Block", EvtCustomBlock.class, CustomBlockBreakEvent.class, "(break[ing]|1¦min(e|ing)) [[of] %-unsafeblockstatematchers%]")
.description("Called when a custom block is broken by a player. If you use 'on mine', only events where the broken block dropped something will call the trigger.");
Skript.registerEvent("Place Custom Block", EvtCustomBlock.class, CustomBlockPlaceEvent.class, "[customblock] (plac(e|ing)|build[ing]) [[of] %-strings%]")
Skript.registerEvent("Place Custom Block", EvtCustomBlock.class, CustomBlockPlaceEvent.class, "(plac(e|ing)|build[ing]) [[of] %-unsafeblockstatematchers%]")
.description("Called when a player places a custom block.");
}
@Nullable
private Literal<String> blocks;
private String[] blockArray;
private Literal<UnsafeBlockStateMatcher> blocks;
private UnsafeBlockStateMatcher[] blockArray;
private boolean mine = false;
@Override
public boolean init(Literal<?>[] args, int matchedPattern, SkriptParser.ParseResult parser) {
if (args[0] != null) {
blocks = ((Literal<String>) args[0]);
blocks = ((Literal<UnsafeBlockStateMatcher>) args[0]);
blockArray = blocks.getAll();
}
mine = parser.mark == 1;
@@ -49,19 +50,16 @@ public class EvtCustomBlock extends SkriptEvent {
if (blocks == null)
return true;
String blockType;
String blockState;
ImmutableBlockState state;
if (event instanceof CustomBlockBreakEvent customBlockBreakEvent) {
blockType = customBlockBreakEvent.customBlock().id().toString();
blockState = customBlockBreakEvent.blockState().toString();
state = customBlockBreakEvent.blockState();
} else if (event instanceof CustomBlockPlaceEvent customBlockPlaceEvent) {
blockType = customBlockPlaceEvent.customBlock().id().toString();
blockState = customBlockPlaceEvent.blockState().toString();
state = customBlockPlaceEvent.blockState();
} else {
return false;
}
return Arrays.stream(blockArray).anyMatch(block -> StringUtils.equals(blockType, block, true) || StringUtils.equals(blockState, block, true));
return Arrays.stream(blockArray).anyMatch(block -> block.matches(state));
}
@Override

View File

@@ -0,0 +1,110 @@
package net.momirealms.craftengine.bukkit.compatibility.skript.event;
import ch.njol.skript.Skript;
import ch.njol.skript.aliases.ItemType;
import ch.njol.skript.bukkitutil.ClickEventTracker;
import ch.njol.skript.lang.Literal;
import ch.njol.skript.lang.SkriptEvent;
import ch.njol.skript.lang.SkriptParser;
import net.momirealms.craftengine.bukkit.api.event.CustomBlockInteractEvent;
import net.momirealms.craftengine.bukkit.api.event.FurnitureInteractEvent;
import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.block.UnsafeBlockStateMatcher;
import net.momirealms.craftengine.core.entity.player.InteractionHand;
import org.bukkit.event.Event;
import org.bukkit.inventory.EquipmentSlot;
import org.jetbrains.annotations.Nullable;
import java.util.function.Predicate;
public class EvtCustomClick extends SkriptEvent {
private final static int RIGHT = 1, LEFT = 2, ANY = RIGHT | LEFT;
public final static ClickEventTracker interactTracker = new ClickEventTracker(Skript.getInstance());
public static void register() {
Skript.registerEvent("Interact Custom Block Furniture", EvtCustomClick.class, new Class[]{CustomBlockInteractEvent.class, FurnitureInteractEvent.class},
"[(" + RIGHT + ":right|" + LEFT + ":left)(| |-)][mouse(| |-)]click[ing] [on %-unsafeblockstatematchers/strings%] [(with|using|holding) %-itemtype%]",
"[(" + RIGHT + ":right|" + LEFT + ":left)(| |-)][mouse(| |-)]click[ing] (with|using|holding) %itemtype% on %unsafeblockstatematchers/strings%");
}
private @Nullable Literal<?> type;
private @Nullable Literal<ItemType> tools;
private int click = ANY;
@Override
public boolean check(Event event) {
ImmutableBlockState block;
String furnitureId;
if (event instanceof CustomBlockInteractEvent interactEvent) {
furnitureId = null;
CustomBlockInteractEvent.Action action = interactEvent.action();
int click;
switch (action) {
case LEFT_CLICK -> click = LEFT;
case RIGHT_CLICK -> click = RIGHT;
default -> {
return false;
}
}
if ((this.click & click) == 0)
return false;
EquipmentSlot hand = interactEvent.hand() == InteractionHand.MAIN_HAND ? EquipmentSlot.HAND : EquipmentSlot.OFF_HAND;
if (!interactTracker.checkEvent(interactEvent.getPlayer(), interactEvent, hand)) {
return false;
}
block = interactEvent.blockState();
} else if (event instanceof FurnitureInteractEvent interactEvent) {
furnitureId = interactEvent.furniture().id().toString();
block = null;
if ((this.click & RIGHT) == 0)
return false;
} else {
return false;
}
Predicate<ItemType> checker = itemType -> {
if (event instanceof CustomBlockInteractEvent event1) {
return itemType.isOfType(event1.item());
} else if (event instanceof FurnitureInteractEvent event1) {
return itemType.isOfType(event1.player().getInventory().getItem(event1.hand() == InteractionHand.MAIN_HAND ? EquipmentSlot.HAND : EquipmentSlot.OFF_HAND));
} else {
return false;
}
};
if (tools != null && !tools.check(event, checker))
return false;
if (type != null) {
return type.check(event, (Predicate<Object>) object -> {
if (object instanceof String id && furnitureId != null) {
return id.equals(furnitureId);
} else if (object instanceof UnsafeBlockStateMatcher matcher && block != null) {
return matcher.matches(block);
}
return false;
});
}
return true;
}
@SuppressWarnings("unchecked")
@Override
public boolean init(Literal<?>[] args, int matchedPattern, SkriptParser.ParseResult parseResult) {
click = parseResult.mark == 0 ? ANY : parseResult.mark;
type = args[matchedPattern];
tools = (Literal<ItemType>) args[1 - matchedPattern];
return true;
}
@Override
public String toString(@Nullable Event event, boolean debug) {
return switch (click) {
case LEFT -> "left";
case RIGHT -> "right";
default -> "";
} + "click" + (type != null ? " on " + type.toString(event, debug) : "") +
(tools != null ? " holding " + tools.toString(event, debug) : "");
}
}

View File

@@ -0,0 +1,58 @@
package net.momirealms.craftengine.bukkit.compatibility.skript.event;
import ch.njol.skript.Skript;
import ch.njol.skript.lang.Literal;
import ch.njol.skript.lang.SkriptEvent;
import ch.njol.skript.lang.SkriptParser;
import net.momirealms.craftengine.bukkit.api.event.FurnitureBreakEvent;
import net.momirealms.craftengine.bukkit.api.event.FurniturePlaceEvent;
import org.bukkit.event.Event;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
@SuppressWarnings({"unchecked"})
public class EvtCustomFurniture extends SkriptEvent {
public static void register() {
Skript.registerEvent("Break Furniture", EvtCustomFurniture.class, FurnitureBreakEvent.class, "(break[ing]) [[of] %-strings%]")
.description("Called when a furniture is broken by a player.");
Skript.registerEvent("Place Furniture", EvtCustomFurniture.class, FurniturePlaceEvent.class, "(plac(e|ing)|build[ing]) [[of] %-strings%]")
.description("Called when a player places a furniture.");
}
@Nullable
private Literal<String> ids;
private String[] idArray;
@Override
public boolean init(Literal<?>[] args, int matchedPattern, SkriptParser.ParseResult parser) {
if (args[0] != null) {
ids = ((Literal<String>) args[0]);
idArray = ids.getAll();
}
return true;
}
@Override
public boolean check(Event event) {
if (ids == null)
return true;
String id;
if (event instanceof FurnitureBreakEvent e) {
id = e.furniture().id().toString();
} else if (event instanceof FurniturePlaceEvent e) {
id = e.furniture().id().toString();
} else {
return false;
}
return Arrays.asList(idArray).contains(id);
}
@Override
public String toString(@Nullable Event event, boolean debug) {
return "break/place" + (ids != null ? " of " + ids.toString(event, debug) : "");
}
}

View File

@@ -13,7 +13,7 @@ import java.util.Optional;
public class ExprBlockCustomBlockID extends SimplePropertyExpression<Object, String> {
public static void register() {
register(ExprBlockCustomBlockID.class, String.class, "block[ ]custom block id", "blocks/blockdata/customblockstates");
register(ExprBlockCustomBlockID.class, String.class, "custom block id", "blocks/blockdata/customblockstates");
}
@Override

View File

@@ -10,7 +10,7 @@ import org.jetbrains.annotations.Nullable;
public class ExprBlockCustomBlockState extends SimplePropertyExpression<Object, ImmutableBlockState> {
public static void register() {
register(ExprBlockCustomBlockState.class, ImmutableBlockState.class, "block[ ]custom block state", "blocks/blockdata");
register(ExprBlockCustomBlockState.class, ImmutableBlockState.class, "custom block[ ]state", "blocks/blockdata");
}
@Override

View File

@@ -0,0 +1,56 @@
package net.momirealms.craftengine.bukkit.compatibility.skript.expression;
import ch.njol.skript.Skript;
import ch.njol.skript.lang.Expression;
import ch.njol.skript.lang.ExpressionType;
import ch.njol.skript.lang.SkriptParser;
import ch.njol.skript.lang.util.SimpleExpression;
import ch.njol.util.Kleenean;
import net.momirealms.craftengine.bukkit.api.CraftEngineItems;
import net.momirealms.craftengine.core.item.ItemBuildContext;
import net.momirealms.craftengine.core.util.Key;
import org.bukkit.event.Event;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
public class ExprCustomItem extends SimpleExpression<ItemStack> {
public static void register() {
Skript.registerExpression(ExprCustomItem.class, ItemStack.class, ExpressionType.SIMPLE, "[(the|a)] custom item [with id] %string%");
}
private Expression<String> itemId;
@Override
@SuppressWarnings("unchecked")
public boolean init(Expression<?>[] exprs, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) {
itemId = (Expression<String>) exprs[0];
return true;
}
@Override
@Nullable
protected ItemStack[] get(Event e) {
String itemId = this.itemId.getSingle(e);
if (itemId == null)
return null;
return new ItemStack[] {Objects.requireNonNull(CraftEngineItems.byId(Key.of(itemId))).buildItemStack(ItemBuildContext.EMPTY)};
}
@Override
public boolean isSingle() {
return true;
}
@Override
public Class<ItemStack> getReturnType() {
return ItemStack.class;
}
@Override
public String toString(@Nullable Event e, boolean debug) {
return "the custom item with id " + itemId.toString(e, debug);
}
}

View File

@@ -1,22 +1,16 @@
package net.momirealms.craftengine.bukkit.compatibility.skript.expression;
import ch.njol.skript.expressions.base.SimplePropertyExpression;
import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks;
import net.momirealms.craftengine.bukkit.api.CraftEngineFurniture;
import net.momirealms.craftengine.core.block.CustomBlock;
import net.momirealms.craftengine.core.block.ImmutableBlockState;
import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.Entity;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
import java.util.Optional;
public class ExprEntityFurnitureID extends SimplePropertyExpression<Object, String> {
public static void register() {
register(ExprEntityFurnitureID.class, String.class, "entity[ ]furniture id", "entities");
register(ExprEntityFurnitureID.class, String.class, "furniture id", "entities");
}
@Override

View File

@@ -0,0 +1,65 @@
package net.momirealms.craftengine.bukkit.compatibility.skript.expression;
import ch.njol.skript.aliases.ItemType;
import ch.njol.skript.classes.Changer;
import ch.njol.skript.expressions.base.SimplePropertyExpression;
import ch.njol.util.coll.CollectionUtils;
import net.momirealms.craftengine.bukkit.api.CraftEngineItems;
import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.util.Key;
import org.bukkit.event.Event;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.Nullable;
import java.util.Optional;
public class ExprItemCustomItemID extends SimplePropertyExpression<Object, String> {
public static void register() {
register(ExprItemCustomItemID.class, String.class, "custom item id", "itemstacks/itemtypes");
}
@Override
public @Nullable String convert(Object object) {
if (object instanceof ItemStack itemStack)
return Optional.ofNullable(CraftEngineItems.byItemStack(itemStack)).map(it -> it.id().toString()).orElse(null);
if (object instanceof ItemType itemType) {
ItemStack itemStack = new ItemStack(itemType.getMaterial());
itemStack.setItemMeta(itemType.getItemMeta());
return Optional.ofNullable(CraftEngineItems.byItemStack(itemStack)).map(it -> it.id().toString()).orElse(null);
}
return null;
}
@Override
protected String getPropertyName() {
return "custom item id";
}
@Override
public Class<? extends String> getReturnType() {
return String.class;
}
@Override
public Class<?>[] acceptChange(Changer.ChangeMode mode) {
return CollectionUtils.array(String.class);
}
@Override
public void change(Event e, @Nullable Object[] delta, Changer.ChangeMode mode) {
Key id = Key.of((String) delta[0]);
for (Object item : getExpr().getArray(e)) {
if (item instanceof ItemStack itemStack) {
Item<ItemStack> item1 = BukkitItemManager.instance().wrap(itemStack);
Item<ItemStack> item2 = BukkitItemManager.instance().createWrappedItem(id, null);
item1.merge(item2);
item1.load();
} else if (item instanceof ItemType itemType) {
Item<ItemStack> item2 = BukkitItemManager.instance().createWrappedItem(id, null);
itemType.setItemMeta(item2.load().getItemMeta());
}
}
}
}

View File

@@ -10,6 +10,8 @@ import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.player.PlayerEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -24,6 +26,7 @@ public class CustomBlockInteractEvent extends PlayerEvent implements Cancellable
private final InteractionHand hand;
private final Action action;
private final BlockFace clickedFace;
private final ItemStack item;
public CustomBlockInteractEvent(@NotNull Player player,
@NotNull Location location,
@@ -32,7 +35,8 @@ public class CustomBlockInteractEvent extends PlayerEvent implements Cancellable
@NotNull Block bukkitBlock,
@NotNull BlockFace clickedFace,
@NotNull InteractionHand hand,
@NotNull Action action) {
@NotNull Action action,
@Nullable ItemStack item) {
super(player);
this.customBlock = state.owner().value();
this.bukkitBlock = bukkitBlock;
@@ -42,6 +46,7 @@ public class CustomBlockInteractEvent extends PlayerEvent implements Cancellable
this.hand = hand;
this.action = action;
this.clickedFace = clickedFace;
this.item = item;
}
@NotNull
@@ -89,6 +94,12 @@ public class CustomBlockInteractEvent extends PlayerEvent implements Cancellable
return this.state;
}
@ApiStatus.Experimental
@NotNull
public ItemStack item() {
return this.item;
}
@NotNull
public static HandlerList getHandlerList() {
return HANDLER_LIST;

View File

@@ -70,7 +70,8 @@ public class ItemEventListener implements Listener {
block,
event.getBlockFace(),
event.getHand() == EquipmentSlot.HAND ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND,
action.isRightClick() ? CustomBlockInteractEvent.Action.RIGHT_CLICK : CustomBlockInteractEvent.Action.LEFT_CLICK
action.isRightClick() ? CustomBlockInteractEvent.Action.RIGHT_CLICK : CustomBlockInteractEvent.Action.LEFT_CLICK,
event.getItem()
);
if (EventUtils.fireAndCheckCancel(interactEvent)) {
event.setCancelled(true);

View File

@@ -368,11 +368,28 @@ public class BukkitInjector {
}
}
public synchronized static void injectLevelChunkSection(Object targetSection, CESection ceSection, CEWorld ceWorld, SectionPos pos) {
// public synchronized static void injectLevelChunkSection(Object targetSection, CESection ceSection, CEWorld ceWorld, SectionPos pos) {
// try {
// Object container = FastNMS.INSTANCE.field$LevelChunkSection$states(targetSection);
// if (!(container instanceof InjectedPalettedContainerHolder)) {
// InjectedPalettedContainerHolder injectedObject = FastNMS.INSTANCE.createInjectedPalettedContainerHolder(container);
// injectedObject.ceSection(ceSection);
// injectedObject.ceWorld(ceWorld);
// injectedObject.cePos(pos);
// Reflections.varHandle$PalettedContainer$data.setVolatile(injectedObject, Reflections.varHandle$PalettedContainer$data.get(container));
// Reflections.field$LevelChunkSection$states.set(targetSection, injectedObject);
// }
// } catch (Exception e) {
// CraftEngine.instance().logger().severe("Failed to inject chunk section", e);
// }
// }
public static void injectLevelChunkSection(Object targetSection, CESection ceSection, CEWorld ceWorld, SectionPos pos) {
try {
Object container = FastNMS.INSTANCE.field$LevelChunkSection$states(targetSection);
if (!(container instanceof InjectedPalettedContainerHolder)) {
InjectedPalettedContainerHolder injectedObject = FastNMS.INSTANCE.createInjectedPalettedContainerHolder(container);
if (!clazz$InjectedPalettedContainer.isInstance(container)) {
InjectedPalettedContainerHolder injectedObject = (InjectedPalettedContainerHolder) Reflections.UNSAFE.allocateInstance(clazz$InjectedPalettedContainer);
varHandle$InjectedPalettedContainer$target.set(injectedObject, container);
injectedObject.ceSection(ceSection);
injectedObject.ceWorld(ceWorld);
injectedObject.cePos(pos);

View File

@@ -48,16 +48,11 @@ public class BlockStateHolder {
return propertyMap.entrySet().stream()
.map(entry -> {
Property<?> property = entry.getKey();
return property.name() + "=" + formatValue(property, entry.getValue());
return property.name() + "=" + Property.formatValue(property, entry.getValue());
})
.collect(Collectors.joining(","));
}
@SuppressWarnings("unchecked")
private static <T extends Comparable<T>> String formatValue(Property<T> property, Comparable<?> value) {
return property.valueName((T) value);
}
public Collection<Property<?>> getProperties() {
return Collections.unmodifiableSet(propertyMap.keySet());
}

View File

@@ -0,0 +1,108 @@
package net.momirealms.craftengine.core.block;
import net.momirealms.craftengine.core.block.properties.Property;
import net.momirealms.craftengine.core.registry.BuiltInRegistries;
import net.momirealms.craftengine.core.registry.Holder;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.Pair;
import net.momirealms.craftengine.core.util.StringReader;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
public class BlockStateMatcher {
private final List<Pair<Property<?>, Comparable<?>>> properties;
private final Key id;
public BlockStateMatcher(Key id, List<Pair<Property<?>, Comparable<?>>> properties) {
this.properties = properties;
this.id = id;
}
public boolean matches(ImmutableBlockState state) {
if (!state.owner().value().id.equals(this.id)) {
return false;
}
for (Pair<Property<?>, Comparable<?>> pair : this.properties) {
if (!state.get(pair.left()).equals(pair.right())) {
return false;
}
}
return true;
}
@Override
public String toString() {
if (properties.isEmpty()) {
return id.toString();
}
return id + "[" + getPropertiesAsString() + "]";
}
public String getPropertiesAsString() {
return properties.stream()
.map(entry -> {
Property<?> property = entry.left();
return property.name() + "=" + Property.formatValue(property, entry.right());
})
.collect(Collectors.joining(","));
}
@SuppressWarnings("DuplicatedCode")
@Nullable
public static BlockStateMatcher deserialize(@NotNull String data) {
StringReader reader = StringReader.simple(data);
String blockIdString = reader.readUnquotedString();
if (reader.canRead() && reader.peek() == ':') {
reader.skip();
blockIdString = blockIdString + ":" + reader.readUnquotedString();
}
Optional<Holder.Reference<CustomBlock>> optional = BuiltInRegistries.BLOCK.get(Key.from(blockIdString));
if (optional.isEmpty()) {
return null;
}
Holder<CustomBlock> holder = optional.get();
List<Pair<Property<?>, Comparable<?>>> properties = new ArrayList<>();
if (reader.canRead() && reader.peek() == '[') {
reader.skip();
while (reader.canRead()) {
reader.skipWhitespace();
if (reader.peek() == ']') break;
String propertyName = reader.readUnquotedString();
reader.skipWhitespace();
if (!reader.canRead() || reader.peek() != '=') {
return null;
}
reader.skip();
reader.skipWhitespace();
String propertyValue = reader.readUnquotedString();
Property<?> property = holder.value().getProperty(propertyName);
if (property != null) {
Optional<?> optionalValue = property.optional(propertyValue);
if (optionalValue.isEmpty()) {
return null;
} else {
properties.add(Pair.of(property, (Comparable<?>) optionalValue.get()));
}
} else {
return null;
}
reader.skipWhitespace();
if (reader.canRead() && reader.peek() == ',') {
reader.skip();
}
}
reader.skipWhitespace();
if (reader.canRead() && reader.peek() == ']') {
reader.skip();
} else {
return null;
}
}
return new BlockStateMatcher(holder.value().id(), properties);
}
}

View File

@@ -0,0 +1,98 @@
package net.momirealms.craftengine.core.block;
import net.momirealms.craftengine.core.block.properties.Property;
import net.momirealms.craftengine.core.registry.BuiltInRegistries;
import net.momirealms.craftengine.core.registry.Holder;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.Pair;
import net.momirealms.craftengine.core.util.StringReader;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
public class UnsafeBlockStateMatcher {
private final List<Pair<String, String>> matchers;
private final Key id;
public UnsafeBlockStateMatcher(Key id, List<Pair<String, String>> matchers) {
this.id = id;
this.matchers = matchers;
}
public boolean matches(ImmutableBlockState state) {
if (!state.owner().value().id.equals(this.id)) {
return false;
}
CustomBlock customBlock = state.owner().value();
for (Pair<String, String> matcher : matchers) {
Property<?> property = customBlock.getProperty(matcher.left());
if (property == null) {
return false;
}
Comparable<?> value = state.get(property);
String valueStr = Property.formatValue(property, value);
if (!matcher.right().equals(valueStr)) {
return false;
}
}
return true;
}
@Override
public String toString() {
if (matchers.isEmpty()) {
return id.toString();
}
return id + "[" + matchers.stream()
.map(entry -> entry.left() + "=" + entry.right())
.collect(Collectors.joining(",")) + "]";
}
@SuppressWarnings("DuplicatedCode")
@Nullable
public static UnsafeBlockStateMatcher deserialize(@NotNull String data) {
StringReader reader = StringReader.simple(data);
String blockIdString = reader.readUnquotedString();
if (reader.canRead() && reader.peek() == ':') {
reader.skip();
blockIdString = blockIdString + ":" + reader.readUnquotedString();
}
Optional<Holder.Reference<CustomBlock>> optional = BuiltInRegistries.BLOCK.get(Key.from(blockIdString));
if (optional.isEmpty()) {
return null;
}
Holder<CustomBlock> holder = optional.get();
List<Pair<String, String>> properties = new ArrayList<>();
if (reader.canRead() && reader.peek() == '[') {
reader.skip();
while (reader.canRead()) {
reader.skipWhitespace();
if (reader.peek() == ']') break;
String propertyName = reader.readUnquotedString();
reader.skipWhitespace();
if (!reader.canRead() || reader.peek() != '=') {
return null;
}
reader.skip();
reader.skipWhitespace();
String propertyValue = reader.readUnquotedString();
properties.add(new Pair<>(propertyName, propertyValue));
reader.skipWhitespace();
if (reader.canRead() && reader.peek() == ',') {
reader.skip();
}
}
reader.skipWhitespace();
if (reader.canRead() && reader.peek() == ']') {
reader.skip();
} else {
return null;
}
}
return new UnsafeBlockStateMatcher(holder.value().id(), properties);
}
}

View File

@@ -162,4 +162,9 @@ public abstract class Property<T extends Comparable<T>> {
.map(it -> it.apply(property))
.orElse(((context, state) -> ImmutableBlockState.with(state, property, property.defaultValue())));
}
@SuppressWarnings("unchecked")
public static <T extends Comparable<T>> String formatValue(Property<T> property, Comparable<?> value) {
return property.valueName((T) value);
}
}

View File

@@ -43,7 +43,8 @@ public record Key(String namespace, String value) {
return false;
}
if (!(obj instanceof Key key)) return false;
return this.namespace.equals(key.namespace()) && this.value.equals(key.value());
// 先比value命中率高
return this.value.equals(key.value()) && this.namespace.equals(key.namespace());
}
@Override

View File

@@ -2,7 +2,7 @@ org.gradle.jvmargs=-Xmx1G
# Project settings
# Rule: [major update].[feature update].[bug fix]
project_version=0.0.51-beta.3
project_version=0.0.51
config_version=30
lang_version=7
project_group=net.momirealms