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

优化粒子行为实现

This commit is contained in:
XiaoMoMi
2025-09-14 20:49:53 +08:00
parent 458ad6d477
commit 708aa394a5
21 changed files with 495 additions and 317 deletions

View File

@@ -7,6 +7,6 @@ public final class BlockEntityTypeKeys {
public static final Key UNSAFE_COMPOSITE = Key.of("craftengine:unsafe_composite");
public static final Key SIMPLE_STORAGE = Key.of("craftengine:simple_storage");
public static final Key PARTICLE = Key.of("craftengine:particle");
public static final Key WALL_PARTICLE = Key.of("craftengine:wall_particle");
public static final Key SIMPLE_PARTICLE = Key.of("craftengine:simple_particle");
public static final Key WALL_TORCH_PARTICLE = Key.of("craftengine:wall_torch_particle");
}

View File

@@ -1,115 +1,25 @@
package net.momirealms.craftengine.core.plugin.context.function;
import net.momirealms.craftengine.core.block.BlockStateWrapper;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.context.Condition;
import net.momirealms.craftengine.core.plugin.context.Context;
import net.momirealms.craftengine.core.plugin.context.number.NumberProvider;
import net.momirealms.craftengine.core.plugin.context.number.NumberProviders;
import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters;
import net.momirealms.craftengine.core.util.Color;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.LazyReference;
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import net.momirealms.craftengine.core.world.Position;
import net.momirealms.craftengine.core.world.Vec3d;
import net.momirealms.craftengine.core.world.World;
import net.momirealms.craftengine.core.world.WorldPosition;
import net.momirealms.craftengine.core.world.particle.*;
import net.momirealms.craftengine.core.world.particle.ParticleConfig;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Supplier;
public class ParticleFunction<CTX extends Context> extends AbstractConditionalFunction<CTX> {
public static final Map<Key, java.util.function.Function<Map<String, Object>, ParticleData>> DATA_TYPES = new HashMap<>();
private final ParticleConfig config;
static {
registerParticleData(map -> new BlockStateData(
LazyReference.lazyReference(new Supplier<>() {
final String blockState = ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("block-state"), "warning.config.function.particle.missing_block_state");
@Override
public BlockStateWrapper get() {
return CraftEngine.instance().blockManager().createBlockState(this.blockState);
}
})),
ParticleTypes.BLOCK, ParticleTypes.FALLING_DUST, ParticleTypes.DUST_PILLAR, ParticleTypes.BLOCK_CRUMBLE, ParticleTypes.BLOCK_MARKER);
registerParticleData(map -> new ColorData(
Color.fromStrings(ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("color"), "warning.config.function.particle.missing_color").split(","))),
ParticleTypes.ENTITY_EFFECT, ParticleTypes.TINTED_LEAVES);
registerParticleData(map -> new JavaTypeData(
ResourceConfigUtils.getAsFloat(map.get("charge"), "charge")),
ParticleTypes.SCULK_CHARGE);
registerParticleData(map -> new JavaTypeData(
ResourceConfigUtils.getAsInt(map.get("shriek"), "shriek")),
ParticleTypes.SHRIEK);
registerParticleData(map -> new DustData(
Color.fromStrings(ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("color"), "warning.config.function.particle.missing_color").split(",")),
ResourceConfigUtils.getAsFloat(map.getOrDefault("scale", 1), "scale")),
ParticleTypes.DUST);
registerParticleData(map -> new DustTransitionData(
Color.fromStrings(ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("from"), "warning.config.function.particle.missing_from").split(",")),
Color.fromStrings(ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("to"), "warning.config.function.particle.missing_to").split(",")),
ResourceConfigUtils.getAsFloat(map.getOrDefault("scale", 1), "scale")),
ParticleTypes.DUST_COLOR_TRANSITION);
registerParticleData(map -> new ItemStackData(
LazyReference.lazyReference(new Supplier<>() {
final Key itemId = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("item"), "warning.config.function.particle.missing_item"));
@Override
public Item<?> get() {
return CraftEngine.instance().itemManager().createWrappedItem(this.itemId, null);
}
})
),
ParticleTypes.ITEM);
registerParticleData(map -> new VibrationData(
NumberProviders.fromObject(map.getOrDefault("target-x", 0)),
NumberProviders.fromObject(map.getOrDefault("target-y", 0)),
NumberProviders.fromObject(map.getOrDefault("target-z", 0)),
NumberProviders.fromObject(map.getOrDefault("arrival-time", 10))),
ParticleTypes.VIBRATION);
registerParticleData(map -> new TrailData(
NumberProviders.fromObject(map.getOrDefault("target-x", 0)),
NumberProviders.fromObject(map.getOrDefault("target-y", 0)),
NumberProviders.fromObject(map.getOrDefault("target-z", 0)),
Color.fromStrings(ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("color"), "warning.config.function.particle.missing_color").split(",")),
NumberProviders.fromObject(map.getOrDefault("duration", 10))),
ParticleTypes.TRAIL);
}
public static void registerParticleData(java.util.function.Function<Map<String, Object>, ParticleData> function, Key... types) {
for (Key type : types) {
DATA_TYPES.put(type, function);
}
}
private final Key particleType;
private final NumberProvider x;
private final NumberProvider y;
private final NumberProvider z;
private final NumberProvider count;
private final NumberProvider xOffset;
private final NumberProvider yOffset;
private final NumberProvider zOffset;
private final NumberProvider speed;
private final ParticleData particleData;
public ParticleFunction(Key particleType, NumberProvider x, NumberProvider y, NumberProvider z, NumberProvider count,
NumberProvider xOffset, NumberProvider yOffset, NumberProvider zOffset, NumberProvider speed, ParticleData particleData, List<Condition<CTX>> predicates) {
public ParticleFunction(ParticleConfig config, List<Condition<CTX>> predicates) {
super(predicates);
this.particleType = particleType;
this.count = count;
this.xOffset = xOffset;
this.yOffset = yOffset;
this.zOffset = zOffset;
this.speed = speed;
this.x = x;
this.y = y;
this.z = z;
this.particleData = particleData;
this.config = config;
}
@Override
@@ -117,8 +27,8 @@ public class ParticleFunction<CTX extends Context> extends AbstractConditionalFu
Optional<WorldPosition> optionalWorldPosition = ctx.getOptionalParameter(DirectContextParameters.POSITION);
if (optionalWorldPosition.isPresent()) {
World world = optionalWorldPosition.get().world();
Position position = new Vec3d(this.x.getDouble(ctx), this.y.getDouble(ctx), this.z.getDouble(ctx));
world.spawnParticle(position, this.particleType, this.count.getInt(ctx), this.xOffset.getDouble(ctx), this.yOffset.getDouble(ctx), this.zOffset.getDouble(ctx), this.speed.getDouble(ctx), this.particleData, ctx);
Position position = new Vec3d(config.x.getDouble(ctx), config.y.getDouble(ctx), config.z.getDouble(ctx));
world.spawnParticle(position, config.particleType, config.count.getInt(ctx), config.xOffset.getDouble(ctx), config.yOffset.getDouble(ctx), config.zOffset.getDouble(ctx), config.speed.getDouble(ctx), config.particleData, ctx);
}
}
@@ -135,17 +45,7 @@ public class ParticleFunction<CTX extends Context> extends AbstractConditionalFu
@Override
public Function<CTX> create(Map<String, Object> arguments) {
Key particleType = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("particle"), "warning.config.function.particle.missing_particle"));
NumberProvider x = NumberProviders.fromObject(arguments.getOrDefault("x", "<arg:position.x>"));
NumberProvider y = NumberProviders.fromObject(arguments.getOrDefault("y", "<arg:position.y>"));
NumberProvider z = NumberProviders.fromObject(arguments.getOrDefault("z", "<arg:position.z>"));
NumberProvider count = NumberProviders.fromObject(arguments.getOrDefault("count", 1));
NumberProvider xOffset = NumberProviders.fromObject(arguments.getOrDefault("offset-x", 0));
NumberProvider yOffset = NumberProviders.fromObject(arguments.getOrDefault("offset-y", 0));
NumberProvider zOffset = NumberProviders.fromObject(arguments.getOrDefault("offset-z", 0));
NumberProvider speed = NumberProviders.fromObject(arguments.getOrDefault("speed", 0));
return new ParticleFunction<>(particleType, x, y, z, count, xOffset, yOffset, zOffset, speed,
Optional.ofNullable(ParticleFunction.DATA_TYPES.get(particleType)).map(it -> it.apply(arguments)).orElse(null), getPredicates(arguments));
return new ParticleFunction<>(ParticleConfig.fromMap$function(arguments), getPredicates(arguments));
}
}
}

