From 456dfb00bc0399fdc5d9af769c7b206920a413de Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 5 Dec 2025 20:29:44 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=B6=E5=85=B7=E8=A1=8C=E4=B8=BAAPI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../entity/furniture/BukkitFurniture.java | 20 ++++ .../furniture/BukkitFurnitureManager.java | 37 +++++-- .../furniture/AbstractFurnitureManager.java | 99 ++++++++++++++++++- .../behavior/EmptyFurnitureBehavior.java | 3 + .../furniture/behavior/FurnitureBehavior.java | 2 + .../behavior/FurnitureBehaviorFactory.java | 3 + .../behavior/FurnitureBehaviorType.java | 2 + .../behavior/FurnitureBehaviorTypes.java | 3 +- .../furniture/tick/FurnitureTicker.java | 2 + .../furniture/tick/TickingFurniture.java | 13 +++ .../furniture/tick/TickingFurnitureImpl.java | 30 ++++++ .../item/recipe/AbstractRecipeSerializer.java | 7 +- .../item/recipe/CustomShapelessRecipe.java | 5 +- .../core/item/recipe/PlacementInfo.java | 2 +- ...ntityTickersList.java => TickersList.java} | 15 +-- .../craftengine/core/world/CEWorld.java | 50 +++++----- 16 files changed, 237 insertions(+), 56 deletions(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/entity/furniture/tick/TickingFurniture.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/entity/furniture/tick/TickingFurnitureImpl.java rename core/src/main/java/net/momirealms/craftengine/core/util/{BlockEntityTickersList.java => TickersList.java} (87%) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurniture.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurniture.java index ec5a845ca..ab51b86ff 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurniture.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurniture.java @@ -26,6 +26,7 @@ import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; +@SuppressWarnings("DuplicatedCode") public class BukkitFurniture extends Furniture { private final WeakReference metaEntity; private Location location; @@ -54,6 +55,25 @@ public class BukkitFurniture extends Furniture { FurnitureVariant variant = this.config.getVariant(variantName); if (variant == null) return false; if (this.currentVariant == variant) return false; + // 检查新位置是否可用 + List aabbs = new ArrayList<>(); + WorldPosition position = position(); + for (FurnitureHitBoxConfig hitBoxConfig : variant.hitBoxConfigs()) { + hitBoxConfig.prepareBoundingBox(position, aabbs::add, false); + } + if (!aabbs.isEmpty()) { + if (!FastNMS.INSTANCE.checkEntityCollision(position.world.serverWorld(), aabbs.stream().map(it -> FastNMS.INSTANCE.constructor$AABB(it.minX, it.minY, it.minZ, it.maxX, it.maxY, it.maxZ)).toList(), + o -> { + for (Collider collider : super.colliders) { + if (o == collider.handle()) { + return false; + } + } + return true; + })) { + return false; + } + } // 删除椅子 super.destroySeats(); BukkitFurnitureManager.instance().invalidateFurniture(this); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureManager.java index 88e847160..6a441f42f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureManager.java @@ -12,6 +12,9 @@ import net.momirealms.craftengine.bukkit.util.KeyUtils; import net.momirealms.craftengine.bukkit.util.LocationUtils; import net.momirealms.craftengine.core.entity.furniture.*; import net.momirealms.craftengine.core.entity.furniture.hitbox.FurnitureHitBoxConfig; +import net.momirealms.craftengine.core.entity.furniture.tick.FurnitureTicker; +import net.momirealms.craftengine.core.entity.furniture.tick.TickingFurniture; +import net.momirealms.craftengine.core.entity.furniture.tick.TickingFurnitureImpl; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.sound.SoundData; import net.momirealms.craftengine.core.util.Key; @@ -86,6 +89,8 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { @Override public void delayedInit() { + super.delayedInit(); + // 确定碰撞箱实体类型 COLLISION_ENTITY_TYPE = Config.colliderType(); COLLISION_ENTITY_CLASS = Config.colliderType() == ColliderType.INTERACTION ? Interaction.class : Boat.class; @@ -127,6 +132,7 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { @Override public void disable() { + super.disable(); HandlerList.unregisterAll(this.furnitureEventListener); unload(); } @@ -330,19 +336,38 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { } protected void initFurniture(BukkitFurniture furniture) { - this.byMetaEntityId.put(furniture.entityId(), furniture); - for (int entityId : furniture.virtualEntityIds()) { - this.byVirtualEntityId.put(entityId, furniture); + int entityId = furniture.entityId(); + this.byMetaEntityId.put(entityId, furniture); + for (int id : furniture.virtualEntityIds()) { + this.byVirtualEntityId.put(id, furniture); } for (Collider collisionEntity : furniture.colliders()) { this.byColliderEntityId.put(collisionEntity.entityId(), furniture); } + if (!this.syncTickers.containsKey(entityId)) { + FurnitureTicker ticker = furniture.config.behavior().createSyncFurnitureTicker(furniture); + if (ticker != null) { + TickingFurnitureImpl tickingFurniture = new TickingFurnitureImpl<>(furniture, ticker); + this.syncTickers.put(entityId, tickingFurniture); + this.addSyncFurnitureTicker(tickingFurniture); + } + } + if (!this.asyncTickers.containsKey(entityId)) { + FurnitureTicker ticker = furniture.config.behavior().createAsyncBlockEntityTicker(furniture); + if (ticker != null) { + TickingFurnitureImpl tickingFurniture = new TickingFurnitureImpl<>(furniture, ticker); + this.asyncTickers.put(entityId, tickingFurniture); + this.addAsyncFurnitureTicker(tickingFurniture); + } + } } protected void invalidateFurniture(BukkitFurniture furniture) { - this.byMetaEntityId.remove(furniture.entityId()); - for (int entityId : furniture.virtualEntityIds()) { - this.byVirtualEntityId.remove(entityId); + int entityId = furniture.entityId(); + // 移除entity id映射 + this.byMetaEntityId.remove(entityId); + for (int id : furniture.virtualEntityIds()) { + this.byVirtualEntityId.remove(id); } for (Collider collisionEntity : furniture.colliders()) { this.byColliderEntityId.remove(collisionEntity.entityId()); diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractFurnitureManager.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractFurnitureManager.java index d757898ff..038b240e2 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractFurnitureManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractFurnitureManager.java @@ -1,9 +1,13 @@ package net.momirealms.craftengine.core.entity.furniture; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import net.momirealms.craftengine.core.block.entity.tick.TickingBlockEntity; +import net.momirealms.craftengine.core.entity.furniture.behavior.FurnitureBehaviorTypes; import net.momirealms.craftengine.core.entity.furniture.element.FurnitureElementConfig; import net.momirealms.craftengine.core.entity.furniture.element.FurnitureElementConfigs; import net.momirealms.craftengine.core.entity.furniture.hitbox.FurnitureHitBoxConfig; import net.momirealms.craftengine.core.entity.furniture.hitbox.FurnitureHitBoxTypes; +import net.momirealms.craftengine.core.entity.furniture.tick.TickingFurniture; import net.momirealms.craftengine.core.loot.LootTable; import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; @@ -14,10 +18,8 @@ import net.momirealms.craftengine.core.plugin.config.IdSectionConfigParser; import net.momirealms.craftengine.core.plugin.context.event.EventFunctions; import net.momirealms.craftengine.core.plugin.entityculling.CullingData; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; -import net.momirealms.craftengine.core.util.GsonHelper; -import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.MiscUtils; -import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.core.plugin.scheduler.SchedulerTask; +import net.momirealms.craftengine.core.util.*; import org.incendo.cloud.suggestion.Suggestion; import org.joml.Vector3f; @@ -31,6 +33,18 @@ public abstract class AbstractFurnitureManager implements FurnitureManager { // Cached command suggestions private final List cachedSuggestions = new ArrayList<>(); + protected final Int2ObjectOpenHashMap syncTickers = new Int2ObjectOpenHashMap<>(256, 0.5f); + protected final Int2ObjectOpenHashMap asyncTickers = new Int2ObjectOpenHashMap<>(256, 0.5f); + protected final TickersList syncTickingFurniture = new TickersList<>(); + protected final List pendingSyncTickingFurniture = new ArrayList<>(); + protected final TickersList asyncTickingFurniture = new TickersList<>(); + protected final List pendingAsyncTickingFurniture = new ArrayList<>(); + private boolean isTickingSyncFurniture = false; + private boolean isTickingAsyncFurniture = false; + + protected SchedulerTask syncTickTask; + protected SchedulerTask asyncTickTask; + public AbstractFurnitureManager(CraftEngine plugin) { this.plugin = plugin; this.furnitureParser = new FurnitureParser(); @@ -69,6 +83,82 @@ public abstract class AbstractFurnitureManager implements FurnitureManager { return Collections.unmodifiableMap(this.byId); } + private void syncTick() { + this.isTickingSyncFurniture = true; + if (!this.pendingSyncTickingFurniture.isEmpty()) { + this.syncTickingFurniture.addAll(this.pendingSyncTickingFurniture); + this.pendingSyncTickingFurniture.clear(); + } + if (!this.syncTickingFurniture.isEmpty()) { + Object[] entities = this.syncTickingFurniture.elements(); + for (int i = 0, size = this.syncTickingFurniture.size(); i < size; i++) { + TickingFurniture entity = (TickingFurniture) entities[i]; + if (entity.isValid()) { + entity.tick(); + } else { + this.syncTickingFurniture.markAsRemoved(i); + this.syncTickers.remove(entity.entityId()); + } + } + this.syncTickingFurniture.removeMarkedEntries(); + } + this.isTickingSyncFurniture = false; + } + + private void asyncTick() { + this.isTickingAsyncFurniture = true; + if (!this.pendingAsyncTickingFurniture.isEmpty()) { + this.asyncTickingFurniture.addAll(this.pendingAsyncTickingFurniture); + this.pendingAsyncTickingFurniture.clear(); + } + if (!this.asyncTickingFurniture.isEmpty()) { + Object[] entities = this.asyncTickingFurniture.elements(); + for (int i = 0, size = this.asyncTickingFurniture.size(); i < size; i++) { + TickingFurniture entity = (TickingFurniture) entities[i]; + if (entity.isValid()) { + entity.tick(); + } else { + this.asyncTickingFurniture.markAsRemoved(i); + this.asyncTickers.remove(entity.entityId()); + } + } + this.asyncTickingFurniture.removeMarkedEntries(); + } + this.isTickingAsyncFurniture = false; + } + + public synchronized void addSyncFurnitureTicker(TickingFurniture ticker) { + if (this.isTickingSyncFurniture) { + this.pendingSyncTickingFurniture.add(ticker); + } else { + this.syncTickingFurniture.add(ticker); + } + } + + public synchronized void addAsyncFurnitureTicker(TickingFurniture ticker) { + if (this.isTickingAsyncFurniture) { + this.pendingAsyncTickingFurniture.add(ticker); + } else { + this.asyncTickingFurniture.add(ticker); + } + } + + @Override + public void delayedInit() { + if (this.syncTickTask == null || this.syncTickTask.cancelled()) + this.syncTickTask = CraftEngine.instance().scheduler().sync().runRepeating(this::syncTick, 1, 1); + if (this.asyncTickTask == null || this.asyncTickTask.cancelled()) + this.asyncTickTask = CraftEngine.instance().scheduler().sync().runAsyncRepeating(this::asyncTick, 1, 1); + } + + @Override + public void disable() { + if (this.syncTickTask != null && !this.syncTickTask.cancelled()) + this.syncTickTask.cancel(); + if (this.asyncTickTask != null && !this.asyncTickTask.cancelled()) + this.asyncTickTask.cancel(); + } + @Override public void unload() { this.byId.clear(); @@ -160,6 +250,7 @@ public abstract class AbstractFurnitureManager implements FurnitureManager { .variants(variants) .events(EventFunctions.parseEvents(ResourceConfigUtils.get(section, "events", "event"))) .lootTable(LootTable.fromMap(MiscUtils.castToMap(section.get("loot"), true))) + .behavior(FurnitureBehaviorTypes.fromMap(ResourceConfigUtils.getAsMapOrNull(ResourceConfigUtils.get(section, "behaviors", "behavior"), "behavior"))) .build(); AbstractFurnitureManager.this.byId.put(id, furniture); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/behavior/EmptyFurnitureBehavior.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/behavior/EmptyFurnitureBehavior.java index 439348957..c646e93b4 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/behavior/EmptyFurnitureBehavior.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/behavior/EmptyFurnitureBehavior.java @@ -1,5 +1,8 @@ package net.momirealms.craftengine.core.entity.furniture.behavior; +import org.jetbrains.annotations.ApiStatus; + +@ApiStatus.Experimental public final class EmptyFurnitureBehavior implements FurnitureBehavior { private EmptyFurnitureBehavior() {} diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/behavior/FurnitureBehavior.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/behavior/FurnitureBehavior.java index 655168a5a..aa76567e5 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/behavior/FurnitureBehavior.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/behavior/FurnitureBehavior.java @@ -2,7 +2,9 @@ package net.momirealms.craftengine.core.entity.furniture.behavior; import net.momirealms.craftengine.core.entity.furniture.Furniture; import net.momirealms.craftengine.core.entity.furniture.tick.FurnitureTicker; +import org.jetbrains.annotations.ApiStatus; +@ApiStatus.Experimental public interface FurnitureBehavior { default FurnitureTicker createSyncFurnitureTicker(T furniture) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/behavior/FurnitureBehaviorFactory.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/behavior/FurnitureBehaviorFactory.java index 99e3eaa3c..1585fc9a9 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/behavior/FurnitureBehaviorFactory.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/behavior/FurnitureBehaviorFactory.java @@ -1,7 +1,10 @@ package net.momirealms.craftengine.core.entity.furniture.behavior; +import org.jetbrains.annotations.ApiStatus; + import java.util.Map; +@ApiStatus.Experimental public interface FurnitureBehaviorFactory { T create(Map properties); diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/behavior/FurnitureBehaviorType.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/behavior/FurnitureBehaviorType.java index 08d006d02..0bf1ebc1d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/behavior/FurnitureBehaviorType.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/behavior/FurnitureBehaviorType.java @@ -1,6 +1,8 @@ package net.momirealms.craftengine.core.entity.furniture.behavior; import net.momirealms.craftengine.core.util.Key; +import org.jetbrains.annotations.ApiStatus; +@ApiStatus.Experimental public record FurnitureBehaviorType(Key id, FurnitureBehaviorFactory factory) { } diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/behavior/FurnitureBehaviorTypes.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/behavior/FurnitureBehaviorTypes.java index 18570cbd8..9647f33fb 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/behavior/FurnitureBehaviorTypes.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/behavior/FurnitureBehaviorTypes.java @@ -7,12 +7,13 @@ import net.momirealms.craftengine.core.registry.WritableRegistry; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.util.ResourceKey; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; import java.util.Map; +@ApiStatus.Experimental public class FurnitureBehaviorTypes { - public static final Key EMPTY = Key.from("craftengine:empty"); public static FurnitureBehavior fromMap(@Nullable Map map) { if (map == null || map.isEmpty()) return EmptyFurnitureBehavior.INSTANCE; diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/tick/FurnitureTicker.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/tick/FurnitureTicker.java index 1f034cbd9..8fe21e145 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/tick/FurnitureTicker.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/tick/FurnitureTicker.java @@ -1,7 +1,9 @@ package net.momirealms.craftengine.core.entity.furniture.tick; import net.momirealms.craftengine.core.entity.furniture.Furniture; +import org.jetbrains.annotations.ApiStatus; +@ApiStatus.Experimental public interface FurnitureTicker { void tick(T furniture); diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/tick/TickingFurniture.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/tick/TickingFurniture.java new file mode 100644 index 000000000..b085e360d --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/tick/TickingFurniture.java @@ -0,0 +1,13 @@ +package net.momirealms.craftengine.core.entity.furniture.tick; + +import org.jetbrains.annotations.ApiStatus; + +@ApiStatus.Experimental +public interface TickingFurniture { + + void tick(); + + boolean isValid(); + + int entityId(); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/tick/TickingFurnitureImpl.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/tick/TickingFurnitureImpl.java new file mode 100644 index 000000000..1388666e3 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/tick/TickingFurnitureImpl.java @@ -0,0 +1,30 @@ +package net.momirealms.craftengine.core.entity.furniture.tick; + +import net.momirealms.craftengine.core.entity.furniture.Furniture; +import org.jetbrains.annotations.ApiStatus; + +@ApiStatus.Experimental +public class TickingFurnitureImpl implements TickingFurniture { + private final T furniture; + private final FurnitureTicker ticker; + + public TickingFurnitureImpl(T furniture, FurnitureTicker ticker) { + this.furniture = furniture; + this.ticker = ticker; + } + + @Override + public void tick() { + this.ticker.tick(this.furniture); + } + + @Override + public boolean isValid() { + return this.furniture.isValid(); + } + + @Override + public int entityId() { + return this.furniture.entityId(); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeSerializer.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeSerializer.java index b98b86b27..2e81fb837 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeSerializer.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeSerializer.java @@ -133,12 +133,12 @@ public abstract class AbstractRecipeSerializer> implement return new CustomRecipeResult<>(CloneableConstantItem.of(result), recipeResult.count(), null); } - @Nullable + @NotNull protected Ingredient toIngredient(String item) { return toIngredient(List.of(item)); } - @Nullable + @NotNull protected Ingredient toIngredient(List items) { Set itemIds = new HashSet<>(); Set minecraftItemIds = new HashSet<>(); @@ -149,6 +149,9 @@ public abstract class AbstractRecipeSerializer> implement Key tag = Key.of(item.substring(1)); elements.add(new IngredientElement.Tag(tag)); List uniqueKeys = itemManager.itemIdsByTag(tag); + if (uniqueKeys.isEmpty()) { + throw new LocalizedResourceConfigException("warning.config.recipe.invalid_ingredient", item); + } itemIds.addAll(uniqueKeys); for (UniqueKey uniqueKey : uniqueKeys) { List ingredientSubstitutes = itemManager.getIngredientSubstitutes(uniqueKey.key()); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomShapelessRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomShapelessRecipe.java index 860d66187..380ae3bca 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomShapelessRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomShapelessRecipe.java @@ -11,6 +11,7 @@ import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; @@ -37,12 +38,12 @@ public class CustomShapelessRecipe extends CustomCraftingTableRecipe { } public PlacementInfo placementInfo() { - return placementInfo; + return this.placementInfo; } @Override public List> ingredientsInUse() { - return ingredients; + return this.ingredients; } @SuppressWarnings("unchecked") diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/PlacementInfo.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/PlacementInfo.java index 69b8f6b43..df5c07a93 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/PlacementInfo.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/PlacementInfo.java @@ -19,7 +19,7 @@ public class PlacementInfo { IntList intList = new IntArrayList(i); for (int j = 0; j < i; j++) { Ingredient ingredient = ingredients.get(j); - if (ingredient.isEmpty()) { + if (ingredient == null || ingredient.isEmpty()) { return new PlacementInfo<>(List.of(), IntList.of()); } intList.add(j); diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/BlockEntityTickersList.java b/core/src/main/java/net/momirealms/craftengine/core/util/TickersList.java similarity index 87% rename from core/src/main/java/net/momirealms/craftengine/core/util/BlockEntityTickersList.java rename to core/src/main/java/net/momirealms/craftengine/core/util/TickersList.java index 4ff57411a..ed7ded3c9 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/BlockEntityTickersList.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/TickersList.java @@ -6,10 +6,8 @@ package net.momirealms.craftengine.core.util; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.momirealms.craftengine.core.block.entity.tick.TickingBlockEntity; import java.util.Arrays; -import java.util.Collection; /** * A list for ServerLevel's blockEntityTickers @@ -20,26 +18,17 @@ import java.util.Collection; * This is faster than using removeAll, since we don't need to compare the identity of each block entity, and faster than looping thru each index manually and deleting with remove, * since we don't need to resize the array every single remove. */ -public final class BlockEntityTickersList extends ObjectArrayList { +public final class TickersList extends ObjectArrayList { private final IntOpenHashSet toRemove = new IntOpenHashSet(); private int startSearchFromIndex = -1; /** * Creates a new array list with {@link #DEFAULT_INITIAL_CAPACITY} capacity. */ - public BlockEntityTickersList() { + public TickersList() { super(); } - /** - * Creates a new array list and fills it with a given collection. - * - * @param c a collection that will be used to fill the array list. - */ - public BlockEntityTickersList(final Collection c) { - super(c); - } - /** * Marks an entry as removed * diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/CEWorld.java b/core/src/main/java/net/momirealms/craftengine/core/world/CEWorld.java index 60098466b..df9472248 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/CEWorld.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/CEWorld.java @@ -7,7 +7,7 @@ import net.momirealms.craftengine.core.block.entity.tick.TickingBlockEntity; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.scheduler.SchedulerTask; -import net.momirealms.craftengine.core.util.BlockEntityTickersList; +import net.momirealms.craftengine.core.util.TickersList; import net.momirealms.craftengine.core.world.chunk.CEChunk; import net.momirealms.craftengine.core.world.chunk.storage.StorageAdaptor; import net.momirealms.craftengine.core.world.chunk.storage.WorldDataStorage; @@ -25,9 +25,9 @@ public abstract class CEWorld { protected final WorldHeight worldHeightAccessor; protected List pendingLightSections = new ArrayList<>(); protected final Set lightSections = ConcurrentHashMap.newKeySet(128); - protected final BlockEntityTickersList tickingSyncBlockEntities = new BlockEntityTickersList(); + protected final TickersList syncTickingBlockEntities = new TickersList<>(); protected final List pendingSyncTickingBlockEntities = new ArrayList<>(); - protected final BlockEntityTickersList tickingAsyncBlockEntities = new BlockEntityTickersList(); + protected final TickersList asyncTickingBlockEntities = new TickersList<>(); protected final List pendingAsyncTickingBlockEntities = new ArrayList<>(); protected volatile boolean isTickingSyncBlockEntities = false; protected volatile boolean isTickingAsyncBlockEntities = false; @@ -51,19 +51,15 @@ public abstract class CEWorld { public void setTicking(boolean ticking) { if (ticking) { - if (this.syncTickTask == null || this.syncTickTask.cancelled()) { + if (this.syncTickTask == null || this.syncTickTask.cancelled()) this.syncTickTask = CraftEngine.instance().scheduler().sync().runRepeating(this::syncTick, 1, 1); - } - if (this.asyncTickTask == null || this.asyncTickTask.cancelled()) { + if (this.asyncTickTask == null || this.asyncTickTask.cancelled()) this.asyncTickTask = CraftEngine.instance().scheduler().sync().runAsyncRepeating(this::asyncTick, 1, 1); - } } else { - if (this.syncTickTask != null && !this.syncTickTask.cancelled()) { + if (this.syncTickTask != null && !this.syncTickTask.cancelled()) this.syncTickTask.cancel(); - } - if (this.asyncTickTask != null && !this.asyncTickTask.cancelled()) { + if (this.asyncTickTask != null && !this.asyncTickTask.cancelled()) this.asyncTickTask.cancel(); - } } } @@ -194,39 +190,39 @@ public abstract class CEWorld { public abstract void updateLight(); - public void addSyncBlockEntityTicker(TickingBlockEntity ticker) { + public synchronized void addSyncBlockEntityTicker(TickingBlockEntity ticker) { if (this.isTickingSyncBlockEntities) { this.pendingSyncTickingBlockEntities.add(ticker); } else { - this.tickingSyncBlockEntities.add(ticker); + this.syncTickingBlockEntities.add(ticker); } } - public void addAsyncBlockEntityTicker(TickingBlockEntity ticker) { + public synchronized void addAsyncBlockEntityTicker(TickingBlockEntity ticker) { if (this.isTickingAsyncBlockEntities) { this.pendingAsyncTickingBlockEntities.add(ticker); } else { - this.tickingAsyncBlockEntities.add(ticker); + this.asyncTickingBlockEntities.add(ticker); } } protected void tickSyncBlockEntities() { this.isTickingSyncBlockEntities = true; if (!this.pendingSyncTickingBlockEntities.isEmpty()) { - this.tickingSyncBlockEntities.addAll(this.pendingSyncTickingBlockEntities); + this.syncTickingBlockEntities.addAll(this.pendingSyncTickingBlockEntities); this.pendingSyncTickingBlockEntities.clear(); } - if (!this.tickingSyncBlockEntities.isEmpty()) { - Object[] entities = this.tickingSyncBlockEntities.elements(); - for (int i = 0, size = this.tickingSyncBlockEntities.size(); i < size; i++) { + if (!this.syncTickingBlockEntities.isEmpty()) { + Object[] entities = this.syncTickingBlockEntities.elements(); + for (int i = 0, size = this.syncTickingBlockEntities.size(); i < size; i++) { TickingBlockEntity entity = (TickingBlockEntity) entities[i]; if (entity.isValid()) { entity.tick(); } else { - this.tickingSyncBlockEntities.markAsRemoved(i); + this.syncTickingBlockEntities.markAsRemoved(i); } } - this.tickingSyncBlockEntities.removeMarkedEntries(); + this.syncTickingBlockEntities.removeMarkedEntries(); } this.isTickingSyncBlockEntities = false; } @@ -234,20 +230,20 @@ public abstract class CEWorld { protected void tickAsyncBlockEntities() { this.isTickingAsyncBlockEntities = true; if (!this.pendingAsyncTickingBlockEntities.isEmpty()) { - this.tickingAsyncBlockEntities.addAll(this.pendingAsyncTickingBlockEntities); + this.asyncTickingBlockEntities.addAll(this.pendingAsyncTickingBlockEntities); this.pendingAsyncTickingBlockEntities.clear(); } - if (!this.tickingAsyncBlockEntities.isEmpty()) { - Object[] entities = this.tickingAsyncBlockEntities.elements(); - for (int i = 0, size = this.tickingAsyncBlockEntities.size(); i < size; i++) { + if (!this.asyncTickingBlockEntities.isEmpty()) { + Object[] entities = this.asyncTickingBlockEntities.elements(); + for (int i = 0, size = this.asyncTickingBlockEntities.size(); i < size; i++) { TickingBlockEntity entity = (TickingBlockEntity) entities[i]; if (entity.isValid()) { entity.tick(); } else { - this.tickingAsyncBlockEntities.markAsRemoved(i); + this.asyncTickingBlockEntities.markAsRemoved(i); } } - this.tickingAsyncBlockEntities.removeMarkedEntries(); + this.asyncTickingBlockEntities.removeMarkedEntries(); } this.isTickingAsyncBlockEntities = false; }