mirror of
https://github.com/Xiao-MoMi/craft-engine.git
synced 2025-12-25 01:49:30 +00:00
添加异步方块实体tick
This commit is contained in:
@@ -6,7 +6,6 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflect
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlocks;
|
||||
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.LocationUtils;
|
||||
import net.momirealms.craftengine.bukkit.world.BukkitWorld;
|
||||
import net.momirealms.craftengine.core.block.*;
|
||||
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
|
||||
import net.momirealms.craftengine.core.block.properties.Property;
|
||||
@@ -14,7 +13,9 @@ import net.momirealms.craftengine.core.block.state.properties.DoubleBlockHalf;
|
||||
import net.momirealms.craftengine.core.item.context.BlockPlaceContext;
|
||||
import net.momirealms.craftengine.core.util.Direction;
|
||||
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
|
||||
import net.momirealms.craftengine.core.world.*;
|
||||
import net.momirealms.craftengine.core.world.BlockPos;
|
||||
import net.momirealms.craftengine.core.world.World;
|
||||
import net.momirealms.craftengine.core.world.WorldEvents;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
@@ -8,7 +8,6 @@ import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.DirectionUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.EventUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.LocationUtils;
|
||||
import net.momirealms.craftengine.bukkit.world.BukkitWorld;
|
||||
import net.momirealms.craftengine.bukkit.world.BukkitWorldManager;
|
||||
import net.momirealms.craftengine.core.block.BlockBehavior;
|
||||
import net.momirealms.craftengine.core.block.CustomBlock;
|
||||
@@ -20,7 +19,8 @@ import net.momirealms.craftengine.core.util.Direction;
|
||||
import net.momirealms.craftengine.core.util.PressurePlateSensitivity;
|
||||
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
|
||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
import net.momirealms.craftengine.core.world.*;
|
||||
import net.momirealms.craftengine.core.world.World;
|
||||
import net.momirealms.craftengine.core.world.WorldEvents;
|
||||
import org.bukkit.GameEvent;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ public class SimpleParticleBlockBehavior extends BukkitBlockBehavior implements
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends BlockEntity> BlockEntityTicker<T> createBlockEntityTicker(CEWorld level, ImmutableBlockState state, BlockEntityType<T> blockEntityType) {
|
||||
public <T extends BlockEntity> BlockEntityTicker<T> createAsyncBlockEntityTicker(CEWorld level, ImmutableBlockState state, BlockEntityType<T> blockEntityType) {
|
||||
if (this.particles.length == 0) return null;
|
||||
return EntityBlockBehavior.createTickerHelper(SimpleParticleBlockEntity::tick);
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ public class WallTorchParticleBlockBehavior extends BukkitBlockBehavior implemen
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends BlockEntity> BlockEntityTicker<T> createBlockEntityTicker(CEWorld level, ImmutableBlockState state, BlockEntityType<T> blockEntityType) {
|
||||
public <T extends BlockEntity> BlockEntityTicker<T> createAsyncBlockEntityTicker(CEWorld level, ImmutableBlockState state, BlockEntityType<T> blockEntityType) {
|
||||
if (this.particles.length == 0) return null;
|
||||
return EntityBlockBehavior.createTickerHelper(WallTorchParticleBlockEntity::tick);
|
||||
}
|
||||
|
||||
@@ -610,14 +610,19 @@ public class RecipeEventListener implements Listener {
|
||||
inventory.setResult(null);
|
||||
return;
|
||||
}
|
||||
CraftingInput<ItemStack> input = getCraftingInput(inventory);
|
||||
if (input == null) return;
|
||||
Player player = InventoryUtils.getPlayerFromInventoryEvent(event);
|
||||
BukkitServerPlayer serverPlayer = BukkitAdaptors.adapt(player);
|
||||
ItemBuildContext itemBuildContext = ItemBuildContext.of(serverPlayer);
|
||||
if (!craftingTableRecipe.canUse(itemBuildContext)) {
|
||||
inventory.setResult(null);
|
||||
return;
|
||||
}
|
||||
CraftingInput<ItemStack> input = getCraftingInput(inventory);
|
||||
if (input == null) return;
|
||||
if (craftingTableRecipe.hasVisualResult() && VersionHelper.PREMIUM) {
|
||||
inventory.setResult(craftingTableRecipe.assembleVisual(input, ItemBuildContext.of(serverPlayer)));
|
||||
inventory.setResult(craftingTableRecipe.assembleVisual(input, itemBuildContext));
|
||||
} else {
|
||||
inventory.setResult(craftingTableRecipe.assemble(input, ItemBuildContext.of(serverPlayer)));
|
||||
inventory.setResult(craftingTableRecipe.assemble(input, itemBuildContext));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -638,7 +643,7 @@ public class RecipeEventListener implements Listener {
|
||||
}
|
||||
Player player = InventoryUtils.getPlayerFromInventoryEvent(event);
|
||||
BukkitServerPlayer serverPlayer = BukkitAdaptors.adapt(player);
|
||||
if (!craftingTableRecipe.hasVisualResult()) {
|
||||
if (craftingTableRecipe.hasVisualResult()) {
|
||||
CraftingInput<ItemStack> input = getCraftingInput(inventory);
|
||||
inventory.setResult(craftingTableRecipe.assemble(input, ItemBuildContext.of(serverPlayer)));
|
||||
}
|
||||
@@ -697,10 +702,16 @@ public class RecipeEventListener implements Listener {
|
||||
event.setResult(null);
|
||||
return;
|
||||
}
|
||||
Player player = InventoryUtils.getPlayerFromInventoryEvent(event);
|
||||
ItemBuildContext itemBuildContext = ItemBuildContext.of(BukkitAdaptors.adapt(player));
|
||||
if (!smithingTrimRecipe.canUse(itemBuildContext)) {
|
||||
event.setResult(null);
|
||||
return;
|
||||
}
|
||||
|
||||
SmithingInput<ItemStack> input = getSmithingInput(inventory);
|
||||
if (smithingTrimRecipe.matches(input)) {
|
||||
Player player = InventoryUtils.getPlayerFromInventoryEvent(event);
|
||||
ItemStack result = smithingTrimRecipe.assemble(getSmithingInput(inventory), ItemBuildContext.of(BukkitAdaptors.adapt(player)));
|
||||
ItemStack result = smithingTrimRecipe.assemble(getSmithingInput(inventory), itemBuildContext);
|
||||
event.setResult(result);
|
||||
} else {
|
||||
event.setResult(null);
|
||||
|
||||
@@ -14,7 +14,6 @@ import net.bytebuddy.implementation.bytecode.assign.Assigner;
|
||||
import net.bytebuddy.matcher.ElementMatchers;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
||||
import net.momirealms.craftengine.bukkit.util.LocationUtils;
|
||||
import net.momirealms.craftengine.core.block.BlockStateWrapper;
|
||||
import net.momirealms.craftengine.core.block.DelegatingBlockState;
|
||||
import net.momirealms.craftengine.core.block.EmptyBlock;
|
||||
|
||||
@@ -152,9 +152,16 @@ public final class ImmutableBlockState extends BlockStateHolder {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends BlockEntity> BlockEntityTicker<T> createBlockEntityTicker(CEWorld world, BlockEntityType<? extends BlockEntity> type) {
|
||||
public <T extends BlockEntity> BlockEntityTicker<T> createSyncBlockEntityTicker(CEWorld world, BlockEntityType<? extends BlockEntity> type) {
|
||||
EntityBlockBehavior blockBehavior = this.behavior.getEntityBehavior();
|
||||
if (blockBehavior == null) return null;
|
||||
return (BlockEntityTicker<T>) blockBehavior.createBlockEntityTicker(world, this, type);
|
||||
return (BlockEntityTicker<T>) blockBehavior.createSyncBlockEntityTicker(world, this, type);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends BlockEntity> BlockEntityTicker<T> createAsyncBlockEntityTicker(CEWorld world, BlockEntityType<? extends BlockEntity> type) {
|
||||
EntityBlockBehavior blockBehavior = this.behavior.getEntityBehavior();
|
||||
if (blockBehavior == null) return null;
|
||||
return (BlockEntityTicker<T>) blockBehavior.createAsyncBlockEntityTicker(world, this, type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,11 @@ public interface EntityBlockBehavior {
|
||||
|
||||
BlockEntity createBlockEntity(BlockPos pos, ImmutableBlockState state);
|
||||
|
||||
default <T extends BlockEntity> BlockEntityTicker<T> createBlockEntityTicker(CEWorld level, ImmutableBlockState state, BlockEntityType<T> blockEntityType) {
|
||||
default <T extends BlockEntity> BlockEntityTicker<T> createSyncBlockEntityTicker(CEWorld level, ImmutableBlockState state, BlockEntityType<T> blockEntityType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
default <T extends BlockEntity> BlockEntityTicker<T> createAsyncBlockEntityTicker(CEWorld level, ImmutableBlockState state, BlockEntityType<T> blockEntityType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,10 @@ import net.momirealms.craftengine.core.item.recipe.result.CustomRecipeResult;
|
||||
import net.momirealms.craftengine.core.item.recipe.result.PostProcessor;
|
||||
import net.momirealms.craftengine.core.item.recipe.result.PostProcessors;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.plugin.context.Condition;
|
||||
import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext;
|
||||
import net.momirealms.craftengine.core.plugin.context.condition.AllOfCondition;
|
||||
import net.momirealms.craftengine.core.plugin.context.event.EventConditions;
|
||||
import net.momirealms.craftengine.core.plugin.context.event.EventFunctions;
|
||||
import net.momirealms.craftengine.core.plugin.context.function.Function;
|
||||
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
|
||||
@@ -29,12 +32,21 @@ public abstract class AbstractRecipeSerializer<T, R extends Recipe<T>> implement
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected Function<PlayerOptionalContext>[] functions(Map<String, Object> arguments) {
|
||||
Object functions = arguments.get("functions");
|
||||
Object functions = ResourceConfigUtils.get(arguments, "functions", "function");
|
||||
if (functions == null) return null;
|
||||
List<Function<PlayerOptionalContext>> functionList = ResourceConfigUtils.parseConfigAsList(functions, EventFunctions::fromMap);
|
||||
return functionList.toArray(new Function[0]);
|
||||
}
|
||||
|
||||
protected Condition<PlayerOptionalContext> conditions(Map<String, Object> arguments) {
|
||||
Object functions = ResourceConfigUtils.get(arguments, "conditions", "condition");
|
||||
if (functions == null) return null;
|
||||
List<Condition<PlayerOptionalContext>> conditionList = ResourceConfigUtils.parseConfigAsList(functions, EventConditions::fromMap);
|
||||
if (conditionList.isEmpty()) return null;
|
||||
if (conditionList.size() == 1) return conditionList.getFirst();
|
||||
return new AllOfCondition<>(conditionList);
|
||||
}
|
||||
|
||||
protected boolean showNotification(Map<String, Object> arguments) {
|
||||
return ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("show-notification", true), "show-notification");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package net.momirealms.craftengine.core.item.recipe;
|
||||
|
||||
import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext;
|
||||
|
||||
public interface ConditionalRecipe {
|
||||
|
||||
boolean canUse(final PlayerOptionalContext context);
|
||||
}
|
||||
@@ -4,15 +4,17 @@ import net.momirealms.craftengine.core.item.Item;
|
||||
import net.momirealms.craftengine.core.item.ItemBuildContext;
|
||||
import net.momirealms.craftengine.core.item.recipe.input.RecipeInput;
|
||||
import net.momirealms.craftengine.core.item.recipe.result.CustomRecipeResult;
|
||||
import net.momirealms.craftengine.core.plugin.context.Condition;
|
||||
import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext;
|
||||
import net.momirealms.craftengine.core.plugin.context.function.Function;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public abstract class CustomCraftingTableRecipe<T> extends AbstractGroupedRecipe<T> {
|
||||
public abstract class CustomCraftingTableRecipe<T> extends AbstractGroupedRecipe<T> implements ConditionalRecipe {
|
||||
protected final CraftingRecipeCategory category;
|
||||
private final CustomRecipeResult<T> visualResult;
|
||||
private final Function<PlayerOptionalContext>[] craftingFunctions;
|
||||
private final Condition<PlayerOptionalContext> craftingCondition;
|
||||
|
||||
protected CustomCraftingTableRecipe(Key id,
|
||||
boolean showNotification,
|
||||
@@ -20,11 +22,20 @@ public abstract class CustomCraftingTableRecipe<T> extends AbstractGroupedRecipe
|
||||
@Nullable CustomRecipeResult<T> visualResult,
|
||||
String group,
|
||||
CraftingRecipeCategory category,
|
||||
Function<PlayerOptionalContext>[] craftingFunctions) {
|
||||
Function<PlayerOptionalContext>[] craftingFunctions,
|
||||
Condition<PlayerOptionalContext> craftingCondition) {
|
||||
super(id, showNotification, result, group);
|
||||
this.category = category == null ? CraftingRecipeCategory.MISC : category;
|
||||
this.visualResult = visualResult;
|
||||
this.craftingFunctions = craftingFunctions;
|
||||
this.craftingCondition = craftingCondition;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean canUse(PlayerOptionalContext context) {
|
||||
if (this.craftingCondition == null) return true;
|
||||
return this.craftingCondition.test(context);
|
||||
}
|
||||
|
||||
public CraftingRecipeCategory category() {
|
||||
|
||||
@@ -5,8 +5,8 @@ import com.google.gson.JsonObject;
|
||||
import net.momirealms.craftengine.core.item.recipe.input.CraftingInput;
|
||||
import net.momirealms.craftengine.core.item.recipe.input.RecipeInput;
|
||||
import net.momirealms.craftengine.core.item.recipe.result.CustomRecipeResult;
|
||||
import net.momirealms.craftengine.core.plugin.context.Condition;
|
||||
import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext;
|
||||
import net.momirealms.craftengine.core.plugin.context.event.EventFunctions;
|
||||
import net.momirealms.craftengine.core.plugin.context.function.Function;
|
||||
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
@@ -28,8 +28,9 @@ public class CustomShapedRecipe<T> extends CustomCraftingTableRecipe<T> {
|
||||
String group,
|
||||
CraftingRecipeCategory category,
|
||||
Pattern<T> pattern,
|
||||
Function<PlayerOptionalContext>[] craftingFunctions) {
|
||||
super(id, showNotification, result, visualResult, group, category, craftingFunctions);
|
||||
Function<PlayerOptionalContext>[] craftingFunctions,
|
||||
Condition<PlayerOptionalContext> craftingCondition) {
|
||||
super(id, showNotification, result, visualResult, group, category, craftingFunctions, craftingCondition);
|
||||
this.pattern = pattern;
|
||||
this.parsedPattern = pattern.parse();
|
||||
}
|
||||
@@ -174,7 +175,8 @@ public class CustomShapedRecipe<T> extends CustomCraftingTableRecipe<T> {
|
||||
parseVisualResult(arguments),
|
||||
arguments.containsKey("group") ? arguments.get("group").toString() : null, craftingRecipeCategory(arguments),
|
||||
new Pattern<>(pattern.toArray(new String[0]), ingredients),
|
||||
functions(arguments)
|
||||
functions(arguments),
|
||||
conditions(arguments)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -188,6 +190,7 @@ public class CustomShapedRecipe<T> extends CustomCraftingTableRecipe<T> {
|
||||
VANILLA_RECIPE_HELPER.readGroup(json),
|
||||
VANILLA_RECIPE_HELPER.craftingCategory(json),
|
||||
new Pattern<>(VANILLA_RECIPE_HELPER.craftingShapedPattern(json), ingredients),
|
||||
null,
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.google.gson.JsonObject;
|
||||
import net.momirealms.craftengine.core.item.recipe.input.CraftingInput;
|
||||
import net.momirealms.craftengine.core.item.recipe.input.RecipeInput;
|
||||
import net.momirealms.craftengine.core.item.recipe.result.CustomRecipeResult;
|
||||
import net.momirealms.craftengine.core.plugin.context.Condition;
|
||||
import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext;
|
||||
import net.momirealms.craftengine.core.plugin.context.function.Function;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
@@ -26,8 +27,9 @@ public class CustomShapelessRecipe<T> extends CustomCraftingTableRecipe<T> {
|
||||
String group,
|
||||
CraftingRecipeCategory category,
|
||||
List<Ingredient<T>> ingredients,
|
||||
Function<PlayerOptionalContext>[] craftingFunctions) {
|
||||
super(id, showNotification, result, visualResult, group, category, craftingFunctions);
|
||||
Function<PlayerOptionalContext>[] craftingFunctions,
|
||||
Condition<PlayerOptionalContext> craftingCondition) {
|
||||
super(id, showNotification, result, visualResult, group, category, craftingFunctions, craftingCondition);
|
||||
this.ingredients = ingredients;
|
||||
this.placementInfo = PlacementInfo.create(ingredients);
|
||||
}
|
||||
@@ -92,7 +94,8 @@ public class CustomShapelessRecipe<T> extends CustomCraftingTableRecipe<T> {
|
||||
parseVisualResult(arguments),
|
||||
arguments.containsKey("group") ? arguments.get("group").toString() : null, craftingRecipeCategory(arguments),
|
||||
ingredients,
|
||||
functions(arguments)
|
||||
functions(arguments),
|
||||
conditions(arguments)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -104,6 +107,7 @@ public class CustomShapelessRecipe<T> extends CustomCraftingTableRecipe<T> {
|
||||
null,
|
||||
VANILLA_RECIPE_HELPER.readGroup(json), VANILLA_RECIPE_HELPER.craftingCategory(json),
|
||||
VANILLA_RECIPE_HELPER.shapelessIngredients(json.getAsJsonArray("ingredients")).stream().map(this::toIngredient).toList(),
|
||||
null,
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ import net.momirealms.craftengine.core.item.recipe.input.RecipeInput;
|
||||
import net.momirealms.craftengine.core.item.recipe.input.SmithingInput;
|
||||
import net.momirealms.craftengine.core.item.recipe.result.CustomRecipeResult;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.plugin.context.Condition;
|
||||
import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext;
|
||||
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
|
||||
import net.momirealms.craftengine.core.registry.BuiltInRegistries;
|
||||
import net.momirealms.craftengine.core.registry.Registries;
|
||||
@@ -20,13 +22,14 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
public class CustomSmithingTransformRecipe<T> extends AbstractedFixedResultRecipe<T> {
|
||||
public class CustomSmithingTransformRecipe<T> extends AbstractedFixedResultRecipe<T> implements ConditionalRecipe {
|
||||
public static final Serializer<?> SERIALIZER = new Serializer<>();
|
||||
private final Ingredient<T> base;
|
||||
private final Ingredient<T> template;
|
||||
private final Ingredient<T> addition;
|
||||
private final boolean mergeComponents;
|
||||
private final List<ItemDataProcessor> processors;
|
||||
private final Condition<PlayerOptionalContext> condition;
|
||||
|
||||
public CustomSmithingTransformRecipe(Key id,
|
||||
boolean showNotification,
|
||||
@@ -35,7 +38,8 @@ public class CustomSmithingTransformRecipe<T> extends AbstractedFixedResultRecip
|
||||
@Nullable Ingredient<T> addition,
|
||||
CustomRecipeResult<T> result,
|
||||
List<ItemDataProcessor> processors,
|
||||
boolean mergeComponents
|
||||
boolean mergeComponents,
|
||||
Condition<PlayerOptionalContext> condition
|
||||
) {
|
||||
super(id, showNotification, result);
|
||||
this.base = base;
|
||||
@@ -43,6 +47,13 @@ public class CustomSmithingTransformRecipe<T> extends AbstractedFixedResultRecip
|
||||
this.addition = addition;
|
||||
this.processors = processors;
|
||||
this.mergeComponents = mergeComponents;
|
||||
this.condition = condition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canUse(PlayerOptionalContext context) {
|
||||
if (this.condition != null) return this.condition.test(context);
|
||||
return true;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -140,14 +151,23 @@ public class CustomSmithingTransformRecipe<T> extends AbstractedFixedResultRecip
|
||||
toIngredient(addition),
|
||||
parseResult(arguments),
|
||||
ItemDataProcessors.fromMapList(processors),
|
||||
mergeComponents
|
||||
mergeComponents,
|
||||
conditions(arguments)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CustomSmithingTransformRecipe<A> readJson(Key id, JsonObject json) {
|
||||
return new CustomSmithingTransformRecipe<>(id,
|
||||
true, toIngredient(VANILLA_RECIPE_HELPER.singleIngredient(json.get("template"))), Objects.requireNonNull(toIngredient(VANILLA_RECIPE_HELPER.singleIngredient(json.get("base")))), toIngredient(VANILLA_RECIPE_HELPER.singleIngredient(json.get("addition"))), parseResult(VANILLA_RECIPE_HELPER.smithingResult(json.getAsJsonObject("result"))), null, true
|
||||
return new CustomSmithingTransformRecipe<>(
|
||||
id,
|
||||
true,
|
||||
toIngredient(VANILLA_RECIPE_HELPER.singleIngredient(json.get("template"))),
|
||||
Objects.requireNonNull(toIngredient(VANILLA_RECIPE_HELPER.singleIngredient(json.get("base")))),
|
||||
toIngredient(VANILLA_RECIPE_HELPER.singleIngredient(json.get("addition"))),
|
||||
parseResult(VANILLA_RECIPE_HELPER.smithingResult(json.getAsJsonObject("result"))),
|
||||
null,
|
||||
true,
|
||||
null
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ import net.momirealms.craftengine.core.item.ItemBuildContext;
|
||||
import net.momirealms.craftengine.core.item.recipe.input.RecipeInput;
|
||||
import net.momirealms.craftengine.core.item.recipe.input.SmithingInput;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.plugin.context.Condition;
|
||||
import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import net.momirealms.craftengine.core.util.MiscUtils;
|
||||
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
|
||||
@@ -18,31 +20,41 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
public class CustomSmithingTrimRecipe<T> extends AbstractRecipe<T> {
|
||||
public class CustomSmithingTrimRecipe<T> extends AbstractRecipe<T> implements ConditionalRecipe {
|
||||
public static final Serializer<?> SERIALIZER = new Serializer<>();
|
||||
private final Ingredient<T> base;
|
||||
private final Ingredient<T> template;
|
||||
private final Ingredient<T> addition;
|
||||
@Nullable // 1.21.5
|
||||
private final Key pattern;
|
||||
@Nullable
|
||||
private final Condition<PlayerOptionalContext> condition;
|
||||
|
||||
public CustomSmithingTrimRecipe(@NotNull Key id,
|
||||
boolean showNotification,
|
||||
@NotNull Ingredient<T> template,
|
||||
@NotNull Ingredient<T> base,
|
||||
@NotNull Ingredient<T> addition,
|
||||
@Nullable Key pattern
|
||||
@Nullable Key pattern,
|
||||
@Nullable Condition<PlayerOptionalContext> condition
|
||||
) {
|
||||
super(id, showNotification);
|
||||
this.base = base;
|
||||
this.template = template;
|
||||
this.addition = addition;
|
||||
this.pattern = pattern;
|
||||
this.condition = condition;
|
||||
if (pattern == null && VersionHelper.isOrAbove1_21_5()) {
|
||||
throw new IllegalStateException("SmithingTrimRecipe cannot have a null pattern on 1.21.5 and above.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canUse(PlayerOptionalContext context) {
|
||||
if (this.condition != null) return this.condition.test(context);
|
||||
return true;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public T assemble(RecipeInput input, ItemBuildContext context) {
|
||||
@@ -122,7 +134,8 @@ public class CustomSmithingTrimRecipe<T> extends AbstractRecipe<T> {
|
||||
ResourceConfigUtils.requireNonNullOrThrow(toIngredient(template), "warning.config.recipe.smithing_trim.missing_template_type"),
|
||||
ResourceConfigUtils.requireNonNullOrThrow(toIngredient(base), "warning.config.recipe.smithing_trim.missing_base"),
|
||||
ResourceConfigUtils.requireNonNullOrThrow(toIngredient(addition), "warning.config.recipe.smithing_trim.missing_addition"),
|
||||
pattern
|
||||
pattern,
|
||||
conditions(arguments)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -133,7 +146,8 @@ public class CustomSmithingTrimRecipe<T> extends AbstractRecipe<T> {
|
||||
Objects.requireNonNull(toIngredient(VANILLA_RECIPE_HELPER.singleIngredient(json.get("template")))),
|
||||
Objects.requireNonNull(toIngredient(VANILLA_RECIPE_HELPER.singleIngredient(json.get("base")))),
|
||||
Objects.requireNonNull(toIngredient(VANILLA_RECIPE_HELPER.singleIngredient(json.get("addition")))),
|
||||
VersionHelper.isOrAbove1_21_5() ? Key.of(json.get("pattern").getAsString()) : null
|
||||
VersionHelper.isOrAbove1_21_5() ? Key.of(json.get("pattern").getAsString()) : null,
|
||||
null
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,9 +25,12 @@ public abstract class CEWorld {
|
||||
protected final WorldHeight worldHeightAccessor;
|
||||
protected List<SectionPos> pendingLightSections = new ArrayList<>();
|
||||
protected final Set<SectionPos> lightSections = ConcurrentHashMap.newKeySet(128);
|
||||
protected final BlockEntityTickersList tickingBlockEntities = new BlockEntityTickersList();
|
||||
protected final List<TickingBlockEntity> pendingTickingBlockEntities = new ArrayList<>();
|
||||
protected volatile boolean isTickingBlockEntities = false;
|
||||
protected final BlockEntityTickersList tickingSyncBlockEntities = new BlockEntityTickersList();
|
||||
protected final List<TickingBlockEntity> pendingSyncTickingBlockEntities = new ArrayList<>();
|
||||
protected final BlockEntityTickersList tickingAsyncBlockEntities = new BlockEntityTickersList();
|
||||
protected final List<TickingBlockEntity> pendingAsyncTickingBlockEntities = new ArrayList<>();
|
||||
protected volatile boolean isTickingSyncBlockEntities = false;
|
||||
protected volatile boolean isTickingAsyncBlockEntities = false;
|
||||
protected volatile boolean isUpdatingLights = false;
|
||||
protected SchedulerTask syncTickTask;
|
||||
protected SchedulerTask asyncTickTask;
|
||||
@@ -176,13 +179,14 @@ public abstract class CEWorld {
|
||||
}
|
||||
|
||||
public void syncTick() {
|
||||
this.tickBlockEntities();
|
||||
this.tickSyncBlockEntities();
|
||||
if (!Config.asyncLightUpdate()) {
|
||||
this.updateLight();
|
||||
}
|
||||
}
|
||||
|
||||
public void asyncTick() {
|
||||
this.tickAsyncBlockEntities();
|
||||
if (Config.asyncLightUpdate()) {
|
||||
this.updateLight();
|
||||
}
|
||||
@@ -190,32 +194,61 @@ public abstract class CEWorld {
|
||||
|
||||
public abstract void updateLight();
|
||||
|
||||
public void addBlockEntityTicker(TickingBlockEntity ticker) {
|
||||
if (this.isTickingBlockEntities) {
|
||||
this.pendingTickingBlockEntities.add(ticker);
|
||||
public void addSyncBlockEntityTicker(TickingBlockEntity ticker) {
|
||||
if (this.isTickingSyncBlockEntities) {
|
||||
this.pendingSyncTickingBlockEntities.add(ticker);
|
||||
} else {
|
||||
this.tickingBlockEntities.add(ticker);
|
||||
this.tickingSyncBlockEntities.add(ticker);
|
||||
}
|
||||
}
|
||||
|
||||
protected void tickBlockEntities() {
|
||||
this.isTickingBlockEntities = true;
|
||||
if (!this.pendingTickingBlockEntities.isEmpty()) {
|
||||
this.tickingBlockEntities.addAll(this.pendingTickingBlockEntities);
|
||||
this.pendingTickingBlockEntities.clear();
|
||||
public void addAsyncBlockEntityTicker(TickingBlockEntity ticker) {
|
||||
if (this.isTickingAsyncBlockEntities) {
|
||||
this.pendingAsyncTickingBlockEntities.add(ticker);
|
||||
} else {
|
||||
this.tickingAsyncBlockEntities.add(ticker);
|
||||
}
|
||||
if (!this.tickingBlockEntities.isEmpty()) {
|
||||
Object[] entities = this.tickingBlockEntities.elements();
|
||||
for (int i = 0, size = this.tickingBlockEntities.size(); i < size; i++) {
|
||||
}
|
||||
|
||||
protected void tickSyncBlockEntities() {
|
||||
this.isTickingSyncBlockEntities = true;
|
||||
if (!this.pendingSyncTickingBlockEntities.isEmpty()) {
|
||||
this.tickingSyncBlockEntities.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++) {
|
||||
TickingBlockEntity entity = (TickingBlockEntity) entities[i];
|
||||
if (entity.isValid()) {
|
||||
entity.tick();
|
||||
} else {
|
||||
this.tickingBlockEntities.markAsRemoved(i);
|
||||
this.tickingSyncBlockEntities.markAsRemoved(i);
|
||||
}
|
||||
}
|
||||
this.tickingBlockEntities.removeMarkedEntries();
|
||||
this.tickingSyncBlockEntities.removeMarkedEntries();
|
||||
}
|
||||
this.isTickingBlockEntities = false;
|
||||
this.isTickingSyncBlockEntities = false;
|
||||
}
|
||||
|
||||
protected void tickAsyncBlockEntities() {
|
||||
this.isTickingAsyncBlockEntities = true;
|
||||
if (!this.pendingAsyncTickingBlockEntities.isEmpty()) {
|
||||
this.tickingAsyncBlockEntities.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++) {
|
||||
TickingBlockEntity entity = (TickingBlockEntity) entities[i];
|
||||
if (entity.isValid()) {
|
||||
entity.tick();
|
||||
} else {
|
||||
this.tickingAsyncBlockEntities.markAsRemoved(i);
|
||||
}
|
||||
}
|
||||
this.tickingAsyncBlockEntities.removeMarkedEntries();
|
||||
}
|
||||
this.isTickingAsyncBlockEntities = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package net.momirealms.craftengine.core.world.chunk;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
import net.momirealms.craftengine.core.block.EmptyBlock;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.block.behavior.EntityBlockBehavior;
|
||||
import net.momirealms.craftengine.core.block.entity.BlockEntity;
|
||||
import net.momirealms.craftengine.core.block.entity.render.ConstantBlockEntityRenderer;
|
||||
import net.momirealms.craftengine.core.block.entity.render.DynamicBlockEntityRenderer;
|
||||
@@ -27,7 +28,8 @@ public class CEChunk {
|
||||
public final CESection[] sections;
|
||||
public final WorldHeight worldHeightAccessor;
|
||||
public final Map<BlockPos, BlockEntity> blockEntities; // 从区域线程上访问,安全
|
||||
public final Map<BlockPos, ReplaceableTickingBlockEntity> tickingBlockEntitiesByPos; // 从区域线程上访问,安全
|
||||
public final Map<BlockPos, ReplaceableTickingBlockEntity> tickingSyncBlockEntitiesByPos; // 从区域线程上访问,安全
|
||||
public final Map<BlockPos, ReplaceableTickingBlockEntity> tickingAsyncBlockEntitiesByPos; // 从区域线程上访问,安全
|
||||
public final Map<BlockPos, ConstantBlockEntityRenderer> constantBlockEntityRenderers; // 会从区域线程上读写,netty线程上读取
|
||||
public final Map<BlockPos, DynamicBlockEntityRenderer> dynamicBlockEntityRenderers; // 会从区域线程上读写,netty线程上读取
|
||||
private final ReentrantReadWriteLock renderLock = new ReentrantReadWriteLock();
|
||||
@@ -42,7 +44,8 @@ public class CEChunk {
|
||||
this.blockEntities = new Object2ObjectOpenHashMap<>(10, 0.5f);
|
||||
this.constantBlockEntityRenderers = new Object2ObjectOpenHashMap<>(10, 0.5f);
|
||||
this.dynamicBlockEntityRenderers = new Object2ObjectOpenHashMap<>(10, 0.5f);
|
||||
this.tickingBlockEntitiesByPos = new Object2ObjectOpenHashMap<>(10, 0.5f);
|
||||
this.tickingSyncBlockEntitiesByPos = new Object2ObjectOpenHashMap<>(10, 0.5f);
|
||||
this.tickingAsyncBlockEntitiesByPos = new Object2ObjectOpenHashMap<>(10, 0.5f);
|
||||
this.fillEmptySection();
|
||||
}
|
||||
|
||||
@@ -51,7 +54,8 @@ public class CEChunk {
|
||||
this.chunkPos = chunkPos;
|
||||
this.worldHeightAccessor = world.worldHeight();
|
||||
this.dynamicBlockEntityRenderers = new Object2ObjectOpenHashMap<>(10, 0.5f);
|
||||
this.tickingBlockEntitiesByPos = new Object2ObjectOpenHashMap<>(10, 0.5f);
|
||||
this.tickingSyncBlockEntitiesByPos = new Object2ObjectOpenHashMap<>(10, 0.5f);
|
||||
this.tickingAsyncBlockEntitiesByPos = new Object2ObjectOpenHashMap<>(10, 0.5f);
|
||||
int sectionCount = this.worldHeightAccessor.getSectionsCount();
|
||||
this.sections = new CESection[sectionCount];
|
||||
if (sections != null) {
|
||||
@@ -198,27 +202,51 @@ public class CEChunk {
|
||||
this.blockEntities.values().forEach(e -> e.setValid(false));
|
||||
this.constantBlockEntityRenderers.values().forEach(ConstantBlockEntityRenderer::deactivate);
|
||||
this.dynamicBlockEntityRenderers.clear();
|
||||
this.tickingBlockEntitiesByPos.values().forEach((ticker) -> ticker.setTicker(DummyTickingBlockEntity.INSTANCE));
|
||||
this.tickingBlockEntitiesByPos.clear();
|
||||
this.tickingSyncBlockEntitiesByPos.values().forEach((ticker) -> ticker.setTicker(DummyTickingBlockEntity.INSTANCE));
|
||||
this.tickingSyncBlockEntitiesByPos.clear();
|
||||
this.tickingAsyncBlockEntitiesByPos.values().forEach((ticker) -> ticker.setTicker(DummyTickingBlockEntity.INSTANCE));
|
||||
this.tickingAsyncBlockEntitiesByPos.clear();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends BlockEntity> void replaceOrCreateTickingBlockEntity(T blockEntity) {
|
||||
ImmutableBlockState blockState = blockEntity.blockState();
|
||||
BlockEntityTicker<T> ticker = blockState.createBlockEntityTicker(this.world, blockEntity.type());
|
||||
if (ticker != null) {
|
||||
this.tickingBlockEntitiesByPos.compute(blockEntity.pos(), ((pos, previousTicker) -> {
|
||||
TickingBlockEntity newTicker = new TickingBlockEntityImpl<>(this, blockEntity, ticker);
|
||||
if (previousTicker != null) {
|
||||
previousTicker.setTicker(newTicker);
|
||||
return previousTicker;
|
||||
} else {
|
||||
ReplaceableTickingBlockEntity replaceableTicker = new ReplaceableTickingBlockEntity(newTicker);
|
||||
this.world.addBlockEntityTicker(replaceableTicker);
|
||||
return replaceableTicker;
|
||||
}
|
||||
}));
|
||||
} else {
|
||||
EntityBlockBehavior blockBehavior = blockState.behavior().getEntityBehavior();
|
||||
if (blockBehavior == null) {
|
||||
this.removeBlockEntityTicker(blockEntity.pos());
|
||||
} else {
|
||||
BlockEntityTicker<T> syncTicker = (BlockEntityTicker<T>) blockBehavior.createSyncBlockEntityTicker(this.world, blockState, blockEntity.type());
|
||||
if (syncTicker != null) {
|
||||
this.tickingSyncBlockEntitiesByPos.compute(blockEntity.pos(), ((pos, previousTicker) -> {
|
||||
TickingBlockEntity newTicker = new TickingBlockEntityImpl<>(this, blockEntity, syncTicker);
|
||||
if (previousTicker != null) {
|
||||
previousTicker.setTicker(newTicker);
|
||||
return previousTicker;
|
||||
} else {
|
||||
ReplaceableTickingBlockEntity replaceableTicker = new ReplaceableTickingBlockEntity(newTicker);
|
||||
this.world.addSyncBlockEntityTicker(replaceableTicker);
|
||||
return replaceableTicker;
|
||||
}
|
||||
}));
|
||||
} else {
|
||||
this.removeSyncBlockEntityTicker(blockEntity.pos());
|
||||
}
|
||||
BlockEntityTicker<T> asyncTicker = (BlockEntityTicker<T>) blockBehavior.createAsyncBlockEntityTicker(this.world, blockState, blockEntity.type());
|
||||
if (asyncTicker != null) {
|
||||
this.tickingAsyncBlockEntitiesByPos.compute(blockEntity.pos(), ((pos, previousTicker) -> {
|
||||
TickingBlockEntity newTicker = new TickingBlockEntityImpl<>(this, blockEntity, asyncTicker);
|
||||
if (previousTicker != null) {
|
||||
previousTicker.setTicker(newTicker);
|
||||
return previousTicker;
|
||||
} else {
|
||||
ReplaceableTickingBlockEntity replaceableTicker = new ReplaceableTickingBlockEntity(newTicker);
|
||||
this.world.addAsyncBlockEntityTicker(replaceableTicker);
|
||||
return replaceableTicker;
|
||||
}
|
||||
}));
|
||||
} else {
|
||||
this.removeAsyncBlockEntityTicker(blockEntity.pos());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,13 +278,25 @@ public class CEChunk {
|
||||
}
|
||||
}
|
||||
|
||||
private void removeBlockEntityTicker(BlockPos pos) {
|
||||
ReplaceableTickingBlockEntity blockEntity = this.tickingBlockEntitiesByPos.remove(pos);
|
||||
if (blockEntity != null) {
|
||||
blockEntity.setTicker(DummyTickingBlockEntity.INSTANCE);
|
||||
private void removeSyncBlockEntityTicker(BlockPos pos) {
|
||||
ReplaceableTickingBlockEntity e1 = this.tickingSyncBlockEntitiesByPos.remove(pos);
|
||||
if (e1 != null) {
|
||||
e1.setTicker(DummyTickingBlockEntity.INSTANCE);
|
||||
}
|
||||
}
|
||||
|
||||
private void removeAsyncBlockEntityTicker(BlockPos pos) {
|
||||
ReplaceableTickingBlockEntity e2 = this.tickingAsyncBlockEntitiesByPos.remove(pos);
|
||||
if (e2 != null) {
|
||||
e2.setTicker(DummyTickingBlockEntity.INSTANCE);
|
||||
}
|
||||
}
|
||||
|
||||
private void removeBlockEntityTicker(BlockPos pos) {
|
||||
removeSyncBlockEntityTicker(pos);
|
||||
removeAsyncBlockEntityTicker(pos);
|
||||
}
|
||||
|
||||
public void setBlockEntity(BlockEntity blockEntity) {
|
||||
BlockPos pos = blockEntity.pos();
|
||||
ImmutableBlockState blockState = this.getBlockState(pos);
|
||||
|
||||
@@ -3,7 +3,6 @@ package net.momirealms.craftengine.core.world.chunk.packet;
|
||||
import net.momirealms.craftengine.core.util.FriendlyByteBuf;
|
||||
import net.momirealms.craftengine.core.util.IndexedIterable;
|
||||
import net.momirealms.craftengine.core.world.chunk.PalettedContainer;
|
||||
import net.momirealms.craftengine.core.world.chunk.ReadableContainer;
|
||||
|
||||
public class MCSection {
|
||||
private short nonEmptyBlockCount;
|
||||
|
||||
@@ -2,7 +2,7 @@ org.gradle.jvmargs=-Xmx1G
|
||||
|
||||
# Project settings
|
||||
# Rule: [major update].[feature update].[bug fix]
|
||||
project_version=0.0.63.1
|
||||
project_version=0.0.63.2
|
||||
config_version=45
|
||||
lang_version=29
|
||||
project_group=net.momirealms
|
||||
|
||||
Reference in New Issue
Block a user