View File

@@ -3,10 +3,26 @@ package net.momirealms.craftengine.core.util;
import org.jetbrains.annotations.NotNull;
public enum HorizontalDirection {
NORTH,
SOUTH,
WEST,
EAST;
NORTH(0, -1),
SOUTH(0, 1),
WEST(-1, 0),
EAST(1, 0);
private final int adjX;
private final int adjZ;
HorizontalDirection(int adjX, int adjZ) {
this.adjX = adjX;
this.adjZ = adjZ;
}
public int stepX() {
return this.adjX;
}
public int stepZ() {
return this.adjZ;
}
public Direction toDirection() {
return switch (this) {

View File

@@ -58,7 +58,7 @@ public interface World {
void levelEvent(int id, BlockPos pos, int data);
void spawnParticle(Position location, Key particle, int count, double xOffset, double yOffset, double zOffset, double speed, @Nullable ParticleData extraData, @Nullable Context context);
void spawnParticle(Position location, Key particle, int count, double xOffset, double yOffset, double zOffset, double speed, @Nullable ParticleData extraData, @NotNull Context context);
long time();

View File

@@ -0,0 +1,101 @@
package net.momirealms.craftengine.core.world.particle;
import net.momirealms.craftengine.core.plugin.context.number.NumberProvider;
import net.momirealms.craftengine.core.plugin.context.number.NumberProviders;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import java.util.Map;
import java.util.Optional;
public class ParticleConfig {
public final Key particleType;
public final NumberProvider x;
public final NumberProvider y;
public final NumberProvider z;
public final NumberProvider count;
public final NumberProvider xOffset;
public final NumberProvider yOffset;
public final NumberProvider zOffset;
public final NumberProvider speed;
public final ParticleData particleData;
public ParticleConfig(Key particleType, NumberProvider x, NumberProvider y, NumberProvider z, NumberProvider count, NumberProvider xOffset, NumberProvider yOffset, NumberProvider zOffset, NumberProvider speed, ParticleData particleData) {
this.particleType = particleType;
this.x = x;
this.y = y;
this.z = z;
this.count = count;
this.xOffset = xOffset;
this.yOffset = yOffset;
this.zOffset = zOffset;
this.speed = speed;
this.particleData = particleData;
}
public static ParticleConfig fromMap$function(Map<String, Object> arguments) {
Key particleType = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("particle"), "warning.config.function.particle.missing_particle"));
NumberProvider x = NumberProviders.fromObject(arguments.getOrDefault("x", "<arg:position.x>"));
NumberProvider y = NumberProviders.fromObject(arguments.getOrDefault("y", "<arg:position.y>"));
NumberProvider z = NumberProviders.fromObject(arguments.getOrDefault("z", "<arg:position.z>"));
NumberProvider count = NumberProviders.fromObject(arguments.getOrDefault("count", 1));
NumberProvider xOffset = NumberProviders.fromObject(arguments.getOrDefault("offset-x", 0));
NumberProvider yOffset = NumberProviders.fromObject(arguments.getOrDefault("offset-y", 0));
NumberProvider zOffset = NumberProviders.fromObject(arguments.getOrDefault("offset-z", 0));
NumberProvider speed = NumberProviders.fromObject(arguments.getOrDefault("speed", 0));
return new ParticleConfig(particleType, x, y, z, count, xOffset, yOffset, zOffset, speed, Optional.ofNullable(ParticleDataTypes.TYPES.get(particleType)).map(it -> it.apply(arguments)).orElse(null));
}
public static ParticleConfig fromMap$blockEntity(Map<String, Object> arguments) {
Key particleType = Key.of(arguments.getOrDefault("particle", "flame").toString());
NumberProvider x = NumberProviders.fromObject(arguments.getOrDefault("x", 0));
NumberProvider y = NumberProviders.fromObject(arguments.getOrDefault("y", 0));
NumberProvider z = NumberProviders.fromObject(arguments.getOrDefault("z", 0));
NumberProvider count = NumberProviders.fromObject(arguments.getOrDefault("count", 1));
NumberProvider xOffset = NumberProviders.fromObject(arguments.getOrDefault("offset-x", 0));
NumberProvider yOffset = NumberProviders.fromObject(arguments.getOrDefault("offset-y", 0));
NumberProvider zOffset = NumberProviders.fromObject(arguments.getOrDefault("offset-z", 0));
NumberProvider speed = NumberProviders.fromObject(arguments.getOrDefault("speed", 0));
return new ParticleConfig(particleType, x, y, z, count, xOffset, yOffset, zOffset, speed, Optional.ofNullable(ParticleDataTypes.TYPES.get(particleType)).map(it -> it.apply(arguments)).orElse(null));
}
public Key particleType() {
return particleType;
}
public NumberProvider x() {
return x;
}
public NumberProvider y() {
return y;
}
public NumberProvider z() {
return z;
}
public NumberProvider count() {
return count;
}
public NumberProvider xOffset() {
return xOffset;
}
public NumberProvider yOffset() {
return yOffset;
}
public NumberProvider zOffset() {
return zOffset;
}
public NumberProvider speed() {
return speed;
}
public ParticleData particleData() {
return particleData;
}
}

View File

@@ -0,0 +1,77 @@
package net.momirealms.craftengine.core.world.particle;
import net.momirealms.craftengine.core.block.BlockStateWrapper;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.context.number.NumberProviders;
import net.momirealms.craftengine.core.util.Color;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.LazyReference;
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;
public final class ParticleDataTypes {
public static final Map<Key, java.util.function.Function<Map<String, Object>, ParticleData>> TYPES = new HashMap<>();
static {
registerParticleData(map -> new BlockStateData(
LazyReference.lazyReference(new Supplier<>() {
final String blockState = ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("block-state"), "warning.config.function.particle.missing_block_state");
@Override
public BlockStateWrapper get() {
return CraftEngine.instance().blockManager().createBlockState(this.blockState);
}
})),
ParticleTypes.BLOCK, ParticleTypes.FALLING_DUST, ParticleTypes.DUST_PILLAR, ParticleTypes.BLOCK_CRUMBLE, ParticleTypes.BLOCK_MARKER);
registerParticleData(map -> new ColorData(
Color.fromStrings(ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("color"), "warning.config.function.particle.missing_color").split(","))),
ParticleTypes.ENTITY_EFFECT, ParticleTypes.TINTED_LEAVES);
registerParticleData(map -> new JavaTypeData(
ResourceConfigUtils.getAsFloat(map.get("charge"), "charge")),
ParticleTypes.SCULK_CHARGE);
registerParticleData(map -> new JavaTypeData(
ResourceConfigUtils.getAsInt(map.get("shriek"), "shriek")),
ParticleTypes.SHRIEK);
registerParticleData(map -> new DustData(
Color.fromStrings(ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("color"), "warning.config.function.particle.missing_color").split(",")),
ResourceConfigUtils.getAsFloat(map.getOrDefault("scale", 1), "scale")),
ParticleTypes.DUST);
registerParticleData(map -> new DustTransitionData(
Color.fromStrings(ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("from"), "warning.config.function.particle.missing_from").split(",")),
Color.fromStrings(ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("to"), "warning.config.function.particle.missing_to").split(",")),
ResourceConfigUtils.getAsFloat(map.getOrDefault("scale", 1), "scale")),
ParticleTypes.DUST_COLOR_TRANSITION);
registerParticleData(map -> new ItemStackData(
LazyReference.lazyReference(new Supplier<>() {
final Key itemId = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("item"), "warning.config.function.particle.missing_item"));
@Override
public Item<?> get() {
return CraftEngine.instance().itemManager().createWrappedItem(this.itemId, null);
}
})
),
ParticleTypes.ITEM);
registerParticleData(map -> new VibrationData(
NumberProviders.fromObject(map.getOrDefault("target-x", 0)),
NumberProviders.fromObject(map.getOrDefault("target-y", 0)),
NumberProviders.fromObject(map.getOrDefault("target-z", 0)),
NumberProviders.fromObject(map.getOrDefault("arrival-time", 10))),
ParticleTypes.VIBRATION);
registerParticleData(map -> new TrailData(
NumberProviders.fromObject(map.getOrDefault("target-x", 0)),
NumberProviders.fromObject(map.getOrDefault("target-y", 0)),
NumberProviders.fromObject(map.getOrDefault("target-z", 0)),
Color.fromStrings(ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("color"), "warning.config.function.particle.missing_color").split(",")),
NumberProviders.fromObject(map.getOrDefault("duration", 10))),
ParticleTypes.TRAIL);
}
public static void registerParticleData(java.util.function.Function<Map<String, Object>, ParticleData> function, Key... types) {
for (Key type : types) {
TYPES.put(type, function);
}
}
}