From 735d578079c7e1e25050bf9cb7b405ec5790e8f5 Mon Sep 17 00:00:00 2001 From: westernat Date: Fri, 3 Oct 2025 17:32:22 +0800 Subject: [PATCH 01/22] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dmanual=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E4=B8=8D=E7=94=9F=E6=88=90=E7=B2=92=E5=AD=90=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gradle.properties | 2 +- src/main/java/org/mesdag/particlestorm/PSGameClient.java | 1 + .../mesdag/particlestorm/data/component/EmitterRate.java | 1 + .../org/mesdag/particlestorm/data/molang/MolangExp.java | 4 ++++ .../mesdag/particlestorm/particle/ParticleEmitter.java | 9 +++------ 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/gradle.properties b/gradle.properties index dd3bd42..e99284d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -31,7 +31,7 @@ mod_name=ParticleStorm # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=LGPL-3.0 # The mod version. See https://semver.org/ -mod_version=1.0.8.7 +mod_version=1.0.8.8 # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. # See https://maven.apache.org/guides/mini/guide-naming-conventions.html diff --git a/src/main/java/org/mesdag/particlestorm/PSGameClient.java b/src/main/java/org/mesdag/particlestorm/PSGameClient.java index d687f56..4011ea8 100644 --- a/src/main/java/org/mesdag/particlestorm/PSGameClient.java +++ b/src/main/java/org/mesdag/particlestorm/PSGameClient.java @@ -98,6 +98,7 @@ private static void renderLevelStage(RenderLevelStageEvent event) { PoseStack poseStack = event.getPoseStack(); MultiBufferSource.BufferSource bufferSource = minecraft.renderBuffers().bufferSource(); for (ParticleEmitter emitter : LOADER.emitters.values()) { + if (emitter.isRemoved()) continue; double x = Mth.lerp(partialTicks, emitter.posO.x, emitter.pos.x); double y = Mth.lerp(partialTicks, emitter.posO.y, emitter.pos.y); double z = Mth.lerp(partialTicks, emitter.posO.z, emitter.pos.z); diff --git a/src/main/java/org/mesdag/particlestorm/data/component/EmitterRate.java b/src/main/java/org/mesdag/particlestorm/data/component/EmitterRate.java index be99b20..151e38e 100644 --- a/src/main/java/org/mesdag/particlestorm/data/component/EmitterRate.java +++ b/src/main/java/org/mesdag/particlestorm/data/component/EmitterRate.java @@ -162,6 +162,7 @@ public void apply(ParticleEmitter emitter) { } else { emitter.particleGroup.setLimit(limit); } + emitter.spawnRate = limit; } @Override diff --git a/src/main/java/org/mesdag/particlestorm/data/molang/MolangExp.java b/src/main/java/org/mesdag/particlestorm/data/molang/MolangExp.java index 574112b..fdb78f4 100644 --- a/src/main/java/org/mesdag/particlestorm/data/molang/MolangExp.java +++ b/src/main/java/org/mesdag/particlestorm/data/molang/MolangExp.java @@ -7,6 +7,7 @@ import org.mesdag.particlestorm.api.MolangInstance; import org.mesdag.particlestorm.data.molang.compiler.MathValue; import org.mesdag.particlestorm.data.molang.compiler.MolangParser; +import org.mesdag.particlestorm.data.molang.compiler.value.Constant; import java.util.Map; @@ -22,6 +23,9 @@ public class MolangExp { public MolangExp(String expStr) { this.expStr = expStr; + if (expStr.isBlank()) { + this.variable = new Constant(0.0); + } } public MolangExp(String key, double value) { diff --git a/src/main/java/org/mesdag/particlestorm/particle/ParticleEmitter.java b/src/main/java/org/mesdag/particlestorm/particle/ParticleEmitter.java index 9390925..7c9273e 100644 --- a/src/main/java/org/mesdag/particlestorm/particle/ParticleEmitter.java +++ b/src/main/java/org/mesdag/particlestorm/particle/ParticleEmitter.java @@ -83,6 +83,7 @@ public class ParticleEmitter implements MolangInstance { public ParticleEmitter(Level level, Vec3 pos, ResourceLocation particleId, MolangExp expression) { this.level = level; setPos(pos); + this.posO = pos; this.particleId = particleId; this.expression = expression; updateRandoms(level.random); @@ -227,7 +228,7 @@ public void addParent(ParticleEmitter parent) { } public boolean isRemoved() { - return removed || (attached != null && attached.isRemoved()); + return removed || (attached != null && attached.isRemoved()) || (attachedBlock != null && attachedBlock.isRemoved()); } public void setPos(Vec3 pos) { @@ -245,9 +246,8 @@ public void deserialize(CompoundTag compound) { this.emitterRandom2 = compound.getDouble("emitterRandom2"); this.emitterRandom3 = compound.getDouble("emitterRandom3"); this.emitterRandom4 = compound.getDouble("emitterRandom4"); - this.pos = new Vec3(compound.getDouble("posX"), compound.getDouble("posY"), compound.getDouble("posZ")); + this.posO = this.pos = new Vec3(compound.getDouble("posX"), compound.getDouble("posY"), compound.getDouble("posZ")); this.rot.set(compound.getFloat("rotX"), compound.getFloat("rotY"), compound.getFloat("rotZ")); - this.posO = new Vec3(compound.getDouble("movX"), compound.getDouble("movY"), compound.getDouble("movZ")); } public void serialize(CompoundTag compound) { @@ -263,9 +263,6 @@ public void serialize(CompoundTag compound) { compound.putFloat("rotX", rot.x); compound.putFloat("rotY", rot.y); compound.putFloat("rotZ", rot.z); - compound.putDouble("movX", posO.x); - compound.putDouble("movY", posO.y); - compound.putDouble("movZ", posO.z); } public double getX() { From d0b99a70cfb4d9f06ca682c2daa85f930a5a8058 Mon Sep 17 00:00:00 2001 From: westernat Date: Fri, 3 Oct 2025 17:59:12 +0800 Subject: [PATCH 02/22] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=A1=A8=E8=BE=BE?= =?UTF-8?q?=E5=BC=8F=E5=A4=B1=E6=95=88=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gradle.properties | 2 +- .../org/mesdag/particlestorm/data/molang/MolangExp.java | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/gradle.properties b/gradle.properties index e99284d..6cbe218 100644 --- a/gradle.properties +++ b/gradle.properties @@ -31,7 +31,7 @@ mod_name=ParticleStorm # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=LGPL-3.0 # The mod version. See https://semver.org/ -mod_version=1.0.8.8 +mod_version=1.0.8.9 # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. # See https://maven.apache.org/guides/mini/guide-naming-conventions.html diff --git a/src/main/java/org/mesdag/particlestorm/data/molang/MolangExp.java b/src/main/java/org/mesdag/particlestorm/data/molang/MolangExp.java index fdb78f4..be295d2 100644 --- a/src/main/java/org/mesdag/particlestorm/data/molang/MolangExp.java +++ b/src/main/java/org/mesdag/particlestorm/data/molang/MolangExp.java @@ -2,6 +2,7 @@ import com.mojang.serialization.Codec; import io.netty.buffer.ByteBuf; +import net.minecraft.Util; import net.minecraft.network.codec.ByteBufCodecs; import net.minecraft.network.codec.StreamCodec; import org.mesdag.particlestorm.api.MolangInstance; @@ -12,7 +13,7 @@ import java.util.Map; public class MolangExp { - public static final MolangExp EMPTY = new MolangExp(""); + public static final MolangExp EMPTY = Util.make(new MolangExp(""), exp -> exp.variable = new Constant(0.0)); public static final Codec CODEC = Codec.STRING.xmap(MolangExp::new, e -> e.expStr); public static final StreamCodec STREAM_CODEC = StreamCodec.composite( ByteBufCodecs.STRING_UTF8, e -> e.expStr, @@ -23,9 +24,6 @@ public class MolangExp { public MolangExp(String expStr) { this.expStr = expStr; - if (expStr.isBlank()) { - this.variable = new Constant(0.0); - } } public MolangExp(String key, double value) { From 565897bd4038afff50ce0fdc2bcfc802410a8eac Mon Sep 17 00:00:00 2001 From: westernat Date: Fri, 3 Oct 2025 19:31:15 +0800 Subject: [PATCH 03/22] =?UTF-8?q?=E5=88=A4=E6=96=AD=E5=AE=9A=E4=BD=8D?= =?UTF-8?q?=E5=99=A8=E6=98=AF=E5=90=A6=E4=B8=BA=E7=A9=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gradle.properties | 2 +- .../integration/geckolib/AnimationProcessorMixin.java | 7 ++++++- .../mixin/integration/geckolib/GeoBoneMixin.java | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/gradle.properties b/gradle.properties index 6cbe218..c623a18 100644 --- a/gradle.properties +++ b/gradle.properties @@ -31,7 +31,7 @@ mod_name=ParticleStorm # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=LGPL-3.0 # The mod version. See https://semver.org/ -mod_version=1.0.8.9 +mod_version=1.0.8.10 # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. # See https://maven.apache.org/guides/mini/guide-naming-conventions.html diff --git a/src/main/java/org/mesdag/particlestorm/mixin/integration/geckolib/AnimationProcessorMixin.java b/src/main/java/org/mesdag/particlestorm/mixin/integration/geckolib/AnimationProcessorMixin.java index c77dd60..730b9b5 100644 --- a/src/main/java/org/mesdag/particlestorm/mixin/integration/geckolib/AnimationProcessorMixin.java +++ b/src/main/java/org/mesdag/particlestorm/mixin/integration/geckolib/AnimationProcessorMixin.java @@ -15,10 +15,12 @@ import software.bernie.geckolib.animation.AnimationController; import software.bernie.geckolib.animation.AnimationState; import software.bernie.geckolib.cache.object.GeoBone; +import software.bernie.geckolib.loading.json.raw.LocatorValue; import software.bernie.geckolib.model.GeoModel; import java.util.Collection; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; @Pseudo @@ -34,7 +36,10 @@ public abstract class AnimationProcessorMixin { private void tickLocators(T animatable, GeoModel model, AnimatableManager animatableManager, double animTime, AnimationState state, boolean crashWhenCantFindBone, CallbackInfo ci, @Local AnimationController controller) { if (particlestorm$bonesWhichHasLocators == null) { this.particlestorm$bonesWhichHasLocators = getRegisteredBones().stream() - .filter(bone -> IGeoBone.of(bone).particlestorm$getLocators() != null) + .filter(bone -> { + Map locators = IGeoBone.of(bone).particlestorm$getLocators(); + return locators != null && !locators.isEmpty(); + }) .collect(Collectors.toList()); } ((IAnimationController) controller).particlestorm$setBonesWhichHasLocators(particlestorm$bonesWhichHasLocators); diff --git a/src/main/java/org/mesdag/particlestorm/mixin/integration/geckolib/GeoBoneMixin.java b/src/main/java/org/mesdag/particlestorm/mixin/integration/geckolib/GeoBoneMixin.java index 1dfd1aa..434c99f 100644 --- a/src/main/java/org/mesdag/particlestorm/mixin/integration/geckolib/GeoBoneMixin.java +++ b/src/main/java/org/mesdag/particlestorm/mixin/integration/geckolib/GeoBoneMixin.java @@ -52,7 +52,7 @@ public abstract class GeoBoneMixin implements IGeoBone { @Inject(method = "resetStateChanges", at = @At("TAIL")) private void setData(CallbackInfo ci) { - if (particlestorm$locators == null) return; + if (particlestorm$locators == null || particlestorm$locators.isEmpty()) return; MolangQueries.Actor actor = MolangQueriesAccessor.callGetActor(); if (actor != null && actor.animatable() instanceof GeoAnimatable animatable) { IAnimatableInstanceCache cache = IAnimatableInstanceCache.of(animatable.getAnimatableInstanceCache()); From fecb3da65a851f082170e862c3af2eab1514be66 Mon Sep 17 00:00:00 2001 From: westernat Date: Sun, 5 Oct 2025 21:44:38 +0800 Subject: [PATCH 04/22] =?UTF-8?q?=E9=87=8D=E5=86=99=E7=B2=92=E5=AD=90?= =?UTF-8?q?=E8=B4=B4=E5=9B=BE=E7=BB=91=E5=AE=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gradle.properties | 2 +- .../mesdag/particlestorm/PSGameClient.java | 6 +- .../mesdag/particlestorm/ParticleStorm.java | 36 +++------- .../mesdag/particlestorm/api/IComponent.java | 3 + .../data/component/EmitterShape.java | 8 ++- .../particlestorm/data/molang/MolangExp.java | 7 +- .../data/molang/compiler/MolangQueries.java | 3 +- .../particlestorm/mixed/IParticleEngine.java | 11 ++++ .../particlestorm/mixed/ITextureAtlas.java | 9 --- .../mixin/LivingEntityMixin.java | 6 +- .../particlestorm/mixin/MinecraftMixin.java | 37 +---------- .../mixin/ParticleEngineAccessor.java | 33 ---------- .../mixin/ParticleEngineMixin.java | 65 +++++++++++++++++++ .../mixin/TextureAtlasMixin.java | 31 --------- .../AnimatableInstanceCacheMixin.java | 4 +- .../geckolib/MolangQueriesMixin.java | 3 +- .../particle/MolangParticleLoader.java | 10 ++- .../particle/MolangParticleOption.java | 28 +++----- .../particle/ParticleEmitter.java | 8 +-- .../resources/META-INF/accesstransformer.cfg | 2 + src/main/resources/particlestorm.mixins.json | 3 +- 21 files changed, 126 insertions(+), 189 deletions(-) create mode 100644 src/main/java/org/mesdag/particlestorm/mixed/IParticleEngine.java delete mode 100644 src/main/java/org/mesdag/particlestorm/mixed/ITextureAtlas.java delete mode 100644 src/main/java/org/mesdag/particlestorm/mixin/ParticleEngineAccessor.java create mode 100644 src/main/java/org/mesdag/particlestorm/mixin/ParticleEngineMixin.java delete mode 100644 src/main/java/org/mesdag/particlestorm/mixin/TextureAtlasMixin.java diff --git a/gradle.properties b/gradle.properties index c623a18..fada27e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -31,7 +31,7 @@ mod_name=ParticleStorm # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=LGPL-3.0 # The mod version. See https://semver.org/ -mod_version=1.0.8.10 +mod_version=1.0.18 # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. # See https://maven.apache.org/guides/mini/guide-naming-conventions.html diff --git a/src/main/java/org/mesdag/particlestorm/PSGameClient.java b/src/main/java/org/mesdag/particlestorm/PSGameClient.java index 4011ea8..631cab6 100644 --- a/src/main/java/org/mesdag/particlestorm/PSGameClient.java +++ b/src/main/java/org/mesdag/particlestorm/PSGameClient.java @@ -32,7 +32,6 @@ import org.mesdag.particlestorm.api.geckolib.ReplacedCreeperRenderer; import org.mesdag.particlestorm.data.component.*; import org.mesdag.particlestorm.data.event.*; -import org.mesdag.particlestorm.mixin.ParticleEngineAccessor; import org.mesdag.particlestorm.particle.MolangParticleLoader; import org.mesdag.particlestorm.particle.ParticleEmitter; @@ -98,14 +97,13 @@ private static void renderLevelStage(RenderLevelStageEvent event) { PoseStack poseStack = event.getPoseStack(); MultiBufferSource.BufferSource bufferSource = minecraft.renderBuffers().bufferSource(); for (ParticleEmitter emitter : LOADER.emitters.values()) { - if (emitter.isRemoved()) continue; double x = Mth.lerp(partialTicks, emitter.posO.x, emitter.pos.x); double y = Mth.lerp(partialTicks, emitter.posO.y, emitter.pos.y); double z = Mth.lerp(partialTicks, emitter.posO.z, emitter.pos.z); DebugRenderer.renderFloatingText(poseStack, bufferSource, emitter.getPreset().option.getId().toString(), x, y + 0.5, z, 0xFFFFFF); DebugRenderer.renderFloatingText(poseStack, bufferSource, "id: " + emitter.id, x, y + 0.3, z, 0xFFFFFF); - int maxNum = ((ParticleEngineAccessor) minecraft.particleEngine).trackedParticleCounts().getInt(emitter.particleGroup); - DebugRenderer.renderFloatingText(poseStack, bufferSource, "particles: " + maxNum, x, y + 0.1, z, maxNum == emitter.particleGroup.getLimit() ? 0xFF0000 : 0xFFFFFF); + int maxNum = minecraft.particleEngine.trackedParticleCounts.getInt(emitter.particleGroup); + DebugRenderer.renderFloatingText(poseStack, bufferSource, "particles: " + maxNum, x, y + 0.1, z, maxNum >= emitter.particleGroup.getLimit() ? 0xFF0000 : 0xFFFFFF); Camera camera = event.getCamera(); double d0 = camera.getPosition().x; double d1 = camera.getPosition().y; diff --git a/src/main/java/org/mesdag/particlestorm/ParticleStorm.java b/src/main/java/org/mesdag/particlestorm/ParticleStorm.java index e4a27fc..101ecdf 100644 --- a/src/main/java/org/mesdag/particlestorm/ParticleStorm.java +++ b/src/main/java/org/mesdag/particlestorm/ParticleStorm.java @@ -3,10 +3,10 @@ import com.mojang.datafixers.util.Either; import com.mojang.serialization.Codec; import com.mojang.serialization.MapCodec; +import io.netty.buffer.ByteBuf; import net.minecraft.core.particles.ParticleType; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.RegistryFriendlyByteBuf; import net.minecraft.network.codec.StreamCodec; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerPlayer; @@ -47,18 +47,18 @@ public final class ParticleStorm { public static final boolean DEBUG = Boolean.getBoolean("particlestorm.debug"); public static final DeferredRegister> PARTICLE = DeferredRegister.create(BuiltInRegistries.PARTICLE_TYPE, MODID); - public static final DeferredHolder, ParticleType> MOLANG = PARTICLE.register("molang", () -> new ParticleType(false) { + public static final DeferredHolder, ParticleType> MOLANG = PARTICLE.register("molang", () -> new ParticleType<>(false) { @Override public @NotNull MapCodec codec() { - return MolangParticleOption.codec(this); + return MolangParticleOption.CODEC; } @Override - public @NotNull StreamCodec streamCodec() { - return MolangParticleOption.streamCodec(this); + public @NotNull StreamCodec streamCodec() { + return MolangParticleOption.STREAM_CODEC; } }); - public static final Codec> STRING_LIST_CODEC = Codec.either(Codec.STRING, Codec.list(Codec.STRING)).xmap( + public static final Codec> STRING_LIST_CODEC = Codec.either(Codec.STRING, Codec.STRING.listOf()).xmap( either -> either.map(Collections::singletonList, Function.identity()), l -> l.size() == 1 ? Either.left(l.getFirst()) : Either.right(l) ); @@ -75,26 +75,10 @@ public ParticleStorm(IEventBus bus, ModContainer container) { private static void registerPayloadHandlers(RegisterPayloadHandlersEvent event) { PayloadRegistrar registrar = event.registrar("1"); - registrar.playToClient( - EmitterCreationPacketS2C.TYPE, - EmitterCreationPacketS2C.STREAM_CODEC, - EmitterCreationPacketS2C::handle - ); - registrar.playToClient( - EmitterAttachPacketS2C.TYPE, - EmitterAttachPacketS2C.STREAM_CODEC, - EmitterAttachPacketS2C::handle - ); - registrar.playBidirectional( - EmitterRemovalPacket.TYPE, - EmitterRemovalPacket.STREAM_CODEC, - EmitterRemovalPacket::handle - ); - registrar.playBidirectional( - EmitterSynchronizePacket.TYPE, - EmitterSynchronizePacket.STREAM_CODEC, - EmitterSynchronizePacket::handle - ); + registrar.playToClient(EmitterCreationPacketS2C.TYPE, EmitterCreationPacketS2C.STREAM_CODEC, EmitterCreationPacketS2C::handle); + registrar.playToClient(EmitterAttachPacketS2C.TYPE, EmitterAttachPacketS2C.STREAM_CODEC, EmitterAttachPacketS2C::handle); + registrar.playBidirectional(EmitterRemovalPacket.TYPE, EmitterRemovalPacket.STREAM_CODEC, EmitterRemovalPacket::handle); + registrar.playBidirectional(EmitterSynchronizePacket.TYPE, EmitterSynchronizePacket.STREAM_CODEC, EmitterSynchronizePacket::handle); } private static void registerCommands(RegisterCommandsEvent event) { diff --git a/src/main/java/org/mesdag/particlestorm/api/IComponent.java b/src/main/java/org/mesdag/particlestorm/api/IComponent.java index 9e6c028..4cde27e 100644 --- a/src/main/java/org/mesdag/particlestorm/api/IComponent.java +++ b/src/main/java/org/mesdag/particlestorm/api/IComponent.java @@ -23,6 +23,9 @@ static void register(String vanillaPath, Codec codec) { List getAllMolangExp(); + /** + * 小于0表示早期初始化 + */ default int order() { return 1000; } diff --git a/src/main/java/org/mesdag/particlestorm/data/component/EmitterShape.java b/src/main/java/org/mesdag/particlestorm/data/component/EmitterShape.java index 42caed7..c6f7ac7 100644 --- a/src/main/java/org/mesdag/particlestorm/data/component/EmitterShape.java +++ b/src/main/java/org/mesdag/particlestorm/data/component/EmitterShape.java @@ -20,7 +20,6 @@ import org.mesdag.particlestorm.data.molang.FloatMolangExp; import org.mesdag.particlestorm.data.molang.FloatMolangExp3; import org.mesdag.particlestorm.data.molang.MolangExp; -import org.mesdag.particlestorm.mixin.ParticleEngineAccessor; import org.mesdag.particlestorm.particle.MolangParticleInstance; import org.mesdag.particlestorm.particle.ParticleEmitter; import org.mesdag.particlestorm.particle.ParticlePreset; @@ -69,7 +68,10 @@ protected boolean isPoint() { } private void emittingParticle(ParticleEmitter emitter) { - MolangParticleInstance instance = (MolangParticleInstance) ((ParticleEngineAccessor) Minecraft.getInstance().particleEngine).callMakeParticle(emitter.getPreset().option, emitter.getX(), emitter.getY(), emitter.getZ(), 0.0, 0.0, 0.0); + MolangParticleInstance instance = (MolangParticleInstance) Minecraft.getInstance().particleEngine.makeParticle( + emitter.getPreset().option, emitter.getX(), emitter.getY(), emitter.getZ(), 0.0, 0.0, 0.0 + ); + if (instance == null) throw new NullPointerException("Failed to create particle!"); instance.setEmitter(emitter); ParticlePreset preset = instance.preset; @@ -121,7 +123,7 @@ private void emittingParticle(ParticleEmitter emitter) { private static boolean hasSpaceInParticleLimit(ParticleEmitter emitter) { ParticleGroup particleGroup = emitter.particleGroup; - return ((ParticleEngineAccessor) Minecraft.getInstance().particleEngine).trackedParticleCounts().getInt(particleGroup) < particleGroup.getLimit(); + return Minecraft.getInstance().particleEngine.trackedParticleCounts.getInt(particleGroup) < particleGroup.getLimit(); } /** diff --git a/src/main/java/org/mesdag/particlestorm/data/molang/MolangExp.java b/src/main/java/org/mesdag/particlestorm/data/molang/MolangExp.java index be295d2..04fdb3c 100644 --- a/src/main/java/org/mesdag/particlestorm/data/molang/MolangExp.java +++ b/src/main/java/org/mesdag/particlestorm/data/molang/MolangExp.java @@ -14,11 +14,8 @@ public class MolangExp { public static final MolangExp EMPTY = Util.make(new MolangExp(""), exp -> exp.variable = new Constant(0.0)); - public static final Codec CODEC = Codec.STRING.xmap(MolangExp::new, e -> e.expStr); - public static final StreamCodec STREAM_CODEC = StreamCodec.composite( - ByteBufCodecs.STRING_UTF8, e -> e.expStr, - MolangExp::new - ); + public static final Codec CODEC = Codec.STRING.xmap(MolangExp::new, MolangExp::getExpStr); + public static final StreamCodec STREAM_CODEC = ByteBufCodecs.STRING_UTF8.map(MolangExp::new, MolangExp::getExpStr); protected final String expStr; protected MathValue variable; diff --git a/src/main/java/org/mesdag/particlestorm/data/molang/compiler/MolangQueries.java b/src/main/java/org/mesdag/particlestorm/data/molang/compiler/MolangQueries.java index d39c8cc..d6d181d 100644 --- a/src/main/java/org/mesdag/particlestorm/data/molang/compiler/MolangQueries.java +++ b/src/main/java/org/mesdag/particlestorm/data/molang/compiler/MolangQueries.java @@ -7,7 +7,6 @@ import org.mesdag.particlestorm.api.MolangInstance; import org.mesdag.particlestorm.api.RegisterMolangQueriesEvent; import org.mesdag.particlestorm.data.molang.compiler.value.Variable; -import org.mesdag.particlestorm.mixin.ParticleEngineAccessor; import java.util.HashMap; import java.util.Map; @@ -82,7 +81,7 @@ private static void setDefaultQueryValues() { registerQueryVariable("query.total_emitter_count", p -> PSGameClient.LOADER.totalEmitterCount()); registerQueryVariable("query.total_particle_count", p -> { int sum = 0; - for (Integer value : ((ParticleEngineAccessor) Minecraft.getInstance().particleEngine).trackedParticleCounts().values()) { + for (Integer value : Minecraft.getInstance().particleEngine.trackedParticleCounts.values()) { sum += value; } return sum; diff --git a/src/main/java/org/mesdag/particlestorm/mixed/IParticleEngine.java b/src/main/java/org/mesdag/particlestorm/mixed/IParticleEngine.java new file mode 100644 index 0000000..62bcf93 --- /dev/null +++ b/src/main/java/org/mesdag/particlestorm/mixed/IParticleEngine.java @@ -0,0 +1,11 @@ +package org.mesdag.particlestorm.mixed; + +import net.minecraft.client.particle.ParticleEngine; + +public interface IParticleEngine { + void particlestorm$bindSprites(); + + static IParticleEngine of(ParticleEngine engine) { + return (IParticleEngine) engine; + } +} diff --git a/src/main/java/org/mesdag/particlestorm/mixed/ITextureAtlas.java b/src/main/java/org/mesdag/particlestorm/mixed/ITextureAtlas.java deleted file mode 100644 index cc4c4c0..0000000 --- a/src/main/java/org/mesdag/particlestorm/mixed/ITextureAtlas.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.mesdag.particlestorm.mixed; - -import net.minecraft.client.renderer.texture.SpriteLoader; - -import java.util.function.Consumer; - -public interface ITextureAtlas { - void particlestorm$consume(Consumer consumer); -} diff --git a/src/main/java/org/mesdag/particlestorm/mixin/LivingEntityMixin.java b/src/main/java/org/mesdag/particlestorm/mixin/LivingEntityMixin.java index ac0c32d..fa4f6c4 100644 --- a/src/main/java/org/mesdag/particlestorm/mixin/LivingEntityMixin.java +++ b/src/main/java/org/mesdag/particlestorm/mixin/LivingEntityMixin.java @@ -6,7 +6,6 @@ import net.minecraft.world.level.Level; import org.mesdag.particlestorm.PSGameClient; import org.mesdag.particlestorm.particle.MolangParticleOption; -import org.mesdag.particlestorm.particle.ParticleEmitter; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -15,10 +14,7 @@ public abstract class LivingEntityMixin { @WrapWithCondition(method = "tickEffects", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;addParticle(Lnet/minecraft/core/particles/ParticleOptions;DDDDDD)V")) private boolean modify(Level instance, ParticleOptions particleData, double x, double y, double z, double xSpeed, double ySpeed, double zSpeed) { if (particleData instanceof MolangParticleOption molang) { - LivingEntity self = (LivingEntity) (Object) this; - ParticleEmitter emitter = new ParticleEmitter(instance, self.position(), molang.getId()); - emitter.attachEntity(self); - PSGameClient.LOADER.addTrackedEmitter(self, emitter); + PSGameClient.LOADER.addTrackedEmitter((LivingEntity) (Object) this, molang.getId()); return false; } return true; diff --git a/src/main/java/org/mesdag/particlestorm/mixin/MinecraftMixin.java b/src/main/java/org/mesdag/particlestorm/mixin/MinecraftMixin.java index e87b89e..9758646 100644 --- a/src/main/java/org/mesdag/particlestorm/mixin/MinecraftMixin.java +++ b/src/main/java/org/mesdag/particlestorm/mixin/MinecraftMixin.java @@ -1,17 +1,8 @@ package org.mesdag.particlestorm.mixin; import net.minecraft.client.Minecraft; -import net.minecraft.client.main.GameConfig; import net.minecraft.client.particle.ParticleEngine; -import net.minecraft.client.renderer.texture.TextureAtlas; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.resources.ResourceLocation; -import org.mesdag.particlestorm.PSGameClient; -import org.mesdag.particlestorm.ParticleStorm; -import org.mesdag.particlestorm.data.DefinedParticleEffect; -import org.mesdag.particlestorm.mixed.ITextureAtlas; -import org.mesdag.particlestorm.particle.ExtendMutableSpriteSet; -import org.mesdag.particlestorm.particle.MolangParticleInstance; +import org.mesdag.particlestorm.mixed.IParticleEngine; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -20,38 +11,14 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import java.util.Map; - @Mixin(Minecraft.class) public abstract class MinecraftMixin { @Shadow @Final public ParticleEngine particleEngine; - @Inject(method = "", at = @At(value = "INVOKE", target = "Lnet/neoforged/neoforge/client/ClientHooks;onRegisterParticleProviders(Lnet/minecraft/client/particle/ParticleEngine;)V", remap = false)) - private void registerCustom(GameConfig gameConfig, CallbackInfo ci) { - ExtendMutableSpriteSet extendMutableSpriteSet = new ExtendMutableSpriteSet(); - ((ParticleEngineAccessor) particleEngine).spriteSets().put(ParticleStorm.MOLANG.getId(), extendMutableSpriteSet); - ((ParticleEngineAccessor) particleEngine).providers().put(ParticleStorm.MOLANG.getId(), new MolangParticleInstance.Provider(extendMutableSpriteSet)); - } - @Inject(method = "onResourceLoadFinished", at = @At("TAIL")) private void onLoaded(@Coerce Object gameLoadCookie, CallbackInfo ci) { - if (((ParticleEngineAccessor) particleEngine).spriteSets().get(ParticleStorm.MOLANG.getId()) instanceof ExtendMutableSpriteSet spriteSet) { - try (TextureAtlas textureAtlas = ((ParticleEngineAccessor) particleEngine).textureAtlas()) { - ((ITextureAtlas) textureAtlas).particlestorm$consume(preparations -> { - spriteSet.clear(); - int i = 0; - for (Map.Entry entry : PSGameClient.LOADER.id2Effect().entrySet()) { - TextureAtlasSprite missing = preparations.missing(); - spriteSet.bindMissing(missing); - ResourceLocation texture = entry.getValue().description.parameters().bindTexture(i); - TextureAtlasSprite sprite = preparations.regions().get(texture); - spriteSet.addSprite(sprite == null ? missing : sprite); - i++; - } - }); - } - } + IParticleEngine.of(particleEngine).particlestorm$bindSprites(); } } diff --git a/src/main/java/org/mesdag/particlestorm/mixin/ParticleEngineAccessor.java b/src/main/java/org/mesdag/particlestorm/mixin/ParticleEngineAccessor.java deleted file mode 100644 index 6fc5607..0000000 --- a/src/main/java/org/mesdag/particlestorm/mixin/ParticleEngineAccessor.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.mesdag.particlestorm.mixin; - -import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; -import net.minecraft.client.particle.Particle; -import net.minecraft.client.particle.ParticleEngine; -import net.minecraft.client.particle.ParticleProvider; -import net.minecraft.client.renderer.texture.TextureAtlas; -import net.minecraft.core.particles.ParticleGroup; -import net.minecraft.core.particles.ParticleOptions; -import net.minecraft.resources.ResourceLocation; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; -import org.spongepowered.asm.mixin.gen.Invoker; - -import java.util.Map; - -@Mixin(ParticleEngine.class) -public interface ParticleEngineAccessor { - @Accessor("spriteSets") - Map spriteSets(); - - @Accessor("providers") - Map> providers(); - - @Accessor("textureAtlas") - TextureAtlas textureAtlas(); - - @Accessor("trackedParticleCounts") - Object2IntOpenHashMap trackedParticleCounts(); - - @Invoker - Particle callMakeParticle(T particleData, double x, double y, double z, double xSpeed, double ySpeed, double zSpeed); -} diff --git a/src/main/java/org/mesdag/particlestorm/mixin/ParticleEngineMixin.java b/src/main/java/org/mesdag/particlestorm/mixin/ParticleEngineMixin.java new file mode 100644 index 0000000..0c23b2a --- /dev/null +++ b/src/main/java/org/mesdag/particlestorm/mixin/ParticleEngineMixin.java @@ -0,0 +1,65 @@ +package org.mesdag.particlestorm.mixin; + +import net.minecraft.client.particle.ParticleEngine; +import net.minecraft.client.particle.ParticleProvider; +import net.minecraft.client.renderer.texture.SpriteLoader; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.resources.ResourceLocation; +import org.mesdag.particlestorm.PSGameClient; +import org.mesdag.particlestorm.ParticleStorm; +import org.mesdag.particlestorm.data.DefinedParticleEffect; +import org.mesdag.particlestorm.mixed.IParticleEngine; +import org.mesdag.particlestorm.particle.ExtendMutableSpriteSet; +import org.mesdag.particlestorm.particle.MolangParticleInstance; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.ModifyArg; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.Map; + +@Mixin(ParticleEngine.class) +public abstract class ParticleEngineMixin implements IParticleEngine { + @Shadow + @Final + private Map spriteSets; + @Shadow + @Final + private Map> providers; + + @Unique + private volatile SpriteLoader.Preparations particlestorm$preparations; + + @Override + public void particlestorm$bindSprites() { + if (particlestorm$preparations != null && spriteSets.get(ParticleStorm.MOLANG.getId()) instanceof ExtendMutableSpriteSet spriteSet) { + spriteSet.clear(); + int i = 0; + for (Map.Entry entry : PSGameClient.LOADER.id2Effect().entrySet()) { + TextureAtlasSprite missing = particlestorm$preparations.missing(); + spriteSet.bindMissing(missing); + ResourceLocation texture = entry.getValue().description.parameters().bindTexture(i); + TextureAtlasSprite sprite = particlestorm$preparations.regions().get(texture); + spriteSet.addSprite(sprite == null ? missing : sprite); + i++; + } + } + this.particlestorm$preparations = null; + } + + @Inject(method = "registerProviders", at = @At("TAIL")) + private void registerCustom(CallbackInfo ci) { + ExtendMutableSpriteSet extendMutableSpriteSet = new ExtendMutableSpriteSet(); + spriteSets.put(ParticleStorm.MOLANG.getId(), extendMutableSpriteSet); + providers.put(ParticleStorm.MOLANG.getId(), new MolangParticleInstance.Provider(extendMutableSpriteSet)); + } + + @ModifyArg(method = "lambda$reload$9", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/texture/TextureAtlas;upload(Lnet/minecraft/client/renderer/texture/SpriteLoader$Preparations;)V")) + private SpriteLoader.Preparations cachePreparations(SpriteLoader.Preparations preparations) { + return this.particlestorm$preparations = preparations; + } +} diff --git a/src/main/java/org/mesdag/particlestorm/mixin/TextureAtlasMixin.java b/src/main/java/org/mesdag/particlestorm/mixin/TextureAtlasMixin.java deleted file mode 100644 index f9e5a0d..0000000 --- a/src/main/java/org/mesdag/particlestorm/mixin/TextureAtlasMixin.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.mesdag.particlestorm.mixin; - -import net.minecraft.client.renderer.texture.SpriteLoader; -import net.minecraft.client.renderer.texture.TextureAtlas; -import org.mesdag.particlestorm.mixed.ITextureAtlas; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import java.util.function.Consumer; - -@Mixin(TextureAtlas.class) -public abstract class TextureAtlasMixin implements ITextureAtlas { - @Unique - private SpriteLoader.Preparations particlestorm$preparations; - - @Override - public void particlestorm$consume(Consumer consumer) { - if (particlestorm$preparations != null) { - consumer.accept(particlestorm$preparations); - this.particlestorm$preparations = null; - } - } - - @Inject(method = "upload", at = @At("HEAD")) - private void storePreparations(SpriteLoader.Preparations preparations, CallbackInfo ci) { - this.particlestorm$preparations = preparations; - } -} diff --git a/src/main/java/org/mesdag/particlestorm/mixin/integration/geckolib/AnimatableInstanceCacheMixin.java b/src/main/java/org/mesdag/particlestorm/mixin/integration/geckolib/AnimatableInstanceCacheMixin.java index ec7782b..e154110 100644 --- a/src/main/java/org/mesdag/particlestorm/mixin/integration/geckolib/AnimatableInstanceCacheMixin.java +++ b/src/main/java/org/mesdag/particlestorm/mixin/integration/geckolib/AnimatableInstanceCacheMixin.java @@ -18,8 +18,8 @@ public class AnimatableInstanceCacheMixin implements IAnimatableInstanceCache { private Vector3f particlestorm$position; @Unique private Vector3f particlestorm$rotation; - @Unique - private Vector3f particlestorm$scale; +// @Unique +// private Vector3f particlestorm$scale; @Override public Object2IntMap particlestorm$getCachedId() { diff --git a/src/main/java/org/mesdag/particlestorm/mixin/integration/geckolib/MolangQueriesMixin.java b/src/main/java/org/mesdag/particlestorm/mixin/integration/geckolib/MolangQueriesMixin.java index 6363593..1411552 100644 --- a/src/main/java/org/mesdag/particlestorm/mixin/integration/geckolib/MolangQueriesMixin.java +++ b/src/main/java/org/mesdag/particlestorm/mixin/integration/geckolib/MolangQueriesMixin.java @@ -2,7 +2,6 @@ import net.minecraft.client.Minecraft; import org.mesdag.particlestorm.PSGameClient; -import org.mesdag.particlestorm.mixin.ParticleEngineAccessor; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Pseudo; import org.spongepowered.asm.mixin.injection.At; @@ -19,7 +18,7 @@ private static void particleQueries(CallbackInfo ci) { setActorVariable("query.total_emitter_count", actor -> PSGameClient.LOADER.totalEmitterCount()); setActorVariable("query.total_particle_count", actor -> { int sum = 0; - for (Integer value : ((ParticleEngineAccessor) Minecraft.getInstance().particleEngine).trackedParticleCounts().values()) { + for (Integer value : Minecraft.getInstance().particleEngine.trackedParticleCounts.values()) { sum += value; } return sum; diff --git a/src/main/java/org/mesdag/particlestorm/particle/MolangParticleLoader.java b/src/main/java/org/mesdag/particlestorm/particle/MolangParticleLoader.java index faa93f6..1f551b9 100644 --- a/src/main/java/org/mesdag/particlestorm/particle/MolangParticleLoader.java +++ b/src/main/java/org/mesdag/particlestorm/particle/MolangParticleLoader.java @@ -40,6 +40,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; +@SuppressWarnings("all") public class MolangParticleLoader implements PreparableReloadListener { private static final FileToIdConverter PARTICLE_LISTER = FileToIdConverter.json("particle_definitions"); private Map id2Effect = new Hashtable<>(); @@ -120,9 +121,14 @@ public void addEmitter(ParticleEmitter emitter, boolean sync) { if (sync) EmitterSynchronizePacket.syncToServer(emitter); } - public void addTrackedEmitter(Entity entity, ParticleEmitter emitter) { + public boolean addTrackedEmitter(Entity entity, ResourceLocation particleId) { + EvictingQueue queue = tracker.computeIfAbsent(entity, e -> EvictingQueue.create(16)); + if (!queue.isEmpty() && queue.stream().anyMatch(emitter -> particleId.equals(emitter.particleId))) return false; + ParticleEmitter emitter = new ParticleEmitter(entity.level(), entity.position(), particleId); addEmitter(emitter, false); - tracker.computeIfAbsent(entity, e -> EvictingQueue.create(16)).add(emitter); + emitter.attachEntity(entity); + queue.add(emitter); + return true; } public void removeEmitter(ParticleEmitter emitter, boolean sync) { diff --git a/src/main/java/org/mesdag/particlestorm/particle/MolangParticleOption.java b/src/main/java/org/mesdag/particlestorm/particle/MolangParticleOption.java index fae0a0f..eb8eb5a 100644 --- a/src/main/java/org/mesdag/particlestorm/particle/MolangParticleOption.java +++ b/src/main/java/org/mesdag/particlestorm/particle/MolangParticleOption.java @@ -1,7 +1,5 @@ package org.mesdag.particlestorm.particle; -import com.google.common.base.Supplier; -import com.google.common.base.Suppliers; import com.mojang.serialization.MapCodec; import io.netty.buffer.ByteBuf; import net.minecraft.core.particles.ParticleOptions; @@ -11,18 +9,19 @@ import org.jetbrains.annotations.NotNull; import org.mesdag.particlestorm.ParticleStorm; - public class MolangParticleOption implements ParticleOptions { - private final Supplier> type; + public static final MapCodec CODEC = ResourceLocation.CODEC.fieldOf("id").xmap(MolangParticleOption::new, MolangParticleOption::getId); + public static final StreamCodec STREAM_CODEC = ResourceLocation.STREAM_CODEC.map(MolangParticleOption::new, MolangParticleOption::getId); + private final ParticleType type; private final ResourceLocation id; - private MolangParticleOption(Supplier> type, ResourceLocation id) { - this.type = Suppliers.memoize(type); + private MolangParticleOption(ParticleType type, ResourceLocation id) { + this.type = type; this.id = id; } public MolangParticleOption(ResourceLocation id) { - this(ParticleStorm.MOLANG::get, id); + this(ParticleStorm.MOLANG.get(), id); } public ResourceLocation getId() { @@ -30,18 +29,7 @@ public ResourceLocation getId() { } @Override - public @NotNull ParticleType getType() { - return type.get(); - } - - public static MapCodec codec(ParticleType type) { - return ResourceLocation.CODEC.xmap( - id -> new MolangParticleOption(() -> type, id), - option -> option.id - ).fieldOf("id"); - } - - public static StreamCodec streamCodec(ParticleType type) { - return ResourceLocation.STREAM_CODEC.map(id -> new MolangParticleOption(() -> type, id), option -> option.id); + public @NotNull ParticleType getType() { + return type; } } diff --git a/src/main/java/org/mesdag/particlestorm/particle/ParticleEmitter.java b/src/main/java/org/mesdag/particlestorm/particle/ParticleEmitter.java index 7c9273e..cede5fa 100644 --- a/src/main/java/org/mesdag/particlestorm/particle/ParticleEmitter.java +++ b/src/main/java/org/mesdag/particlestorm/particle/ParticleEmitter.java @@ -1,9 +1,7 @@ package org.mesdag.particlestorm.particle; -import net.minecraft.client.Minecraft; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.util.Mth; import net.minecraft.util.RandomSource; @@ -117,11 +115,7 @@ public void attachEntity(@Nullable Entity entity) { private void init() { this.preset = PSGameClient.LOADER.id2Emitter().get(particleId); if (preset == null) { - if (Minecraft.getInstance().player != null) { - Minecraft.getInstance().player.sendSystemMessage(Component.translatable("particle.notFound", particleId.toString())); - } - remove(); - return; + throw new IllegalArgumentException("Unknown particle id: '" + particleId + "'!"); } this.vars = new VariableTable(preset.vars); if (expression != null && !expression.initialized()) { diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg index e335bd3..1425b8b 100644 --- a/src/main/resources/META-INF/accesstransformer.cfg +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -5,3 +5,5 @@ public net.minecraft.client.particle.Particle setLocationFromBoundingbox()V public net.minecraft.client.particle.ParticleEngine$MutableSpriteSet protected net.minecraft.client.particle.ParticleEngine$MutableSpriteSet sprites protected net.minecraft.client.particle.ParticleEngine$MutableSpriteSet ()V +public net.minecraft.client.particle.ParticleEngine trackedParticleCounts +public net.minecraft.client.particle.ParticleEngine makeParticle(Lnet/minecraft/core/particles/ParticleOptions;DDDDDD)Lnet/minecraft/client/particle/Particle; diff --git a/src/main/resources/particlestorm.mixins.json b/src/main/resources/particlestorm.mixins.json index 6d7ff75..bc94ae6 100644 --- a/src/main/resources/particlestorm.mixins.json +++ b/src/main/resources/particlestorm.mixins.json @@ -12,8 +12,7 @@ "EntityMixin", "LivingEntityMixin", "MinecraftMixin", - "ParticleEngineAccessor", - "TextureAtlasMixin", + "ParticleEngineMixin", "TextureAtlasSpriteMixin", "integration.geckolib.AnimatableInstanceCacheMixin", "integration.geckolib.AnimationControllerMixin", From bb8120e1c7648a1fd844991a93ee0da56d81a295 Mon Sep 17 00:00:00 2001 From: westernat Date: Sun, 5 Oct 2025 22:01:24 +0800 Subject: [PATCH 05/22] =?UTF-8?q?=E5=BB=B6=E8=BF=9F=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E7=B2=92=E5=AD=90=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gradle.properties | 2 +- .../particlestorm/particle/MolangParticleOption.java | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/gradle.properties b/gradle.properties index fada27e..c5c418d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -31,7 +31,7 @@ mod_name=ParticleStorm # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=LGPL-3.0 # The mod version. See https://semver.org/ -mod_version=1.0.18 +mod_version=1.0.19 # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. # See https://maven.apache.org/guides/mini/guide-naming-conventions.html diff --git a/src/main/java/org/mesdag/particlestorm/particle/MolangParticleOption.java b/src/main/java/org/mesdag/particlestorm/particle/MolangParticleOption.java index eb8eb5a..0100706 100644 --- a/src/main/java/org/mesdag/particlestorm/particle/MolangParticleOption.java +++ b/src/main/java/org/mesdag/particlestorm/particle/MolangParticleOption.java @@ -9,19 +9,21 @@ import org.jetbrains.annotations.NotNull; import org.mesdag.particlestorm.ParticleStorm; +import java.util.function.Supplier; + public class MolangParticleOption implements ParticleOptions { public static final MapCodec CODEC = ResourceLocation.CODEC.fieldOf("id").xmap(MolangParticleOption::new, MolangParticleOption::getId); public static final StreamCodec STREAM_CODEC = ResourceLocation.STREAM_CODEC.map(MolangParticleOption::new, MolangParticleOption::getId); - private final ParticleType type; + private final Supplier> type; private final ResourceLocation id; - private MolangParticleOption(ParticleType type, ResourceLocation id) { + private MolangParticleOption(Supplier> type, ResourceLocation id) { this.type = type; this.id = id; } public MolangParticleOption(ResourceLocation id) { - this(ParticleStorm.MOLANG.get(), id); + this(ParticleStorm.MOLANG, id); } public ResourceLocation getId() { @@ -30,6 +32,6 @@ public ResourceLocation getId() { @Override public @NotNull ParticleType getType() { - return type; + return type.get(); } } From 5d617b1d189431b4bdd37f8fe3b99a473d430a81 Mon Sep 17 00:00:00 2001 From: westernat Date: Wed, 8 Oct 2025 13:14:26 +0800 Subject: [PATCH 06/22] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=90=8C=E4=B8=80?= =?UTF-8?q?=E4=B8=AAprocessor=E4=B8=8B=E4=B8=8D=E5=90=8Ccontroller?= =?UTF-8?q?=E5=AF=BC=E8=87=B4=E7=9A=84locator=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gradle.properties | 2 +- .../api/geckolib/GeckoLibHelper.java | 14 +++++------ .../mixed/IAnimationController.java | 8 ++++++- .../geckolib/AnimationControllerMixin.java | 23 +++++++++++++------ .../geckolib/AnimationProcessorMixin.java | 19 +-------------- 5 files changed, 31 insertions(+), 35 deletions(-) diff --git a/gradle.properties b/gradle.properties index c5c418d..0a53181 100644 --- a/gradle.properties +++ b/gradle.properties @@ -31,7 +31,7 @@ mod_name=ParticleStorm # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=LGPL-3.0 # The mod version. See https://semver.org/ -mod_version=1.0.19 +mod_version=1.0.20 # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. # See https://maven.apache.org/guides/mini/guide-naming-conventions.html diff --git a/src/main/java/org/mesdag/particlestorm/api/geckolib/GeckoLibHelper.java b/src/main/java/org/mesdag/particlestorm/api/geckolib/GeckoLibHelper.java index fc2c52b..24f8951 100644 --- a/src/main/java/org/mesdag/particlestorm/api/geckolib/GeckoLibHelper.java +++ b/src/main/java/org/mesdag/particlestorm/api/geckolib/GeckoLibHelper.java @@ -15,7 +15,6 @@ import software.bernie.geckolib.animatable.GeoAnimatable; import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache; import software.bernie.geckolib.animation.AnimationController; -import software.bernie.geckolib.animation.keyframe.event.ParticleKeyframeEvent; import software.bernie.geckolib.animation.keyframe.event.data.ParticleKeyframeData; import software.bernie.geckolib.cache.object.GeoBone; import software.bernie.geckolib.loading.json.raw.LocatorValue; @@ -42,18 +41,17 @@ public static double[] getLocatorRotation(Object locatorValue) { /** * @return true means failed to add emitter */ - public static boolean processParticleEffect(Object particleKeyframeEvent) { - ParticleKeyframeEvent event = (ParticleKeyframeEvent) particleKeyframeEvent; - List bones = ((IAnimationController) event.getController()).particlestorm$getBonesWhichHasLocators(); + public static boolean processParticleEffect(Object a, Object c, Object d) { + List bones = IAnimationController.of((AnimationController) c).particlestorm$getBonesWhichHasLocators(); if (bones.isEmpty()) return true; - ParticleKeyframeData keyframeData = event.getKeyframeData(); + ParticleKeyframeData keyframeData = (ParticleKeyframeData) d; IParticleKeyframeData iData = (IParticleKeyframeData) keyframeData; Entity entity = null; BlockEntity blockEntity = null; VariableTable variableTable; Level level; - GeoAnimatable animatable = event.getAnimatable(); + GeoAnimatable animatable = (GeoAnimatable) a; switch (animatable) { case Entity entity1 -> { entity = entity1; @@ -108,8 +106,8 @@ public static void setCurrentEntity(Object animatable, Entity entity) { } } - public static void removeEmittersWhenAnimationChange(int size, Object animationState, Object animatableInstanceCache) { - if (size > 0 && animationState == AnimationController.State.TRANSITIONING) { + public static void removeEmittersWhenAnimationChange(Object animationState, Object animatableInstanceCache) { + if (animationState == AnimationController.State.TRANSITIONING) { IntIterator iterator = IAnimatableInstanceCache.of((AnimatableInstanceCache) animatableInstanceCache).particlestorm$getCachedId().values().iterator(); while (iterator.hasNext()) { PSGameClient.LOADER.removeEmitter(iterator.nextInt(), false); diff --git a/src/main/java/org/mesdag/particlestorm/mixed/IAnimationController.java b/src/main/java/org/mesdag/particlestorm/mixed/IAnimationController.java index 10c827b..02a1410 100644 --- a/src/main/java/org/mesdag/particlestorm/mixed/IAnimationController.java +++ b/src/main/java/org/mesdag/particlestorm/mixed/IAnimationController.java @@ -1,11 +1,17 @@ package org.mesdag.particlestorm.mixed; +import software.bernie.geckolib.animation.AnimationController; import software.bernie.geckolib.cache.object.GeoBone; +import java.util.Collection; import java.util.List; public interface IAnimationController { List particlestorm$getBonesWhichHasLocators(); - void particlestorm$setBonesWhichHasLocators(List bones); + void particlestorm$setBonesWhichHasLocators(Collection registeredBones); + + static IAnimationController of(AnimationController controller) { + return (IAnimationController) controller; + } } diff --git a/src/main/java/org/mesdag/particlestorm/mixin/integration/geckolib/AnimationControllerMixin.java b/src/main/java/org/mesdag/particlestorm/mixin/integration/geckolib/AnimationControllerMixin.java index f085d35..297ba30 100644 --- a/src/main/java/org/mesdag/particlestorm/mixin/integration/geckolib/AnimationControllerMixin.java +++ b/src/main/java/org/mesdag/particlestorm/mixin/integration/geckolib/AnimationControllerMixin.java @@ -6,17 +6,21 @@ import org.apache.logging.log4j.Logger; import org.mesdag.particlestorm.api.geckolib.GeckoLibHelper; import org.mesdag.particlestorm.mixed.IAnimationController; +import org.mesdag.particlestorm.mixed.IGeoBone; import org.spongepowered.asm.mixin.*; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import software.bernie.geckolib.animatable.GeoAnimatable; import software.bernie.geckolib.animation.AnimationController; -import software.bernie.geckolib.animation.keyframe.event.ParticleKeyframeEvent; import software.bernie.geckolib.animation.keyframe.event.data.ParticleKeyframeData; import software.bernie.geckolib.cache.object.GeoBone; +import software.bernie.geckolib.loading.json.raw.LocatorValue; +import java.util.Collection; import java.util.List; +import java.util.Map; +import java.util.Objects; @Pseudo @Mixin(targets = "software.bernie.geckolib.animation.AnimationController", remap = false) @@ -32,23 +36,28 @@ public abstract class AnimationControllerMixin implemen @Override public List particlestorm$getBonesWhichHasLocators() { - return particlestorm$bonesWhichHasLocators; + return Objects.requireNonNullElse(particlestorm$bonesWhichHasLocators, List.of()); } @Override - public void particlestorm$setBonesWhichHasLocators(List bones) { - this.particlestorm$bonesWhichHasLocators = bones; + public void particlestorm$setBonesWhichHasLocators(Collection registeredBones) { + if (particlestorm$bonesWhichHasLocators == null) { + this.particlestorm$bonesWhichHasLocators = registeredBones.stream().filter(bone -> { + Map locators = IGeoBone.of(bone).particlestorm$getLocators(); + return locators != null && !locators.isEmpty(); + }).toList(); + } } @WrapWithCondition(method = "processCurrentAnimation", at = @At(value = "INVOKE", target = "Lorg/apache/logging/log4j/Logger;log(Lorg/apache/logging/log4j/Level;Ljava/lang/String;)V", ordinal = 1)) private boolean processParticleEffect(Logger instance, Level level, String s, @Local(argsOnly = true, ordinal = 0) double adjustedTick, @Local ParticleKeyframeData keyframeData) { - return GeckoLibHelper.processParticleEffect(new ParticleKeyframeEvent<>(animatable, adjustedTick, (AnimationController) (Object) this, keyframeData)); + return GeckoLibHelper.processParticleEffect(animatable, this, keyframeData); } @Inject(method = "resetEventKeyFrames", at = @At("HEAD")) private void removeEmitters(CallbackInfo ci) { - if (particlestorm$bonesWhichHasLocators != null) { - GeckoLibHelper.removeEmittersWhenAnimationChange(particlestorm$bonesWhichHasLocators.size(), animationState, animatable.getAnimatableInstanceCache()); + if (!particlestorm$getBonesWhichHasLocators().isEmpty()) { + GeckoLibHelper.removeEmittersWhenAnimationChange(animationState, animatable.getAnimatableInstanceCache()); } } } diff --git a/src/main/java/org/mesdag/particlestorm/mixin/integration/geckolib/AnimationProcessorMixin.java b/src/main/java/org/mesdag/particlestorm/mixin/integration/geckolib/AnimationProcessorMixin.java index 730b9b5..3c80d79 100644 --- a/src/main/java/org/mesdag/particlestorm/mixin/integration/geckolib/AnimationProcessorMixin.java +++ b/src/main/java/org/mesdag/particlestorm/mixin/integration/geckolib/AnimationProcessorMixin.java @@ -2,11 +2,9 @@ import com.llamalad7.mixinextras.sugar.Local; import org.mesdag.particlestorm.mixed.IAnimationController; -import org.mesdag.particlestorm.mixed.IGeoBone; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Pseudo; import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @@ -15,13 +13,9 @@ import software.bernie.geckolib.animation.AnimationController; import software.bernie.geckolib.animation.AnimationState; import software.bernie.geckolib.cache.object.GeoBone; -import software.bernie.geckolib.loading.json.raw.LocatorValue; import software.bernie.geckolib.model.GeoModel; import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; @Pseudo @Mixin(targets = "software.bernie.geckolib.animation.AnimationProcessor", remap = false) @@ -29,19 +23,8 @@ public abstract class AnimationProcessorMixin { @Shadow public abstract Collection getRegisteredBones(); - @Unique - private List particlestorm$bonesWhichHasLocators; - @Inject(method = "tickAnimation", at = @At(value = "INVOKE", target = "Lsoftware/bernie/geckolib/animation/AnimationController;process(Lsoftware/bernie/geckolib/model/GeoModel;Lsoftware/bernie/geckolib/animation/AnimationState;Ljava/util/Map;Ljava/util/Map;DZ)V")) private void tickLocators(T animatable, GeoModel model, AnimatableManager animatableManager, double animTime, AnimationState state, boolean crashWhenCantFindBone, CallbackInfo ci, @Local AnimationController controller) { - if (particlestorm$bonesWhichHasLocators == null) { - this.particlestorm$bonesWhichHasLocators = getRegisteredBones().stream() - .filter(bone -> { - Map locators = IGeoBone.of(bone).particlestorm$getLocators(); - return locators != null && !locators.isEmpty(); - }) - .collect(Collectors.toList()); - } - ((IAnimationController) controller).particlestorm$setBonesWhichHasLocators(particlestorm$bonesWhichHasLocators); + IAnimationController.of(controller).particlestorm$setBonesWhichHasLocators(getRegisteredBones()); } } From ea39a977eb68a63404256d88485c49c4c87e9680 Mon Sep 17 00:00:00 2001 From: westernat Date: Fri, 7 Nov 2025 19:05:07 +0800 Subject: [PATCH 07/22] =?UTF-8?q?=E5=B0=9D=E8=AF=95=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E5=B4=A9=E6=BA=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gradle.properties | 2 +- .../mesdag/particlestorm/PSGameClient.java | 2 +- .../particle/MolangParticleLoader.java | 61 +++++++++++-------- 3 files changed, 39 insertions(+), 26 deletions(-) diff --git a/gradle.properties b/gradle.properties index 0a53181..efc9f10 100644 --- a/gradle.properties +++ b/gradle.properties @@ -31,7 +31,7 @@ mod_name=ParticleStorm # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=LGPL-3.0 # The mod version. See https://semver.org/ -mod_version=1.0.20 +mod_version=1.1.0 # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. # See https://maven.apache.org/guides/mini/guide-naming-conventions.html diff --git a/src/main/java/org/mesdag/particlestorm/PSGameClient.java b/src/main/java/org/mesdag/particlestorm/PSGameClient.java index 631cab6..6312b39 100644 --- a/src/main/java/org/mesdag/particlestorm/PSGameClient.java +++ b/src/main/java/org/mesdag/particlestorm/PSGameClient.java @@ -96,7 +96,7 @@ private static void renderLevelStage(RenderLevelStageEvent event) { float partialTicks = event.getPartialTick().getGameTimeDeltaPartialTick(true); PoseStack poseStack = event.getPoseStack(); MultiBufferSource.BufferSource bufferSource = minecraft.renderBuffers().bufferSource(); - for (ParticleEmitter emitter : LOADER.emitters.values()) { + for (ParticleEmitter emitter : LOADER.getEmitters()) { double x = Mth.lerp(partialTicks, emitter.posO.x, emitter.pos.x); double y = Mth.lerp(partialTicks, emitter.posO.y, emitter.pos.y); double z = Mth.lerp(partialTicks, emitter.posO.z, emitter.pos.z); diff --git a/src/main/java/org/mesdag/particlestorm/particle/MolangParticleLoader.java b/src/main/java/org/mesdag/particlestorm/particle/MolangParticleLoader.java index 1f551b9..6b34e20 100644 --- a/src/main/java/org/mesdag/particlestorm/particle/MolangParticleLoader.java +++ b/src/main/java/org/mesdag/particlestorm/particle/MolangParticleLoader.java @@ -46,7 +46,7 @@ public class MolangParticleLoader implements PreparableReloadListener { private Map id2Effect = new Hashtable<>(); private Map id2Particle = new Hashtable<>(); private Map id2Emitter = new Hashtable<>(); - public final Int2ObjectMap emitters = new Int2ObjectOpenHashMap<>(); + private final Int2ObjectOpenHashMap emitters = new Int2ObjectOpenHashMap<>(); private final Object2ObjectMap> tracker = new Object2ObjectOpenHashMap<>(); private final IntAllocator allocator = new IntAllocator(); @@ -65,43 +65,56 @@ public Map id2Emitter() { } public void tick(LocalPlayer localPlayer) { - if (initialized) { - if (!emitters.isEmpty()) { - int renderDistSqr = Mth.square(Minecraft.getInstance().options.renderDistance().get() * 16); - ObjectIterator> iterator = emitters.int2ObjectEntrySet().iterator(); - while (iterator.hasNext()) { - ParticleEmitter emitter = iterator.next().getValue(); + if (!initialized) { + for (ParticlePreset detail : id2Particle.values()) { + for (IParticleComponent component : detail.effect.orderedParticleComponents) { + component.initialize(localPlayer.level()); + } + } + removeAll(); + this.initialized = true; + } + if (!emitters.isEmpty()) { + int renderDistSqr = Mth.square(Minecraft.getInstance().options.renderDistance().get() * 16); + ObjectIterator> iterator = emitters.int2ObjectEntrySet().fastIterator(); + while (iterator.hasNext()) { + ParticleEmitter emitter = iterator.next().getValue(); + try { if (emitter.isRemoved() || emitter.level.dimension() != localPlayer.level().dimension()) { - emitter.onRemove(); allocator.release(emitter.id); + emitter.onRemove(); + emitter.remove(); iterator.remove(); } else if (Mth.square(emitter.pos.x - localPlayer.getX()) + Mth.square(emitter.pos.z - localPlayer.getZ()) < renderDistSqr) { emitter.tick(); } - } - } - if (!tracker.isEmpty()) { - ObjectIterator>> iterator1 = tracker.entrySet().iterator(); - while (iterator1.hasNext()) { - Map.Entry> entry = iterator1.next(); - if (entry.getKey().isRemoved()) { - iterator1.remove(); - } else if (entry.getValue().removeIf(ParticleEmitter::isRemoved) && entry.getValue().isEmpty()) { - iterator1.remove(); + } catch (Exception e) { + ParticleStorm.LOGGER.warn("Error ticking: {}", e.getMessage()); + e.printStackTrace(); + if (emitter != null) { + emitter.remove(); } + iterator.remove(); } } - } else { - for (ParticlePreset detail : id2Particle.values()) { - for (IParticleComponent component : detail.effect.orderedParticleComponents) { - component.initialize(localPlayer.level()); + } + if (!tracker.isEmpty()) { + ObjectIterator>> iterator1 = tracker.entrySet().iterator(); + while (iterator1.hasNext()) { + Map.Entry> entry = iterator1.next(); + if (entry.getKey().isRemoved()) { + iterator1.remove(); + } else if (entry.getValue().removeIf(ParticleEmitter::isRemoved) && entry.getValue().isEmpty()) { + iterator1.remove(); } } - removeAll(); - this.initialized = true; } } + public Iterable getEmitters() { + return emitters.values(); + } + public int totalEmitterCount() { return emitters.size(); } From 415f65c834b34c25cbbc647c2bfd56ee2de57578 Mon Sep 17 00:00:00 2001 From: westernat Date: Mon, 24 Nov 2025 14:01:42 +0800 Subject: [PATCH 08/22] =?UTF-8?q?=E6=8F=90=E5=8F=96=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gradle.properties | 10 +- .../mesdag/particlestorm/PSGameClient.java | 3 +- .../mesdag/particlestorm/ParticleStorm.java | 5 +- .../mesdag/particlestorm/api/IComponent.java | 4 +- .../api/IMolangParticleInstance.java | 111 ++++++++ .../particlestorm/api/IParticleComponent.java | 5 +- .../particlestorm/api/geckolib/TestBlock.java | 7 +- .../api/geckolib/package-info.java | 7 + .../particlestorm/api/package-info.java | 7 + .../data/component/EmitterShape.java | 14 +- .../ParticleAppearanceBillboard.java | 111 ++++---- .../component/ParticleAppearanceTinting.java | 8 +- .../data/component/ParticleInitialSpeed.java | 8 +- .../data/component/ParticleInitialSpin.java | 8 +- .../component/ParticleInitialization.java | 6 +- .../component/ParticleLifeTimeEvents.java | 16 +- .../component/ParticleLifetimeExpression.java | 6 +- .../component/ParticleLifetimeKillPlane.java | 12 +- .../component/ParticleMotionCollision.java | 12 +- .../data/component/ParticleMotionDynamic.java | 20 +- .../component/ParticleMotionParametric.java | 6 +- .../data/component/package-info.java | 7 + .../particlestorm/data/curve/CurveType.java | 4 +- .../data/curve/package-info.java | 7 + .../data/description/DescriptionMaterial.java | 3 +- .../data/description/package-info.java | 7 + .../data/event/ParticleEffect.java | 3 +- .../data/event/package-info.java | 7 + .../data/molang/compiler/MolangParser.java | 3 +- .../data/molang/compiler/Operator.java | 3 +- .../network/EmitterAttachPacketS2C.java | 3 +- .../network/EmitterCreationPacketS2C.java | 3 +- .../network/EmitterRemovalPacket.java | 3 +- .../network/EmitterSynchronizePacket.java | 3 +- .../particlestorm/network/package-info.java | 7 + .../mesdag/particlestorm/package-info.java | 7 + .../particlestorm/particle/EmitterPreset.java | 3 +- .../particle/ExtendMutableSpriteSet.java | 3 +- .../particle/MolangParticleInstance.java | 247 ++++++++++++++---- .../particle/MolangParticleLoader.java | 3 +- .../particle/MolangParticleOption.java | 3 +- .../particle/ParticlePreset.java | 6 +- .../particlestorm/particle/package-info.java | 7 + 43 files changed, 515 insertions(+), 213 deletions(-) create mode 100644 src/main/java/org/mesdag/particlestorm/api/IMolangParticleInstance.java create mode 100644 src/main/java/org/mesdag/particlestorm/api/geckolib/package-info.java create mode 100644 src/main/java/org/mesdag/particlestorm/api/package-info.java create mode 100644 src/main/java/org/mesdag/particlestorm/data/component/package-info.java create mode 100644 src/main/java/org/mesdag/particlestorm/data/curve/package-info.java create mode 100644 src/main/java/org/mesdag/particlestorm/data/description/package-info.java create mode 100644 src/main/java/org/mesdag/particlestorm/data/event/package-info.java create mode 100644 src/main/java/org/mesdag/particlestorm/network/package-info.java create mode 100644 src/main/java/org/mesdag/particlestorm/package-info.java create mode 100644 src/main/java/org/mesdag/particlestorm/particle/package-info.java diff --git a/gradle.properties b/gradle.properties index efc9f10..5e4ff98 100644 --- a/gradle.properties +++ b/gradle.properties @@ -31,7 +31,7 @@ mod_name=ParticleStorm # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=LGPL-3.0 # The mod version. See https://semver.org/ -mod_version=1.1.0 +mod_version=1.2.0 # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. # See https://maven.apache.org/guides/mini/guide-naming-conventions.html @@ -43,7 +43,7 @@ mod_description=Uses a Bedrock Edition JSON format for particle effects. geckolib_version=4.7.5.1 -# systemProp.http.proxyHost=localhost -# systemProp.http.proxyPort=7890 -# systemProp.https.proxyHost=localhost -# systemProp.https.proxyPort=7890 +systemProp.http.proxyHost=localhost +systemProp.http.proxyPort=7890 +systemProp.https.proxyHost=localhost +systemProp.https.proxyPort=7890 diff --git a/src/main/java/org/mesdag/particlestorm/PSGameClient.java b/src/main/java/org/mesdag/particlestorm/PSGameClient.java index 6312b39..6a62721 100644 --- a/src/main/java/org/mesdag/particlestorm/PSGameClient.java +++ b/src/main/java/org/mesdag/particlestorm/PSGameClient.java @@ -25,7 +25,6 @@ import net.neoforged.neoforge.client.event.RegisterClientReloadListenersEvent; import net.neoforged.neoforge.client.event.RenderLevelStageEvent; import net.neoforged.neoforge.common.NeoForge; -import org.jetbrains.annotations.NotNull; import org.mesdag.particlestorm.api.IComponent; import org.mesdag.particlestorm.api.IEventNode; import org.mesdag.particlestorm.api.geckolib.ExampleBlockEntityRenderer; @@ -40,7 +39,7 @@ public final class PSGameClient { public static final MolangParticleLoader LOADER = new MolangParticleLoader(); public static final ParticleRenderType PARTICLE_ADD = new ParticleRenderType() { @Override - public BufferBuilder begin(Tesselator tesselator, @NotNull TextureManager textureManager) { + public BufferBuilder begin(Tesselator tesselator, TextureManager textureManager) { RenderSystem.enableDepthTest(); Minecraft.getInstance().gameRenderer.lightTexture().turnOnLightLayer(); RenderSystem.depthMask(false); diff --git a/src/main/java/org/mesdag/particlestorm/ParticleStorm.java b/src/main/java/org/mesdag/particlestorm/ParticleStorm.java index 101ecdf..b62b111 100644 --- a/src/main/java/org/mesdag/particlestorm/ParticleStorm.java +++ b/src/main/java/org/mesdag/particlestorm/ParticleStorm.java @@ -23,7 +23,6 @@ import net.neoforged.neoforge.network.registration.PayloadRegistrar; import net.neoforged.neoforge.registries.DeferredHolder; import net.neoforged.neoforge.registries.DeferredRegister; -import org.jetbrains.annotations.NotNull; import org.mesdag.particlestorm.api.geckolib.TestBlock; import org.mesdag.particlestorm.network.EmitterAttachPacketS2C; import org.mesdag.particlestorm.network.EmitterCreationPacketS2C; @@ -49,12 +48,12 @@ public final class ParticleStorm { public static final DeferredRegister> PARTICLE = DeferredRegister.create(BuiltInRegistries.PARTICLE_TYPE, MODID); public static final DeferredHolder, ParticleType> MOLANG = PARTICLE.register("molang", () -> new ParticleType<>(false) { @Override - public @NotNull MapCodec codec() { + public MapCodec codec() { return MolangParticleOption.CODEC; } @Override - public @NotNull StreamCodec streamCodec() { + public StreamCodec streamCodec() { return MolangParticleOption.STREAM_CODEC; } }); diff --git a/src/main/java/org/mesdag/particlestorm/api/IComponent.java b/src/main/java/org/mesdag/particlestorm/api/IComponent.java index 4cde27e..6858ec6 100644 --- a/src/main/java/org/mesdag/particlestorm/api/IComponent.java +++ b/src/main/java/org/mesdag/particlestorm/api/IComponent.java @@ -23,9 +23,7 @@ static void register(String vanillaPath, Codec codec) { List getAllMolangExp(); - /** - * 小于0表示早期初始化 - */ + /// @return <= 0 means early initialize default int order() { return 1000; } diff --git a/src/main/java/org/mesdag/particlestorm/api/IMolangParticleInstance.java b/src/main/java/org/mesdag/particlestorm/api/IMolangParticleInstance.java new file mode 100644 index 0000000..32f1cd1 --- /dev/null +++ b/src/main/java/org/mesdag/particlestorm/api/IMolangParticleInstance.java @@ -0,0 +1,111 @@ +package org.mesdag.particlestorm.api; + +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.core.particles.ParticleGroup; +import net.minecraft.world.phys.AABB; +import org.joml.Vector3f; +import org.mesdag.particlestorm.particle.ParticlePreset; + +import java.util.List; + +public interface IMolangParticleInstance extends MolangInstance { + ParticlePreset getPreset(); + + TextureAtlasSprite getSprite(); + + Vector3f getAcceleration(); + + Vector3f getFacingDirection(); + + Vector3f getInitialSpeed(); + + void setXRot(float x); + + void setYRot(float y); + + void setZRot(float z); + + void setZRotD(float delta); + + float getZRotD(); + + void setCollisionDrag(float drag); + + void setCoefficientOfRestitution(float coefficient); + + void setExpireOnContact(boolean b); + + void setComponents(List components); + + float getScaleU(); + + float getScaleV(); + + void setBillboardSize(float[] size); + + void setUvSize(float[] size); + + float[] getUvSize(); + + void setUvStep(float[] step); + + float[] getUvStep(); + + void setMaxFrame(int frame); + + int getMaxFrame(); + + void setCurrentFrame(int frame); + + int getCurrentFrame(); + + void setInsideKillPlane(boolean b); + + boolean isInsideKillPlane(); + + void setParticleGroup(ParticleGroup group); + + void setLastTimeline(int last); + + int getLastTimeline(); + + double getXd(); + + double getYd(); + + double getZd(); + + double getX(); + + double getY(); + + double getZ(); + + void setPosO(double x, double y, double z); + + void setColor(float red, float green, float blue, float alpha); + + void setUV(float u, float v, float w, float h); + + void setCollision(boolean bool); + + void moveDirectly(double x, double y, double z); + + // region particle + void setLifetime(int lifetime); + + int getLifetime(); + + int getAge(); + + void remove(); + + void setBoundingBox(AABB box); + + AABB getBoundingBox(); + + void setLocationFromBoundingbox(); + + void setParticleSpeed(double xd, double yd, double zd); + // endregion +} diff --git a/src/main/java/org/mesdag/particlestorm/api/IParticleComponent.java b/src/main/java/org/mesdag/particlestorm/api/IParticleComponent.java index d1b4792..ac63ea3 100644 --- a/src/main/java/org/mesdag/particlestorm/api/IParticleComponent.java +++ b/src/main/java/org/mesdag/particlestorm/api/IParticleComponent.java @@ -1,12 +1,11 @@ package org.mesdag.particlestorm.api; import net.minecraft.world.level.Level; -import org.mesdag.particlestorm.particle.MolangParticleInstance; public interface IParticleComponent extends IComponent { - default void update(MolangParticleInstance instance) {} + default void update(IMolangParticleInstance instance) {} - default void apply(MolangParticleInstance instance) {} + default void apply(IMolangParticleInstance instance) {} default boolean requireUpdate() { return false; diff --git a/src/main/java/org/mesdag/particlestorm/api/geckolib/TestBlock.java b/src/main/java/org/mesdag/particlestorm/api/geckolib/TestBlock.java index 9bdc501..cbea6e0 100644 --- a/src/main/java/org/mesdag/particlestorm/api/geckolib/TestBlock.java +++ b/src/main/java/org/mesdag/particlestorm/api/geckolib/TestBlock.java @@ -10,7 +10,6 @@ import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.Shapes; import net.minecraft.world.phys.shapes.VoxelShape; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.mesdag.particlestorm.ParticleStorm; import software.bernie.geckolib.animatable.GeoBlockEntity; @@ -28,17 +27,17 @@ public TestBlock() { } @Override - public @Nullable BlockEntity newBlockEntity(@NotNull BlockPos pos, @NotNull BlockState state) { + public @Nullable BlockEntity newBlockEntity(BlockPos pos, BlockState state) { return new Entity(pos, state); } @Override - public @NotNull RenderShape getRenderShape(@NotNull BlockState state) { + public RenderShape getRenderShape(BlockState state) { return RenderShape.ENTITYBLOCK_ANIMATED; } @Override - protected @NotNull VoxelShape getShape(@NotNull BlockState state, @NotNull BlockGetter level, @NotNull BlockPos pos, @NotNull CollisionContext context) { + protected VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) { return BOX; } diff --git a/src/main/java/org/mesdag/particlestorm/api/geckolib/package-info.java b/src/main/java/org/mesdag/particlestorm/api/geckolib/package-info.java new file mode 100644 index 0000000..22df274 --- /dev/null +++ b/src/main/java/org/mesdag/particlestorm/api/geckolib/package-info.java @@ -0,0 +1,7 @@ +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +package org.mesdag.particlestorm.api.geckolib; + +import net.minecraft.MethodsReturnNonnullByDefault; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/src/main/java/org/mesdag/particlestorm/api/package-info.java b/src/main/java/org/mesdag/particlestorm/api/package-info.java new file mode 100644 index 0000000..1cd5279 --- /dev/null +++ b/src/main/java/org/mesdag/particlestorm/api/package-info.java @@ -0,0 +1,7 @@ +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +package org.mesdag.particlestorm.api; + +import net.minecraft.MethodsReturnNonnullByDefault; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/src/main/java/org/mesdag/particlestorm/data/component/EmitterShape.java b/src/main/java/org/mesdag/particlestorm/data/component/EmitterShape.java index c6f7ac7..aadd0b1 100644 --- a/src/main/java/org/mesdag/particlestorm/data/component/EmitterShape.java +++ b/src/main/java/org/mesdag/particlestorm/data/component/EmitterShape.java @@ -10,7 +10,6 @@ import net.minecraft.util.StringRepresentable; import net.minecraft.world.entity.EntityDimensions; import net.minecraft.world.phys.Vec3; -import org.jetbrains.annotations.NotNull; import org.joml.Quaternionf; import org.joml.Vector3f; import org.mesdag.particlestorm.api.IEmitterComponent; @@ -74,7 +73,7 @@ private void emittingParticle(ParticleEmitter emitter) { if (instance == null) throw new NullPointerException("Failed to create particle!"); instance.setEmitter(emitter); - ParticlePreset preset = instance.preset; + ParticlePreset preset = instance.getPreset(); MathHelper.redirect(preset.assignments, instance.getVars()); Vector3f position = new Vector3f(); @@ -83,7 +82,7 @@ private void emittingParticle(ParticleEmitter emitter) { for (IParticleComponent component : preset.effect.orderedParticleEarlyComponents) { component.apply(instance); } - speed.mul(instance.initialSpeed); + speed.mul(instance.getInitialSpeed()); if (emitter.parentMode == ParticleEmitter.ParentMode.LOCATOR) { position.x *= -1; position.y *= -1; @@ -110,14 +109,13 @@ private void emittingParticle(ParticleEmitter emitter) { instance.setParticleSpeed(speed.x, speed.y, speed.z); instance.setPos(position.x, position.y, position.z); instance.setPosO(position.x, position.y, position.z); - instance.particleGroup = emitter.particleGroup; + instance.setParticleGroup(emitter.particleGroup); for (IParticleComponent component : preset.effect.orderedParticleComponents) { component.apply(instance); } - instance.components = preset.effect.orderedParticleComponentsWhichRequireUpdate; - instance.motionDynamic = preset.motionDynamic; - if (!instance.motionDynamic) instance.setParticleSpeed(0.0, 0.0, 0.0); + instance.setComponents(preset.effect.orderedParticleComponentsWhichRequireUpdate); + if (!preset.motionDynamic) instance.setParticleSpeed(0.0, 0.0, 0.0); Minecraft.getInstance().particleEngine.add(instance); } @@ -508,7 +506,7 @@ public static class Direction implements StringRepresentable { } @Override - public @NotNull String getSerializedName() { + public String getSerializedName() { return name; } diff --git a/src/main/java/org/mesdag/particlestorm/data/component/ParticleAppearanceBillboard.java b/src/main/java/org/mesdag/particlestorm/data/component/ParticleAppearanceBillboard.java index 9baed9e..05c7391 100644 --- a/src/main/java/org/mesdag/particlestorm/data/component/ParticleAppearanceBillboard.java +++ b/src/main/java/org/mesdag/particlestorm/data/component/ParticleAppearanceBillboard.java @@ -6,14 +6,13 @@ import net.minecraft.util.ExtraCodecs; import net.minecraft.util.Mth; import net.minecraft.util.StringRepresentable; -import org.jetbrains.annotations.NotNull; +import org.mesdag.particlestorm.api.IMolangParticleInstance; import org.mesdag.particlestorm.api.IParticleComponent; import org.mesdag.particlestorm.data.DuplicateFieldDecoder; import org.mesdag.particlestorm.data.molang.FloatMolangExp; import org.mesdag.particlestorm.data.molang.FloatMolangExp2; import org.mesdag.particlestorm.data.molang.FloatMolangExp3; import org.mesdag.particlestorm.data.molang.MolangExp; -import org.mesdag.particlestorm.particle.MolangParticleInstance; import java.util.List; import java.util.Locale; @@ -42,76 +41,69 @@ public List getAllMolangExp() { } @Override - public void update(MolangParticleInstance instance) { - if (faceCameraMode.isDirection()) { - if (direction.mode == ParticleAppearanceBillboard.Direction.Mode.CUSTOM_DIRECTION) { - float[] values = direction.customDirection.calculate(instance); - instance.xRot = values[0]; - instance.yRot = values[1]; - instance.setRoll(values[2]); - } else { - if (direction.minSpeedThreshold > 0.0F && Mth.lengthSquared(instance.getXd(), instance.getYd(), instance.getZd()) > instance.preset.minSpeedThresholdSqr) { - instance.facingDirection.set(instance.getXd(), instance.getYd(), instance.getZd()).normalize(); - } - } - } - if (size.initialized()) { - instance.billboardSize = size.calculate(instance); - } + public void update(IMolangParticleInstance instance) { + doFacingCameraMode(instance); + doSize(instance); if (uv != UV.EMPTY) { UV.Flipbook flipbook = uv.flipbook; if (flipbook == UV.Flipbook.EMPTY) { updateSimpleUV(instance); } else if (flipbook.stretchToLifetime) { updateFlipbookUV(instance); - instance.maxFrame = (int) flipbook.maxFrame.calculate(instance); - instance.currentFrame = instance.maxFrame * instance.getAge() / instance.getLifetime(); + instance.setMaxFrame((int) flipbook.maxFrame.calculate(instance)); + instance.setCurrentFrame(instance.getMaxFrame() * instance.getAge() / instance.getLifetime()); } else if (instance.getLevel().getGameTime() % flipbook.framesPerTick < 1.0F) { updateFlipbookUV(instance); - instance.maxFrame = (int) flipbook.maxFrame.calculate(instance); - if (instance.currentFrame < instance.maxFrame) { - instance.currentFrame++; - if (flipbook.loop && instance.currentFrame == instance.maxFrame) { - instance.currentFrame = 0; + instance.setMaxFrame((int) flipbook.maxFrame.calculate(instance)); + if (instance.getCurrentFrame() < instance.getMaxFrame()) { + instance.setCurrentFrame(instance.getCurrentFrame() + 1); + if (flipbook.loop && instance.getCurrentFrame() == instance.getMaxFrame()) { + instance.setCurrentFrame(0); } } else { - instance.currentFrame = instance.maxFrame - 1; + instance.setCurrentFrame(instance.getMaxFrame() - 1); } } } } @Override - public void apply(MolangParticleInstance instance) { + public void apply(IMolangParticleInstance instance) { + doFacingCameraMode(instance); + doSize(instance); + if (uv != UV.EMPTY) { + if (uv.flipbook == UV.Flipbook.EMPTY) { + updateSimpleUV(instance); + } else { + instance.setUvSize(uv.flipbook.getSizeUV(instance)); + instance.getUvSize()[0] *= instance.getScaleU(); + instance.getUvSize()[1] *= instance.getScaleV(); + instance.setUvStep(uv.flipbook.getStepUV(instance)); + instance.getUvStep()[0] *= instance.getScaleU(); + instance.getUvStep()[1] *= instance.getScaleV(); + updateFlipbookUV(instance); + } + } + } + + private void doFacingCameraMode(IMolangParticleInstance instance) { if (faceCameraMode.isDirection()) { - if (direction.mode == ParticleAppearanceBillboard.Direction.Mode.CUSTOM_DIRECTION) { + if (direction.mode == Direction.Mode.CUSTOM_DIRECTION) { float[] values = direction.customDirection.calculate(instance); - instance.xRot = values[0]; - instance.yRot = values[1]; - instance.setRoll(values[2]); + instance.setXRot(values[0]); + instance.setYRot(values[1]); + instance.setZRot(values[2]); } else { - double xdSqr = instance.getXd() * instance.getXd(); - double zdSqr = instance.getZd() * instance.getZd(); - if (direction.minSpeedThreshold > 0.0F && xdSqr + instance.getYd() * instance.getYd() + zdSqr > instance.preset.minSpeedThresholdSqr) { - instance.facingDirection.set(instance.getXd(), instance.getYd(), instance.getZd()).normalize(); + if (direction.minSpeedThreshold > 0.0F && Mth.lengthSquared(instance.getXd(), instance.getYd(), instance.getZd()) > instance.getPreset().minSpeedThresholdSqr) { + instance.getFacingDirection().set(instance.getXd(), instance.getYd(), instance.getZd()).normalize(); } } } + } + + private void doSize(IMolangParticleInstance instance) { if (size.initialized()) { - instance.billboardSize = size.calculate(instance); - } - if (uv != UV.EMPTY) { - if (uv.flipbook == UV.Flipbook.EMPTY) { - updateSimpleUV(instance); - } else { - instance.uvSize = uv.flipbook.getSizeUV(instance); - instance.uvSize[0] *= instance.scaleU; - instance.uvSize[1] *= instance.scaleV; - instance.uvStep = uv.flipbook.getStepUV(instance); - instance.uvStep[0] *= instance.scaleU; - instance.uvStep[1] *= instance.scaleV; - updateFlipbookUV(instance); - } + instance.setBillboardSize(size.calculate(instance)); } } @@ -120,22 +112,21 @@ public boolean requireUpdate() { return true; } - private void updateSimpleUV(MolangParticleInstance instance) { + private void updateSimpleUV(IMolangParticleInstance instance) { float[] base = uv.uv.calculate(instance); float[] size = uv.uvSize.calculate(instance); int x = instance.getSprite().getX(); int y = instance.getSprite().getY(); - instance.setUV(x + base[0], y + base[1], size[0] * instance.scaleU, size[1] * instance.scaleV); + instance.setUV(x + base[0], y + base[1], size[0] * instance.getScaleU(), size[1] * instance.getScaleV()); } - private void updateFlipbookUV(MolangParticleInstance instance) { + private void updateFlipbookUV(IMolangParticleInstance instance) { float[] base = uv.flipbook.baseUV.calculate(instance); - int index = instance.currentFrame; - float u = instance.uvStep[0] * index; - float v = instance.uvStep[1] * index; + float u = instance.getUvStep()[0] * instance.getCurrentFrame(); + float v = instance.getUvStep()[1] * instance.getCurrentFrame(); int x = instance.getSprite().getX(); int y = instance.getSprite().getY(); - instance.setUV(x + base[0] + u, y + base[1] + v, instance.uvSize[0], instance.uvSize[1]); + instance.setUV(x + base[0] + u, y + base[1] + v, instance.getUvSize()[0], instance.getUvSize()[1]); } @Override @@ -164,7 +155,7 @@ public enum FaceCameraMode implements StringRepresentable { public static final Codec CODEC = StringRepresentable.fromEnum(FaceCameraMode::values); @Override - public @NotNull String getSerializedName() { + public String getSerializedName() { return name().toLowerCase(Locale.ROOT); } @@ -207,7 +198,7 @@ public enum Mode implements StringRepresentable { }); @Override - public @NotNull String getSerializedName() { + public String getSerializedName() { return name().toLowerCase(Locale.ROOT); } @@ -298,11 +289,11 @@ public Flipbook(FloatMolangExp2 baseUV, FloatMolangExp2 sizeUV, FloatMolangExp2 } } - public float[] getSizeUV(MolangParticleInstance instance) { + public float[] getSizeUV(IMolangParticleInstance instance) { return sizeUV.calculate(instance); } - public float[] getStepUV(MolangParticleInstance instance) { + public float[] getStepUV(IMolangParticleInstance instance) { return stepUV.calculate(instance); } diff --git a/src/main/java/org/mesdag/particlestorm/data/component/ParticleAppearanceTinting.java b/src/main/java/org/mesdag/particlestorm/data/component/ParticleAppearanceTinting.java index f3803e0..2664e22 100644 --- a/src/main/java/org/mesdag/particlestorm/data/component/ParticleAppearanceTinting.java +++ b/src/main/java/org/mesdag/particlestorm/data/component/ParticleAppearanceTinting.java @@ -6,11 +6,11 @@ import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.util.Mth; import net.minecraft.util.Tuple; +import org.mesdag.particlestorm.api.IMolangParticleInstance; import org.mesdag.particlestorm.api.IParticleComponent; import org.mesdag.particlestorm.api.MolangInstance; import org.mesdag.particlestorm.data.molang.FloatMolangExp; import org.mesdag.particlestorm.data.molang.MolangExp; -import org.mesdag.particlestorm.particle.MolangParticleInstance; import java.util.*; import java.util.stream.Stream; @@ -38,11 +38,11 @@ public List getAllMolangExp() { } @Override - public void update(MolangParticleInstance instance) { + public void update(IMolangParticleInstance instance) { apply(instance); } - private float[] getCalculatedColor(MolangParticleInstance instance, ArrayList> list, float ratio) { + private float[] getCalculatedColor(IMolangParticleInstance instance, ArrayList> list, float ratio) { int n = 0; for (int index = 0; index < list.size(); index++) { Tuple tuple = list.get(index); @@ -72,7 +72,7 @@ private float mix(float first, float second, float ratio) { } @Override - public void apply(MolangParticleInstance instance) { + public void apply(IMolangParticleInstance instance) { if (color.interpolant.initialized() && !color.gradient.map.isEmpty()) { float interpolant = color.interpolant.calculate(instance); float[] calculated = getCalculatedColor(instance, color.gradient.list, interpolant / color.gradient.range); diff --git a/src/main/java/org/mesdag/particlestorm/data/component/ParticleInitialSpeed.java b/src/main/java/org/mesdag/particlestorm/data/component/ParticleInitialSpeed.java index 5045fee..131303e 100644 --- a/src/main/java/org/mesdag/particlestorm/data/component/ParticleInitialSpeed.java +++ b/src/main/java/org/mesdag/particlestorm/data/component/ParticleInitialSpeed.java @@ -2,11 +2,11 @@ import com.mojang.datafixers.util.Either; import com.mojang.serialization.Codec; +import org.mesdag.particlestorm.api.IMolangParticleInstance; import org.mesdag.particlestorm.api.IParticleComponent; import org.mesdag.particlestorm.data.molang.FloatMolangExp; import org.mesdag.particlestorm.data.molang.FloatMolangExp3; import org.mesdag.particlestorm.data.molang.MolangExp; -import org.mesdag.particlestorm.particle.MolangParticleInstance; import java.util.List; @@ -32,13 +32,13 @@ public List getAllMolangExp() { } @Override - public void apply(MolangParticleInstance instance) { + public void apply(IMolangParticleInstance instance) { speed.ifLeft(exp -> { float value = exp.calculate(instance); - instance.initialSpeed.set(value); + instance.getInitialSpeed().set(value); }).ifRight(exp3 -> { float[] mul = exp3.calculate(instance); - instance.initialSpeed.set(mul); + instance.getInitialSpeed().set(mul); }); } diff --git a/src/main/java/org/mesdag/particlestorm/data/component/ParticleInitialSpin.java b/src/main/java/org/mesdag/particlestorm/data/component/ParticleInitialSpin.java index 5b7b289..1784bbc 100644 --- a/src/main/java/org/mesdag/particlestorm/data/component/ParticleInitialSpin.java +++ b/src/main/java/org/mesdag/particlestorm/data/component/ParticleInitialSpin.java @@ -3,10 +3,10 @@ import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.util.Mth; +import org.mesdag.particlestorm.api.IMolangParticleInstance; import org.mesdag.particlestorm.api.IParticleComponent; import org.mesdag.particlestorm.data.molang.FloatMolangExp; import org.mesdag.particlestorm.data.molang.MolangExp; -import org.mesdag.particlestorm.particle.MolangParticleInstance; import java.util.List; @@ -33,9 +33,9 @@ public List getAllMolangExp() { } @Override - public void apply(MolangParticleInstance instance) { - instance.setRoll(rotation.calculate(instance) * Mth.DEG_TO_RAD); - instance.rolld = rotationRate.calculate(instance) * instance.getInvTickRate() * Mth.DEG_TO_RAD; + public void apply(IMolangParticleInstance instance) { + instance.setZRot(rotation.calculate(instance) * Mth.DEG_TO_RAD); + instance.setZRotD(rotationRate.calculate(instance) * instance.getInvTickRate() * Mth.DEG_TO_RAD); } @Override diff --git a/src/main/java/org/mesdag/particlestorm/data/component/ParticleInitialization.java b/src/main/java/org/mesdag/particlestorm/data/component/ParticleInitialization.java index 37e8869..988bd87 100644 --- a/src/main/java/org/mesdag/particlestorm/data/component/ParticleInitialization.java +++ b/src/main/java/org/mesdag/particlestorm/data/component/ParticleInitialization.java @@ -2,10 +2,10 @@ import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; +import org.mesdag.particlestorm.api.IMolangParticleInstance; import org.mesdag.particlestorm.api.IParticleComponent; import org.mesdag.particlestorm.data.molang.FloatMolangExp; import org.mesdag.particlestorm.data.molang.MolangExp; -import org.mesdag.particlestorm.particle.MolangParticleInstance; import java.util.List; @@ -28,12 +28,12 @@ public List getAllMolangExp() { } @Override - public void update(MolangParticleInstance instance) { + public void update(IMolangParticleInstance instance) { perRenderExpression.calculate(instance); } @Override - public void apply(MolangParticleInstance instance) { + public void apply(IMolangParticleInstance instance) { perRenderExpression.calculate(instance); } diff --git a/src/main/java/org/mesdag/particlestorm/data/component/ParticleLifeTimeEvents.java b/src/main/java/org/mesdag/particlestorm/data/component/ParticleLifeTimeEvents.java index b21bff7..07fcfbb 100644 --- a/src/main/java/org/mesdag/particlestorm/data/component/ParticleLifeTimeEvents.java +++ b/src/main/java/org/mesdag/particlestorm/data/component/ParticleLifeTimeEvents.java @@ -6,9 +6,9 @@ import net.minecraft.util.Tuple; import org.mesdag.particlestorm.ParticleStorm; import org.mesdag.particlestorm.api.IEventNode; +import org.mesdag.particlestorm.api.IMolangParticleInstance; import org.mesdag.particlestorm.api.IParticleComponent; import org.mesdag.particlestorm.data.molang.MolangExp; -import org.mesdag.particlestorm.particle.MolangParticleInstance; import java.util.ArrayList; import java.util.Comparator; @@ -61,11 +61,11 @@ public List getAllMolangExp() { } @Override - public void update(MolangParticleInstance instance) { - for (int i = instance.lastTimeline; i < sortedTimeline.size(); i++) { + public void update(IMolangParticleInstance instance) { + for (int i = instance.getLastTimeline(); i < sortedTimeline.size(); i++) { Tuple, List> tuple = sortedTimeline.get(i); if (tuple.getA().apply(instance.getLifetime())) { - instance.lastTimeline = i + 1; + instance.setLastTimeline(i + 1); executes(instance, tuple.getB()); break; } @@ -73,7 +73,7 @@ public void update(MolangParticleInstance instance) { } @Override - public void apply(MolangParticleInstance instance) { + public void apply(IMolangParticleInstance instance) { executes(instance, creationEvent); } @@ -82,7 +82,7 @@ public boolean requireUpdate() { return true; } - public void onExpiration(MolangParticleInstance instance) { + public void onExpiration(IMolangParticleInstance instance) { executes(instance, expirationEvent); } @@ -94,9 +94,9 @@ public String toString() { "timeline=" + timeline + ']'; } - private static void executes(MolangParticleInstance instance, List triggers) { + private static void executes(IMolangParticleInstance instance, List triggers) { for (String event : triggers) { - for (IEventNode node : instance.preset.effect.events.get(event).values()) { + for (IEventNode node : instance.getPreset().effect.events.get(event).values()) { node.execute(instance); } } diff --git a/src/main/java/org/mesdag/particlestorm/data/component/ParticleLifetimeExpression.java b/src/main/java/org/mesdag/particlestorm/data/component/ParticleLifetimeExpression.java index a6c24b9..019e1ff 100644 --- a/src/main/java/org/mesdag/particlestorm/data/component/ParticleLifetimeExpression.java +++ b/src/main/java/org/mesdag/particlestorm/data/component/ParticleLifetimeExpression.java @@ -2,10 +2,10 @@ import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; +import org.mesdag.particlestorm.api.IMolangParticleInstance; import org.mesdag.particlestorm.api.IParticleComponent; import org.mesdag.particlestorm.data.molang.FloatMolangExp; import org.mesdag.particlestorm.data.molang.MolangExp; -import org.mesdag.particlestorm.particle.MolangParticleInstance; import java.util.List; @@ -37,14 +37,14 @@ public List getAllMolangExp() { } @Override - public void update(MolangParticleInstance instance) { + public void update(IMolangParticleInstance instance) { if (expirationExpression.initialized() && expirationExpression.getVariable().get(instance) != 0.0) { instance.remove(); } } @Override - public void apply(MolangParticleInstance instance) { + public void apply(IMolangParticleInstance instance) { if (maxLifetime.initialized()) { instance.setLifetime(Math.max((int) (maxLifetime.calculate(instance) * 20), 1)); } diff --git a/src/main/java/org/mesdag/particlestorm/data/component/ParticleLifetimeKillPlane.java b/src/main/java/org/mesdag/particlestorm/data/component/ParticleLifetimeKillPlane.java index 9ebdf4e..240f824 100644 --- a/src/main/java/org/mesdag/particlestorm/data/component/ParticleLifetimeKillPlane.java +++ b/src/main/java/org/mesdag/particlestorm/data/component/ParticleLifetimeKillPlane.java @@ -1,9 +1,9 @@ package org.mesdag.particlestorm.data.component; import com.mojang.serialization.Codec; +import org.mesdag.particlestorm.api.IMolangParticleInstance; import org.mesdag.particlestorm.api.IParticleComponent; import org.mesdag.particlestorm.data.molang.MolangExp; -import org.mesdag.particlestorm.particle.MolangParticleInstance; import java.util.List; @@ -35,16 +35,16 @@ public ParticleLifetimeKillPlane(float A, float B, float C, float D) { } @Override - public void update(MolangParticleInstance instance) { - if (instance.motionDynamic) return; - if (distanceSqr(instance.getX(), instance.getY(), instance.getZ()) > killDistanceSqr == instance.insideKillPlane) { + public void update(IMolangParticleInstance instance) { + if (instance.getPreset().motionDynamic) return; + if (distanceSqr(instance.getX(), instance.getY(), instance.getZ()) > killDistanceSqr == instance.isInsideKillPlane()) { instance.remove(); } } @Override - public void apply(MolangParticleInstance instance) { - instance.insideKillPlane = distanceSqr(instance.getX(), instance.getY(), instance.getZ()) < killDistanceSqr; + public void apply(IMolangParticleInstance instance) { + instance.setInsideKillPlane(distanceSqr(instance.getX(), instance.getY(), instance.getZ()) < killDistanceSqr); } @Override diff --git a/src/main/java/org/mesdag/particlestorm/data/component/ParticleMotionCollision.java b/src/main/java/org/mesdag/particlestorm/data/component/ParticleMotionCollision.java index 037dd64..b4e0e9f 100644 --- a/src/main/java/org/mesdag/particlestorm/data/component/ParticleMotionCollision.java +++ b/src/main/java/org/mesdag/particlestorm/data/component/ParticleMotionCollision.java @@ -6,10 +6,10 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.util.ExtraCodecs; import net.minecraft.util.Mth; +import org.mesdag.particlestorm.api.IMolangParticleInstance; import org.mesdag.particlestorm.api.IParticleComponent; import org.mesdag.particlestorm.data.molang.BoolMolangExp; import org.mesdag.particlestorm.data.molang.MolangExp; -import org.mesdag.particlestorm.particle.MolangParticleInstance; import java.util.Collections; import java.util.List; @@ -59,19 +59,19 @@ public List getAllMolangExp() { } @Override - public void update(MolangParticleInstance instance) { + public void update(IMolangParticleInstance instance) { instance.setCollision(enabled.get(instance)); } @Override - public void apply(MolangParticleInstance instance) { + public void apply(IMolangParticleInstance instance) { update(instance); - instance.collisionDrag = collisionDrag * instance.getInvTickRate(); - instance.coefficientOfRestitution = coefficientOfRestitution; + instance.setCollisionDrag(collisionDrag * instance.getInvTickRate()); + instance.setCoefficientOfRestitution(coefficientOfRestitution); float radius = Math.max(collisionRadius, Mth.EPSILON); instance.setBoundingBox(instance.getBoundingBox().inflate(radius, 0.0, radius)); instance.setLocationFromBoundingbox(); - instance.expireOnContact = expireOnContact; + instance.setExpireOnContact(expireOnContact); } @Override diff --git a/src/main/java/org/mesdag/particlestorm/data/component/ParticleMotionDynamic.java b/src/main/java/org/mesdag/particlestorm/data/component/ParticleMotionDynamic.java index 0a1721a..ade3bf1 100644 --- a/src/main/java/org/mesdag/particlestorm/data/component/ParticleMotionDynamic.java +++ b/src/main/java/org/mesdag/particlestorm/data/component/ParticleMotionDynamic.java @@ -3,11 +3,12 @@ import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.resources.ResourceLocation; +import org.joml.Vector3f; +import org.mesdag.particlestorm.api.IMolangParticleInstance; import org.mesdag.particlestorm.api.IParticleComponent; import org.mesdag.particlestorm.data.molang.FloatMolangExp; import org.mesdag.particlestorm.data.molang.FloatMolangExp3; import org.mesdag.particlestorm.data.molang.MolangExp; -import org.mesdag.particlestorm.particle.MolangParticleInstance; import java.util.List; @@ -58,28 +59,29 @@ public List getAllMolangExp() { } @Override - public void update(MolangParticleInstance instance) { + public void update(IMolangParticleInstance instance) { apply(instance); } @Override - public void apply(MolangParticleInstance instance) { + public void apply(IMolangParticleInstance instance) { float invTickRate = instance.getInvTickRate(); float tickRate = instance.getLevel().tickRateManager().tickrate(); - instance.acceleration.set(linerAcceleration.calculate(instance)); + Vector3f acceleration = instance.getAcceleration(); + acceleration.set(linerAcceleration.calculate(instance)); float c = -linearDragCoefficient.calculate(instance); double xd = instance.getXd(); double yd = instance.getYd(); double zd = instance.getZd(); - instance.acceleration.add(c * (float) xd * tickRate, c * (float) yd * tickRate, c * (float) zd * tickRate); + acceleration.add(c * (float) xd * tickRate, c * (float) yd * tickRate, c * (float) zd * tickRate); float v = invTickRate * invTickRate; instance.setParticleSpeed( - xd + instance.acceleration.x * v, - yd + instance.acceleration.y * v, - zd + instance.acceleration.z * v + xd + acceleration.x * v, + yd + acceleration.y * v, + zd + acceleration.z * v ); - instance.rolld = (rotationAcceleration.calculate(instance) - rotationDragCoefficient.calculate(instance) * instance.rolld * tickRate) * v; + instance.setZRotD((rotationAcceleration.calculate(instance) - rotationDragCoefficient.calculate(instance) * instance.getZRotD() * tickRate) * v); } @Override diff --git a/src/main/java/org/mesdag/particlestorm/data/component/ParticleMotionParametric.java b/src/main/java/org/mesdag/particlestorm/data/component/ParticleMotionParametric.java index 8faed28..f88067d 100644 --- a/src/main/java/org/mesdag/particlestorm/data/component/ParticleMotionParametric.java +++ b/src/main/java/org/mesdag/particlestorm/data/component/ParticleMotionParametric.java @@ -2,11 +2,11 @@ import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; +import org.mesdag.particlestorm.api.IMolangParticleInstance; import org.mesdag.particlestorm.api.IParticleComponent; import org.mesdag.particlestorm.data.molang.FloatMolangExp; import org.mesdag.particlestorm.data.molang.FloatMolangExp3; import org.mesdag.particlestorm.data.molang.MolangExp; -import org.mesdag.particlestorm.particle.MolangParticleInstance; import java.util.List; @@ -46,14 +46,14 @@ public List getAllMolangExp() { } @Override - public void update(MolangParticleInstance instance) { + public void update(IMolangParticleInstance instance) { float[] pos = relativePosition.calculate(instance); instance.moveDirectly(pos[0], pos[1], pos[2]); if (direction != FloatMolangExp3.ZERO) { float[] dir = direction.calculate(instance); instance.setParticleSpeed(dir[0], dir[1], dir[2]); } - instance.setRoll(rotation.calculate(instance)); + instance.setZRot(rotation.calculate(instance)); } @Override diff --git a/src/main/java/org/mesdag/particlestorm/data/component/package-info.java b/src/main/java/org/mesdag/particlestorm/data/component/package-info.java new file mode 100644 index 0000000..73783b9 --- /dev/null +++ b/src/main/java/org/mesdag/particlestorm/data/component/package-info.java @@ -0,0 +1,7 @@ +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +package org.mesdag.particlestorm.data.component; + +import net.minecraft.MethodsReturnNonnullByDefault; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/src/main/java/org/mesdag/particlestorm/data/curve/CurveType.java b/src/main/java/org/mesdag/particlestorm/data/curve/CurveType.java index f0b368a..4461319 100644 --- a/src/main/java/org/mesdag/particlestorm/data/curve/CurveType.java +++ b/src/main/java/org/mesdag/particlestorm/data/curve/CurveType.java @@ -2,7 +2,6 @@ import com.mojang.serialization.Codec; import net.minecraft.util.StringRepresentable; -import org.jetbrains.annotations.NotNull; import java.util.Locale; @@ -15,8 +14,7 @@ public enum CurveType implements StringRepresentable { public static final Codec CODEC = StringRepresentable.fromEnum(CurveType::values); @Override - public @NotNull String getSerializedName() { + public String getSerializedName() { return name().toLowerCase(Locale.ROOT); } - } diff --git a/src/main/java/org/mesdag/particlestorm/data/curve/package-info.java b/src/main/java/org/mesdag/particlestorm/data/curve/package-info.java new file mode 100644 index 0000000..1ce7cff --- /dev/null +++ b/src/main/java/org/mesdag/particlestorm/data/curve/package-info.java @@ -0,0 +1,7 @@ +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +package org.mesdag.particlestorm.data.curve; + +import net.minecraft.MethodsReturnNonnullByDefault; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/src/main/java/org/mesdag/particlestorm/data/description/DescriptionMaterial.java b/src/main/java/org/mesdag/particlestorm/data/description/DescriptionMaterial.java index 5e0ab52..8e2c880 100644 --- a/src/main/java/org/mesdag/particlestorm/data/description/DescriptionMaterial.java +++ b/src/main/java/org/mesdag/particlestorm/data/description/DescriptionMaterial.java @@ -2,7 +2,6 @@ import com.mojang.serialization.Codec; import net.minecraft.util.StringRepresentable; -import org.jetbrains.annotations.NotNull; import java.util.Locale; @@ -22,7 +21,7 @@ public enum DescriptionMaterial implements StringRepresentable { public static final Codec CODEC = StringRepresentable.fromEnum(DescriptionMaterial::values); @Override - public @NotNull String getSerializedName() { + public String getSerializedName() { return name().toLowerCase(Locale.ROOT); } } diff --git a/src/main/java/org/mesdag/particlestorm/data/description/package-info.java b/src/main/java/org/mesdag/particlestorm/data/description/package-info.java new file mode 100644 index 0000000..326dd95 --- /dev/null +++ b/src/main/java/org/mesdag/particlestorm/data/description/package-info.java @@ -0,0 +1,7 @@ +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +package org.mesdag.particlestorm.data.description; + +import net.minecraft.MethodsReturnNonnullByDefault; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/src/main/java/org/mesdag/particlestorm/data/event/ParticleEffect.java b/src/main/java/org/mesdag/particlestorm/data/event/ParticleEffect.java index 4b04874..e765927 100644 --- a/src/main/java/org/mesdag/particlestorm/data/event/ParticleEffect.java +++ b/src/main/java/org/mesdag/particlestorm/data/event/ParticleEffect.java @@ -9,7 +9,6 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.util.ByIdMap; import net.minecraft.util.StringRepresentable; -import org.jetbrains.annotations.NotNull; import org.mesdag.particlestorm.PSGameClient; import org.mesdag.particlestorm.api.IEventNode; import org.mesdag.particlestorm.api.MolangInstance; @@ -111,7 +110,7 @@ public int getId() { } @Override - public @NotNull String getSerializedName() { + public String getSerializedName() { return name().toLowerCase(Locale.ROOT); } diff --git a/src/main/java/org/mesdag/particlestorm/data/event/package-info.java b/src/main/java/org/mesdag/particlestorm/data/event/package-info.java new file mode 100644 index 0000000..eaadc24 --- /dev/null +++ b/src/main/java/org/mesdag/particlestorm/data/event/package-info.java @@ -0,0 +1,7 @@ +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +package org.mesdag.particlestorm.data.event; + +import net.minecraft.MethodsReturnNonnullByDefault; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/src/main/java/org/mesdag/particlestorm/data/molang/compiler/MolangParser.java b/src/main/java/org/mesdag/particlestorm/data/molang/compiler/MolangParser.java index f6f1f8f..191f095 100644 --- a/src/main/java/org/mesdag/particlestorm/data/molang/compiler/MolangParser.java +++ b/src/main/java/org/mesdag/particlestorm/data/molang/compiler/MolangParser.java @@ -3,7 +3,6 @@ import com.mojang.datafixers.util.Either; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import net.minecraft.Util; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.mesdag.particlestorm.data.molang.VariableTable; import org.mesdag.particlestorm.data.molang.compiler.function.MathFunction; @@ -403,7 +402,7 @@ public static boolean isOperativeSymbol(char symbol) { } @Deprecated(forRemoval = true) - public static boolean isOperativeSymbol(@NotNull String symbol) { + public static boolean isOperativeSymbol(String symbol) { return Operator.isOperator(symbol) || symbol.equals("?") || symbol.equals(":"); } diff --git a/src/main/java/org/mesdag/particlestorm/data/molang/compiler/Operator.java b/src/main/java/org/mesdag/particlestorm/data/molang/compiler/Operator.java index bd548ab..5e4feae 100644 --- a/src/main/java/org/mesdag/particlestorm/data/molang/compiler/Operator.java +++ b/src/main/java/org/mesdag/particlestorm/data/molang/compiler/Operator.java @@ -4,7 +4,6 @@ import it.unimi.dsi.fastutil.chars.CharSet; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import net.minecraft.Util; -import org.jetbrains.annotations.NotNull; import java.util.Arrays; import java.util.Map; @@ -103,7 +102,7 @@ public double compute(double argA, double argB) { } @Override - public int compareTo(@NotNull Operator operator) { + public int compareTo(Operator operator) { return Integer.compare(this.precedence, operator.precedence); } diff --git a/src/main/java/org/mesdag/particlestorm/network/EmitterAttachPacketS2C.java b/src/main/java/org/mesdag/particlestorm/network/EmitterAttachPacketS2C.java index dcb69e0..81fe611 100644 --- a/src/main/java/org/mesdag/particlestorm/network/EmitterAttachPacketS2C.java +++ b/src/main/java/org/mesdag/particlestorm/network/EmitterAttachPacketS2C.java @@ -10,7 +10,6 @@ import net.minecraft.world.entity.player.Player; import net.neoforged.neoforge.network.PacketDistributor; import net.neoforged.neoforge.network.handling.IPayloadContext; -import org.jetbrains.annotations.NotNull; import org.mesdag.particlestorm.PSGameClient; import org.mesdag.particlestorm.ParticleStorm; import org.mesdag.particlestorm.particle.ParticleEmitter; @@ -24,7 +23,7 @@ public record EmitterAttachPacketS2C(int particleId, int entityId) implements Cu ); @Override - public @NotNull Type type() { + public Type type() { return TYPE; } diff --git a/src/main/java/org/mesdag/particlestorm/network/EmitterCreationPacketS2C.java b/src/main/java/org/mesdag/particlestorm/network/EmitterCreationPacketS2C.java index 5e2a64b..d91be43 100644 --- a/src/main/java/org/mesdag/particlestorm/network/EmitterCreationPacketS2C.java +++ b/src/main/java/org/mesdag/particlestorm/network/EmitterCreationPacketS2C.java @@ -13,7 +13,6 @@ import net.neoforged.neoforge.network.PacketDistributor; import net.neoforged.neoforge.network.handling.IPayloadContext; import net.neoforged.neoforge.server.ServerLifecycleHooks; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.joml.Vector3f; import org.mesdag.particlestorm.PSGameClient; @@ -33,7 +32,7 @@ public record EmitterCreationPacketS2C(ResourceLocation id, Vector3f pos, Molang ); @Override - public @NotNull Type type() { + public Type type() { return TYPE; } diff --git a/src/main/java/org/mesdag/particlestorm/network/EmitterRemovalPacket.java b/src/main/java/org/mesdag/particlestorm/network/EmitterRemovalPacket.java index 0b9671f..73219bd 100644 --- a/src/main/java/org/mesdag/particlestorm/network/EmitterRemovalPacket.java +++ b/src/main/java/org/mesdag/particlestorm/network/EmitterRemovalPacket.java @@ -10,7 +10,6 @@ import net.minecraft.world.entity.player.Player; import net.neoforged.neoforge.network.PacketDistributor; import net.neoforged.neoforge.network.handling.IPayloadContext; -import org.jetbrains.annotations.NotNull; import org.mesdag.particlestorm.PSGameClient; import org.mesdag.particlestorm.ParticleStorm; import org.mesdag.particlestorm.particle.ParticleEmitter; @@ -26,7 +25,7 @@ public record EmitterRemovalPacket(int id) implements CustomPacketPayload { ); @Override - public @NotNull Type type() { + public Type type() { return TYPE; } diff --git a/src/main/java/org/mesdag/particlestorm/network/EmitterSynchronizePacket.java b/src/main/java/org/mesdag/particlestorm/network/EmitterSynchronizePacket.java index 9e4dd6d..e6ed4b0 100644 --- a/src/main/java/org/mesdag/particlestorm/network/EmitterSynchronizePacket.java +++ b/src/main/java/org/mesdag/particlestorm/network/EmitterSynchronizePacket.java @@ -10,7 +10,6 @@ import net.minecraft.world.entity.player.Player; import net.neoforged.neoforge.network.PacketDistributor; import net.neoforged.neoforge.network.handling.IPayloadContext; -import org.jetbrains.annotations.NotNull; import org.mesdag.particlestorm.PSGameClient; import org.mesdag.particlestorm.ParticleStorm; import org.mesdag.particlestorm.particle.ParticleEmitter; @@ -26,7 +25,7 @@ public record EmitterSynchronizePacket(int id, CompoundTag tag) implements Custo public static final String KEY = "particlestorm:emitters"; @Override - public @NotNull Type type() { + public Type type() { return TYPE; } diff --git a/src/main/java/org/mesdag/particlestorm/network/package-info.java b/src/main/java/org/mesdag/particlestorm/network/package-info.java new file mode 100644 index 0000000..f256445 --- /dev/null +++ b/src/main/java/org/mesdag/particlestorm/network/package-info.java @@ -0,0 +1,7 @@ +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +package org.mesdag.particlestorm.network; + +import net.minecraft.MethodsReturnNonnullByDefault; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/src/main/java/org/mesdag/particlestorm/package-info.java b/src/main/java/org/mesdag/particlestorm/package-info.java new file mode 100644 index 0000000..7157968 --- /dev/null +++ b/src/main/java/org/mesdag/particlestorm/package-info.java @@ -0,0 +1,7 @@ +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +package org.mesdag.particlestorm; + +import net.minecraft.MethodsReturnNonnullByDefault; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/src/main/java/org/mesdag/particlestorm/particle/EmitterPreset.java b/src/main/java/org/mesdag/particlestorm/particle/EmitterPreset.java index f86d496..a940f8c 100644 --- a/src/main/java/org/mesdag/particlestorm/particle/EmitterPreset.java +++ b/src/main/java/org/mesdag/particlestorm/particle/EmitterPreset.java @@ -1,6 +1,5 @@ package org.mesdag.particlestorm.particle; -import org.jetbrains.annotations.NotNull; import org.mesdag.particlestorm.api.IEmitterComponent; import org.mesdag.particlestorm.api.IEventNode; import org.mesdag.particlestorm.data.MathHelper; @@ -77,7 +76,7 @@ public EmitterPreset(MolangParticleOption option, List compon this.assignments = toInit; } - private static @NotNull Hashtable addDefaultVariables() { + private static Hashtable addDefaultVariables() { Hashtable table = new Hashtable<>(); table.computeIfAbsent("variable.emitter_age", s -> new Variable(s, i -> i.getEmitter().tickAge())); table.computeIfAbsent("variable.emitter_lifetime", s -> new Variable(s, i -> i.getEmitter().tickLifetime())); diff --git a/src/main/java/org/mesdag/particlestorm/particle/ExtendMutableSpriteSet.java b/src/main/java/org/mesdag/particlestorm/particle/ExtendMutableSpriteSet.java index a9bf972..02288a5 100644 --- a/src/main/java/org/mesdag/particlestorm/particle/ExtendMutableSpriteSet.java +++ b/src/main/java/org/mesdag/particlestorm/particle/ExtendMutableSpriteSet.java @@ -2,7 +2,6 @@ import net.minecraft.client.particle.ParticleEngine; import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.List; @@ -28,7 +27,7 @@ public void clear() { } @Override - public void rebind(@NotNull List sprites) { + public void rebind(List sprites) { this.sprites = new ArrayList<>(sprites); } diff --git a/src/main/java/org/mesdag/particlestorm/particle/MolangParticleInstance.java b/src/main/java/org/mesdag/particlestorm/particle/MolangParticleInstance.java index 9c9fa7a..928928e 100644 --- a/src/main/java/org/mesdag/particlestorm/particle/MolangParticleInstance.java +++ b/src/main/java/org/mesdag/particlestorm/particle/MolangParticleInstance.java @@ -15,14 +15,13 @@ import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; import net.neoforged.fml.ModList; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.joml.Quaternionf; import org.joml.Vector3f; import org.mesdag.particlestorm.PSGameClient; import org.mesdag.particlestorm.api.IEventNode; +import org.mesdag.particlestorm.api.IMolangParticleInstance; import org.mesdag.particlestorm.api.IParticleComponent; -import org.mesdag.particlestorm.api.MolangInstance; import org.mesdag.particlestorm.data.component.ParticleMotionCollision; import org.mesdag.particlestorm.data.molang.VariableTable; import org.mesdag.particlestorm.mixed.ITextureAtlasSprite; @@ -30,54 +29,51 @@ import java.util.List; import java.util.Optional; -public class MolangParticleInstance extends TextureSheetParticle implements MolangInstance { +public class MolangParticleInstance extends TextureSheetParticle implements IMolangParticleInstance { public static final int FULL_LIGHT = 0xF000F0; private static final boolean isSodiumLoaded = ModList.get().isLoaded("sodium"); - public final RandomSource random; - public final ParticlePreset preset; + protected final ParticlePreset preset; protected ParticleVariableTable vars; protected final float originX; protected final float originY; - public Vector3f acceleration = new Vector3f(); - public Vector3f facingDirection = new Vector3f(); - public Vector3f initialSpeed = new Vector3f(); - public float xRot = 0.0F; - public float yRot = 0.0F; + protected Vector3f acceleration = new Vector3f(); + protected Vector3f facingDirection = new Vector3f(); + protected Vector3f initialSpeed = new Vector3f(); + protected float xRot = 0.0F; + protected float yRot = 0.0F; protected float xRotO = 0.0F; protected float yRotO = 0.0F; - public float rolld = 0.0F; - private boolean hasCollision = false; - public float collisionDrag = 0.0F; - public float coefficientOfRestitution = 0.0F; - public boolean expireOnContact = false; + protected float rolld = 0.0F; + protected boolean hasCollision = false; + protected float collisionDrag = 0.0F; + protected float coefficientOfRestitution = 0.0F; + protected boolean expireOnContact = false; protected final double particleRandom1; protected final double particleRandom2; protected final double particleRandom3; protected final double particleRandom4; - public List components; + protected List components; protected ParticleEmitter emitter; - public boolean motionDynamic = false; - public final float scaleU; - public final float scaleV; - public float[] billboardSize = new float[2]; - public float[] uvSize; - public float[] uvStep; - public int maxFrame = 1; - public int currentFrame = 0; - public float[] UV; + protected final float scaleU; + protected final float scaleV; + protected float[] billboardSize = new float[2]; + protected float[] uvSize; + protected float[] uvStep; + protected int maxFrame = 1; + protected int currentFrame = 0; + protected float[] UV; - public boolean insideKillPlane; - public ParticleGroup particleGroup; - public int lastTimeline = 0; + protected boolean insideKillPlane; + protected ParticleGroup particleGroup; + protected int lastTimeline = 0; public MolangParticleInstance(ParticlePreset preset, ClientLevel level, double x, double y, double z, ExtendMutableSpriteSet sprites) { super(level, x, y, z); this.friction = 1.0F; - this.random = level.getRandom(); this.preset = preset; setSprite(sprites.get(preset.effect.description.parameters().getTextureIndex())); this.originX = ((ITextureAtlasSprite) sprite).particlestorm$getOriginX(); @@ -85,6 +81,7 @@ public MolangParticleInstance(ParticlePreset preset, ClientLevel level, double x this.scaleU = sprite.contents().width() * preset.invTextureWidth; this.scaleV = sprite.contents().height() * preset.invTextureHeight; + RandomSource random = level.getRandom(); this.particleRandom1 = random.nextDouble(); this.particleRandom2 = random.nextDouble(); this.particleRandom3 = random.nextDouble(); @@ -96,49 +93,211 @@ public void setEmitter(ParticleEmitter emitter) { this.vars = new ParticleVariableTable(preset.vars, emitter.vars); } + @Override + public ParticlePreset getPreset() { + return preset; + } + + @Override + public TextureAtlasSprite getSprite() { + return sprite; + } + + @Override + public Vector3f getAcceleration() { + return acceleration; + } + + @Override + public Vector3f getFacingDirection() { + return facingDirection; + } + + @Override + public Vector3f getInitialSpeed() { + return initialSpeed; + } + + @Override + public void setXRot(float x) { + this.xRot = x; + } + + @Override + public void setYRot(float y) { + this.yRot = y; + } + + @Override + public void setZRot(float z) { + this.roll = z; + } + + @Override + public void setZRotD(float delta) { + this.rolld = delta; + } + + @Override + public float getZRotD() { + return rolld; + } + + @Override + public void setCollisionDrag(float drag) { + this.collisionDrag = drag; + } + + @Override + public void setCoefficientOfRestitution(float coefficient) { + this.coefficientOfRestitution = coefficient; + } + + @Override + public void setExpireOnContact(boolean b) { + this.expireOnContact = b; + } + + @Override + public void setComponents(List components) { + this.components = components; + } + + @Override + public float getScaleU() { + return scaleU; + } + + @Override + public float getScaleV() { + return scaleV; + } + + @Override + public void setBillboardSize(float[] billboardSize) { + this.billboardSize = billboardSize; + } + + @Override + public void setUvSize(float[] size) { + this.uvSize = size; + } + + @Override + public float[] getUvSize() { + return uvSize; + } + + @Override + public void setUvStep(float[] step) { + this.uvStep = step; + } + + @Override + public float[] getUvStep() { + return uvStep; + } + + @Override + public void setMaxFrame(int frame) { + this.maxFrame = frame; + } + + @Override + public int getMaxFrame() { + return maxFrame; + } + + @Override + public void setCurrentFrame(int frame) { + this.currentFrame = frame; + } + + @Override + public int getCurrentFrame() { + return currentFrame; + } + + @Override + public void setInsideKillPlane(boolean b) { + this.insideKillPlane = b; + } + + @Override + public boolean isInsideKillPlane() { + return insideKillPlane; + } + + @Override + public void setParticleGroup(ParticleGroup group) { + this.particleGroup = group; + } + + @Override + public void setLastTimeline(int last) { + this.lastTimeline = last; + } + + @Override + public int getLastTimeline() { + return lastTimeline; + } + + @Override public double getXd() { return xd; } + @Override public double getYd() { return yd; } + @Override public double getZd() { return zd; } + @Override public double getX() { return x; } + @Override public double getY() { return y; } + @Override public double getZ() { return z; } + @Override public void setPosO(double x, double y, double z) { this.xo = x; this.yo = y; this.zo = z; } + /// @see MolangParticleInstance#setZRot(float) + /// @deprecated public void setRoll(float roll) { this.roll = roll; } + @Deprecated public float getRoll() { return roll; } + @Override public void setColor(float red, float green, float blue, float alpha) { super.setColor(red, green, blue); super.setAlpha(alpha); } + @Override public void setUV(float u, float v, float w, float h) { if (UV == null) this.UV = new float[4]; this.UV[0] = u / originX; @@ -147,10 +306,17 @@ public void setUV(float u, float v, float w, float h) { this.UV[3] = (v + h) / originY; } + @Override public void setCollision(boolean bool) { this.hasCollision = bool; } + @Override + public void moveDirectly(double x, double y, double z) { + setBoundingBox(getBoundingBox().move(x, y, z)); + setLocationFromBoundingbox(); + } + @Override public VariableTable getVars() { return vars; @@ -215,10 +381,6 @@ public ParticleEmitter getEmitter() { return emitter; } - public TextureAtlasSprite getSprite() { - return sprite; - } - @Override protected float getU0() { return UV == null ? super.getU0() : UV[0]; @@ -256,7 +418,7 @@ public void tick() { } @Override - public void render(@NotNull VertexConsumer buffer, @NotNull Camera renderInfo, float partialTicks) { + public void render(VertexConsumer buffer, Camera renderInfo, float partialTicks) { Quaternionf quaternionf = new Quaternionf(); getFacingCameraMode().setRotation(this, quaternionf, renderInfo, partialTicks); if (xRot != 0.0F) quaternionf.rotateX(Mth.lerp(partialTicks, xRotO, xRot)); @@ -266,7 +428,7 @@ public void render(@NotNull VertexConsumer buffer, @NotNull Camera renderInfo, f } @Override - protected void renderRotatedQuad(@NotNull VertexConsumer buffer, @NotNull Quaternionf quaternion, float x, float y, float z, float partialTicks) { + protected void renderRotatedQuad(VertexConsumer buffer, Quaternionf quaternion, float x, float y, float z, float partialTicks) { if (isSodiumLoaded) { float f1 = getU0(); float f2 = getU1(); @@ -283,16 +445,11 @@ protected void renderRotatedQuad(@NotNull VertexConsumer buffer, @NotNull Quater } @Override - protected void renderVertex(@NotNull VertexConsumer buffer, @NotNull Quaternionf quaternion, float x, float y, float z, float xOffset, float yOffset, float quadSize, float u, float v, int packedLight) { + protected void renderVertex(VertexConsumer buffer, Quaternionf quaternion, float x, float y, float z, float xOffset, float yOffset, float quadSize, float u, float v, int packedLight) { Vector3f vector3f = new Vector3f(xOffset * billboardSize[0], yOffset * billboardSize[1], 0.0F).rotate(quaternion).add(x, y, z); buffer.addVertex(vector3f.x(), vector3f.y(), vector3f.z()).setUv(u, v).setColor(rCol, gCol, bCol, alpha).setLight(packedLight); } - public void moveDirectly(double x, double y, double z) { - setBoundingBox(getBoundingBox().move(x, y, z)); - setLocationFromBoundingbox(); - } - @Override public void move(double x, double y, double z) { if (stoppedByCollision) return; @@ -354,12 +511,12 @@ public void remove() { } @Override - public @NotNull ParticleRenderType getRenderType() { + public ParticleRenderType getRenderType() { return preset.renderType; } @Override - public @NotNull FaceCameraMode getFacingCameraMode() { + public FaceCameraMode getFacingCameraMode() { return preset.facingCameraMode; } @@ -369,7 +526,7 @@ protected int getLightColor(float partialTick) { } @Override - public @NotNull Optional getParticleGroup() { + public Optional getParticleGroup() { return Optional.ofNullable(particleGroup); } @@ -381,7 +538,7 @@ public Provider(ExtendMutableSpriteSet sprites) { } @Override - public TextureSheetParticle createParticle(@NotNull MolangParticleOption option, @NotNull ClientLevel level, double x, double y, double z, double xSpeed, double ySpeed, double zSpeed) { + public TextureSheetParticle createParticle(MolangParticleOption option, ClientLevel level, double x, double y, double z, double xSpeed, double ySpeed, double zSpeed) { return new MolangParticleInstance(PSGameClient.LOADER.id2Particle().get(option.getId()), level, x, y, z, sprites); } } diff --git a/src/main/java/org/mesdag/particlestorm/particle/MolangParticleLoader.java b/src/main/java/org/mesdag/particlestorm/particle/MolangParticleLoader.java index 6b34e20..5238792 100644 --- a/src/main/java/org/mesdag/particlestorm/particle/MolangParticleLoader.java +++ b/src/main/java/org/mesdag/particlestorm/particle/MolangParticleLoader.java @@ -22,7 +22,6 @@ import net.minecraft.util.profiling.ProfilerFiller; import net.minecraft.world.entity.Entity; import net.minecraft.world.level.Level; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.mesdag.particlestorm.ParticleStorm; import org.mesdag.particlestorm.api.IParticleComponent; @@ -179,7 +178,7 @@ public boolean contains(int id) { } @Override - public @NotNull CompletableFuture reload(PreparationBarrier preparationBarrier, @NotNull ResourceManager resourceManager, @NotNull ProfilerFiller preparationsProfiler, @NotNull ProfilerFiller reloadProfiler, @NotNull Executor backgroundExecutor, @NotNull Executor gameExecutor) { + public CompletableFuture reload(PreparationBarrier preparationBarrier, ResourceManager resourceManager, ProfilerFiller preparationsProfiler, ProfilerFiller reloadProfiler, Executor backgroundExecutor, Executor gameExecutor) { return CompletableFuture.supplyAsync(() -> PARTICLE_LISTER.listMatchingResources(resourceManager), backgroundExecutor).thenCompose(map -> { List> list = new ArrayList<>(map.size()); for (Map.Entry entry : map.entrySet()) { diff --git a/src/main/java/org/mesdag/particlestorm/particle/MolangParticleOption.java b/src/main/java/org/mesdag/particlestorm/particle/MolangParticleOption.java index 0100706..d3ac109 100644 --- a/src/main/java/org/mesdag/particlestorm/particle/MolangParticleOption.java +++ b/src/main/java/org/mesdag/particlestorm/particle/MolangParticleOption.java @@ -6,7 +6,6 @@ import net.minecraft.core.particles.ParticleType; import net.minecraft.network.codec.StreamCodec; import net.minecraft.resources.ResourceLocation; -import org.jetbrains.annotations.NotNull; import org.mesdag.particlestorm.ParticleStorm; import java.util.function.Supplier; @@ -31,7 +30,7 @@ public ResourceLocation getId() { } @Override - public @NotNull ParticleType getType() { + public ParticleType getType() { return type.get(); } } diff --git a/src/main/java/org/mesdag/particlestorm/particle/ParticlePreset.java b/src/main/java/org/mesdag/particlestorm/particle/ParticlePreset.java index 521a7e0..e1cd0dd 100644 --- a/src/main/java/org/mesdag/particlestorm/particle/ParticlePreset.java +++ b/src/main/java/org/mesdag/particlestorm/particle/ParticlePreset.java @@ -2,7 +2,6 @@ import com.google.common.collect.Iterables; import net.minecraft.client.particle.ParticleRenderType; -import org.jetbrains.annotations.NotNull; import org.mesdag.particlestorm.PSGameClient; import org.mesdag.particlestorm.api.IComponent; import org.mesdag.particlestorm.api.IParticleComponent; @@ -36,7 +35,7 @@ public class ParticlePreset { public List collisionEvents = List.of(); public final float invTextureWidth; public final float invTextureHeight; - public boolean motionDynamic; + public final boolean motionDynamic; public final VariableTable vars; public final List assignments; @@ -82,6 +81,7 @@ public ParticlePreset(DefinedParticleEffect effect) { List toInit = new ArrayList<>(); for (IParticleComponent component : Iterables.concat(effect.orderedParticleEarlyComponents, effect.orderedParticleComponents)) { + assert component != null; for (MolangExp exp : component.getAllMolangExp()) { exp.compile(parser); MathValue variable = exp.getVariable(); @@ -94,7 +94,7 @@ public ParticlePreset(DefinedParticleEffect effect) { this.assignments = toInit; } - private static @NotNull Hashtable addDefaultVariables() { + private static Hashtable addDefaultVariables() { Hashtable table = new Hashtable<>(); table.computeIfAbsent("variable.particle_age", s -> new Variable(s, MolangInstance::tickAge)); table.computeIfAbsent("variable.particle_lifetime", s -> new Variable(s, MolangInstance::tickLifetime)); diff --git a/src/main/java/org/mesdag/particlestorm/particle/package-info.java b/src/main/java/org/mesdag/particlestorm/particle/package-info.java new file mode 100644 index 0000000..ec468ef --- /dev/null +++ b/src/main/java/org/mesdag/particlestorm/particle/package-info.java @@ -0,0 +1,7 @@ +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +package org.mesdag.particlestorm.particle; + +import net.minecraft.MethodsReturnNonnullByDefault; + +import javax.annotation.ParametersAreNonnullByDefault; From 1762fc9848098061be29f2882ca54bcb9799d5de Mon Sep 17 00:00:00 2001 From: westernat Date: Mon, 24 Nov 2025 14:04:47 +0800 Subject: [PATCH 09/22] unproxy --- gradle.properties | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gradle.properties b/gradle.properties index 5e4ff98..169bce0 100644 --- a/gradle.properties +++ b/gradle.properties @@ -43,7 +43,7 @@ mod_description=Uses a Bedrock Edition JSON format for particle effects. geckolib_version=4.7.5.1 -systemProp.http.proxyHost=localhost -systemProp.http.proxyPort=7890 -systemProp.https.proxyHost=localhost -systemProp.https.proxyPort=7890 +#systemProp.http.proxyHost=localhost +#systemProp.http.proxyPort=7890 +#systemProp.https.proxyHost=localhost +#systemProp.https.proxyPort=7890 From ed935815dcb619200822a87ac22ac9cdcf0057e6 Mon Sep 17 00:00:00 2001 From: westernat Date: Mon, 24 Nov 2025 16:13:28 +0800 Subject: [PATCH 10/22] =?UTF-8?q?=E6=8F=90=E5=8F=96=E5=B9=B2=E5=87=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gradle.properties | 2 +- .../mesdag/particlestorm/PSGameClient.java | 2 +- .../org/mesdag/particlestorm/PSModClient.java | 17 ++++ .../api/IMolangParticleInstance.java | 29 +++---- .../api/RegisterCustomParticleTypeEvent.java | 83 +++++++++++++++++++ .../data/component/EmitterShape.java | 35 ++++---- .../ParticleAppearanceBillboard.java | 2 +- .../component/ParticleLifeTimeEvents.java | 2 +- .../component/ParticleLifetimeExpression.java | 4 +- .../component/ParticleLifetimeKillPlane.java | 2 +- .../component/ParticleMotionCollision.java | 4 +- .../data/component/ParticleMotionDynamic.java | 2 +- .../component/ParticleMotionParametric.java | 2 +- .../data/description/ParticleDescription.java | 12 ++- .../mixin/LivingEntityMixin.java | 5 +- .../mixin/ParticleEngineMixin.java | 10 +-- .../particlestorm/particle/EmitterPreset.java | 10 ++- .../particle/FaceCameraMode.java | 15 ++-- .../particle/MolangParticleInstance.java | 25 ++---- .../particle/MolangParticleLoader.java | 2 +- .../particle/MolangParticleOption.java | 25 +----- .../resources/META-INF/accesstransformer.cfg | 1 - 22 files changed, 179 insertions(+), 112 deletions(-) create mode 100644 src/main/java/org/mesdag/particlestorm/PSModClient.java create mode 100644 src/main/java/org/mesdag/particlestorm/api/RegisterCustomParticleTypeEvent.java diff --git a/gradle.properties b/gradle.properties index 169bce0..a6a8604 100644 --- a/gradle.properties +++ b/gradle.properties @@ -31,7 +31,7 @@ mod_name=ParticleStorm # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=LGPL-3.0 # The mod version. See https://semver.org/ -mod_version=1.2.0 +mod_version=1.2.1 # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. # See https://maven.apache.org/guides/mini/guide-naming-conventions.html diff --git a/src/main/java/org/mesdag/particlestorm/PSGameClient.java b/src/main/java/org/mesdag/particlestorm/PSGameClient.java index 6a62721..56b3988 100644 --- a/src/main/java/org/mesdag/particlestorm/PSGameClient.java +++ b/src/main/java/org/mesdag/particlestorm/PSGameClient.java @@ -99,7 +99,7 @@ private static void renderLevelStage(RenderLevelStageEvent event) { double x = Mth.lerp(partialTicks, emitter.posO.x, emitter.pos.x); double y = Mth.lerp(partialTicks, emitter.posO.y, emitter.pos.y); double z = Mth.lerp(partialTicks, emitter.posO.z, emitter.pos.z); - DebugRenderer.renderFloatingText(poseStack, bufferSource, emitter.getPreset().option.getId().toString(), x, y + 0.5, z, 0xFFFFFF); + DebugRenderer.renderFloatingText(poseStack, bufferSource, emitter.particleId.toString(), x, y + 0.5, z, 0xFFFFFF); DebugRenderer.renderFloatingText(poseStack, bufferSource, "id: " + emitter.id, x, y + 0.3, z, 0xFFFFFF); int maxNum = minecraft.particleEngine.trackedParticleCounts.getInt(emitter.particleGroup); DebugRenderer.renderFloatingText(poseStack, bufferSource, "particles: " + maxNum, x, y + 0.1, z, maxNum >= emitter.particleGroup.getLimit() ? 0xFF0000 : 0xFFFFFF); diff --git a/src/main/java/org/mesdag/particlestorm/PSModClient.java b/src/main/java/org/mesdag/particlestorm/PSModClient.java new file mode 100644 index 0000000..4fc4fc1 --- /dev/null +++ b/src/main/java/org/mesdag/particlestorm/PSModClient.java @@ -0,0 +1,17 @@ +package org.mesdag.particlestorm; + +import net.neoforged.api.distmarker.Dist; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import org.mesdag.particlestorm.api.RegisterCustomParticleTypeEvent; +import org.mesdag.particlestorm.particle.MolangParticleInstance; + +@EventBusSubscriber(modid = ParticleStorm.MODID, bus = EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) +public final class PSModClient { + @SubscribeEvent + public static void registerCustomParticleType(RegisterCustomParticleTypeEvent event) { + event.registerWithSprites(ParticleStorm.MOLANG, (emitter, particlePreset, level, x, y, z, sprites) -> + new MolangParticleInstance(particlePreset, level, x, y, z, sprites) + ); + } +} diff --git a/src/main/java/org/mesdag/particlestorm/api/IMolangParticleInstance.java b/src/main/java/org/mesdag/particlestorm/api/IMolangParticleInstance.java index 32f1cd1..3030ddb 100644 --- a/src/main/java/org/mesdag/particlestorm/api/IMolangParticleInstance.java +++ b/src/main/java/org/mesdag/particlestorm/api/IMolangParticleInstance.java @@ -1,14 +1,23 @@ package org.mesdag.particlestorm.api; +import net.minecraft.client.particle.Particle; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.core.particles.ParticleGroup; -import net.minecraft.world.phys.AABB; import org.joml.Vector3f; +import org.mesdag.particlestorm.particle.ParticleEmitter; import org.mesdag.particlestorm.particle.ParticlePreset; import java.util.List; public interface IMolangParticleInstance extends MolangInstance { + default Particle self() { + return (Particle) this; + } + + int getAge(); + + void setEmitter(ParticleEmitter emitter); + ParticlePreset getPreset(); TextureAtlasSprite getSprite(); @@ -90,22 +99,4 @@ public interface IMolangParticleInstance extends MolangInstance { void setCollision(boolean bool); void moveDirectly(double x, double y, double z); - - // region particle - void setLifetime(int lifetime); - - int getLifetime(); - - int getAge(); - - void remove(); - - void setBoundingBox(AABB box); - - AABB getBoundingBox(); - - void setLocationFromBoundingbox(); - - void setParticleSpeed(double xd, double yd, double zd); - // endregion } diff --git a/src/main/java/org/mesdag/particlestorm/api/RegisterCustomParticleTypeEvent.java b/src/main/java/org/mesdag/particlestorm/api/RegisterCustomParticleTypeEvent.java new file mode 100644 index 0000000..f385c19 --- /dev/null +++ b/src/main/java/org/mesdag/particlestorm/api/RegisterCustomParticleTypeEvent.java @@ -0,0 +1,83 @@ +package org.mesdag.particlestorm.api; + +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.particle.Particle; +import net.minecraft.client.particle.ParticleEngine; +import net.minecraft.core.Holder; +import net.minecraft.core.particles.ParticleType; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.ResourceLocation; +import net.neoforged.bus.api.Event; +import net.neoforged.fml.ModLoader; +import net.neoforged.fml.event.IModBusEvent; +import org.jetbrains.annotations.Contract; +import org.mesdag.particlestorm.PSGameClient; +import org.mesdag.particlestorm.particle.ExtendMutableSpriteSet; +import org.mesdag.particlestorm.particle.ParticleEmitter; +import org.mesdag.particlestorm.particle.ParticlePreset; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +public class RegisterCustomParticleTypeEvent extends Event implements IModBusEvent { + private static Map, Provider> map; + private static ExtendMutableSpriteSet sprites; + private final Map spriteSets; + + private RegisterCustomParticleTypeEvent(Map spriteSets) { + this.spriteSets = spriteSets; + } + + public void register(ParticleType type, Provider provider) { + map.put(type, provider); + } + + public void registerWithSprites(ParticleType type, ProviderWithSprites provider) { + spriteSets.put(Objects.requireNonNull(BuiltInRegistries.PARTICLE_TYPE.getKey(type)), sprites); + register(type, provider); + } + + public void registerWithSprites(Holder> holder, ProviderWithSprites provider) { + spriteSets.put(holder.unwrapKey().orElseThrow().location(), sprites); + register(holder.value(), provider); + } + + public static void postEvent(Map spriteSets) { + map = new HashMap<>(); + sprites = new ExtendMutableSpriteSet(); + ModLoader.postEvent(new RegisterCustomParticleTypeEvent(spriteSets)); + } + + public static V createParticle(ParticleEmitter emitter) { + Provider provider = map.get(emitter.getPreset().type); + if (provider == null) { + throw new NullPointerException("Provider from '" + BuiltInRegistries.PARTICLE_TYPE.getKey(emitter.getPreset().type) + "' is not registered"); + } + + return (V) provider.create(emitter, PSGameClient.LOADER.id2Particle().get(emitter.particleId), (ClientLevel) emitter.level, emitter.getX(), emitter.getY(), emitter.getZ(), sprites); + } + + @FunctionalInterface + public interface Provider { + V create(ParticleEmitter emitter, ParticlePreset particlePreset, ClientLevel level, double x, double y, double z); + + /// @see Provider#create(ParticleEmitter, ParticlePreset, ClientLevel, double, double, double) + @Contract("_, _, _, _, _, _, _ -> fail") + default V create(ParticleEmitter emitter, ParticlePreset particlePreset, ClientLevel level, double x, double y, double z, ExtendMutableSpriteSet sprites) { + throw new UnsupportedOperationException(); + } + } + + @FunctionalInterface + public interface ProviderWithSprites extends Provider { + /// @see ProviderWithSprites#create(ParticleEmitter, ParticlePreset, ClientLevel, double, double, double, ExtendMutableSpriteSet) + @Contract("_, _, _, _, _, _ -> fail") + default V create(ParticleEmitter emitter, ParticlePreset particlePreset, ClientLevel level, double x, double y, double z) { + throw new UnsupportedOperationException(); + } + + @Override + V create(ParticleEmitter emitter, ParticlePreset particlePreset, ClientLevel level, double x, double y, double z, ExtendMutableSpriteSet sprites); + } +} diff --git a/src/main/java/org/mesdag/particlestorm/data/component/EmitterShape.java b/src/main/java/org/mesdag/particlestorm/data/component/EmitterShape.java index aadd0b1..74522eb 100644 --- a/src/main/java/org/mesdag/particlestorm/data/component/EmitterShape.java +++ b/src/main/java/org/mesdag/particlestorm/data/component/EmitterShape.java @@ -4,6 +4,7 @@ import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.client.Minecraft; +import net.minecraft.client.particle.Particle; import net.minecraft.core.particles.ParticleGroup; import net.minecraft.util.Mth; import net.minecraft.util.RandomSource; @@ -12,14 +13,12 @@ import net.minecraft.world.phys.Vec3; import org.joml.Quaternionf; import org.joml.Vector3f; -import org.mesdag.particlestorm.api.IEmitterComponent; -import org.mesdag.particlestorm.api.IParticleComponent; -import org.mesdag.particlestorm.api.MolangInstance; +import org.mesdag.particlestorm.api.*; import org.mesdag.particlestorm.data.MathHelper; import org.mesdag.particlestorm.data.molang.FloatMolangExp; import org.mesdag.particlestorm.data.molang.FloatMolangExp3; import org.mesdag.particlestorm.data.molang.MolangExp; -import org.mesdag.particlestorm.particle.MolangParticleInstance; +import org.mesdag.particlestorm.particle.EmitterPreset; import org.mesdag.particlestorm.particle.ParticleEmitter; import org.mesdag.particlestorm.particle.ParticlePreset; @@ -66,20 +65,17 @@ protected boolean isPoint() { return false; } - private void emittingParticle(ParticleEmitter emitter) { - MolangParticleInstance instance = (MolangParticleInstance) Minecraft.getInstance().particleEngine.makeParticle( - emitter.getPreset().option, emitter.getX(), emitter.getY(), emitter.getZ(), 0.0, 0.0, 0.0 - ); - if (instance == null) throw new NullPointerException("Failed to create particle!"); + private void emittingParticle(ParticleEmitter emitter) { + T instance = RegisterCustomParticleTypeEvent.createParticle(emitter); instance.setEmitter(emitter); - ParticlePreset preset = instance.getPreset(); - MathHelper.redirect(preset.assignments, instance.getVars()); + ParticlePreset particlePreset = instance.getPreset(); + MathHelper.redirect(particlePreset.assignments, instance.getVars()); Vector3f position = new Vector3f(); Vector3f speed = new Vector3f(); initializeParticle(instance, position, speed); - for (IParticleComponent component : preset.effect.orderedParticleEarlyComponents) { + for (IParticleComponent component : particlePreset.effect.orderedParticleEarlyComponents) { component.apply(instance); } speed.mul(instance.getInitialSpeed()); @@ -89,19 +85,20 @@ private void emittingParticle(ParticleEmitter emitter) { speed.x *= -1; speed.y *= -1; } - if (emitter.parentMode != ParticleEmitter.ParentMode.WORLD && emitter.getPreset().localPosition && !emitter.getPreset().localRotation) { + EmitterPreset emitterPreset = emitter.getPreset(); + if (emitter.parentMode != ParticleEmitter.ParentMode.WORLD && emitterPreset.localPosition && !emitterPreset.localRotation) { speed.x *= -1; speed.z *= -1; } - if (emitter.getPreset().localRotation) { + if (emitterPreset.localRotation) { MathHelper.applyEuler(emitter.rot.x, emitter.rot.y, 0.0F, position); } - if (emitter.getPreset().localPosition) { + if (emitterPreset.localPosition) { Vec3 emitterPos = emitter.getPosition(); position.add((float) emitterPos.x, (float) emitterPos.y, (float) emitterPos.z); } speed.mul(emitter.invTickRate); - if (emitter.getAttachedEntity() != null && emitter.getPreset().localVelocity) { + if (emitter.getAttachedEntity() != null && emitterPreset.localVelocity) { Vec3 emitterVec = emitter.getAttachedEntity().getDeltaMovement(); speed.add((float) emitterVec.x, (float) emitterVec.y, (float) emitterVec.z); } @@ -111,11 +108,11 @@ private void emittingParticle(ParticleEmitter emitter) { instance.setPosO(position.x, position.y, position.z); instance.setParticleGroup(emitter.particleGroup); - for (IParticleComponent component : preset.effect.orderedParticleComponents) { + for (IParticleComponent component : particlePreset.effect.orderedParticleComponents) { component.apply(instance); } - instance.setComponents(preset.effect.orderedParticleComponentsWhichRequireUpdate); - if (!preset.motionDynamic) instance.setParticleSpeed(0.0, 0.0, 0.0); + instance.setComponents(particlePreset.effect.orderedParticleComponentsWhichRequireUpdate); + if (!particlePreset.motionDynamic) instance.setParticleSpeed(0.0, 0.0, 0.0); Minecraft.getInstance().particleEngine.add(instance); } diff --git a/src/main/java/org/mesdag/particlestorm/data/component/ParticleAppearanceBillboard.java b/src/main/java/org/mesdag/particlestorm/data/component/ParticleAppearanceBillboard.java index 05c7391..327302d 100644 --- a/src/main/java/org/mesdag/particlestorm/data/component/ParticleAppearanceBillboard.java +++ b/src/main/java/org/mesdag/particlestorm/data/component/ParticleAppearanceBillboard.java @@ -51,7 +51,7 @@ public void update(IMolangParticleInstance instance) { } else if (flipbook.stretchToLifetime) { updateFlipbookUV(instance); instance.setMaxFrame((int) flipbook.maxFrame.calculate(instance)); - instance.setCurrentFrame(instance.getMaxFrame() * instance.getAge() / instance.getLifetime()); + instance.setCurrentFrame(instance.getMaxFrame() * instance.getAge() / instance.self().getLifetime()); } else if (instance.getLevel().getGameTime() % flipbook.framesPerTick < 1.0F) { updateFlipbookUV(instance); instance.setMaxFrame((int) flipbook.maxFrame.calculate(instance)); diff --git a/src/main/java/org/mesdag/particlestorm/data/component/ParticleLifeTimeEvents.java b/src/main/java/org/mesdag/particlestorm/data/component/ParticleLifeTimeEvents.java index 07fcfbb..f440638 100644 --- a/src/main/java/org/mesdag/particlestorm/data/component/ParticleLifeTimeEvents.java +++ b/src/main/java/org/mesdag/particlestorm/data/component/ParticleLifeTimeEvents.java @@ -64,7 +64,7 @@ public List getAllMolangExp() { public void update(IMolangParticleInstance instance) { for (int i = instance.getLastTimeline(); i < sortedTimeline.size(); i++) { Tuple, List> tuple = sortedTimeline.get(i); - if (tuple.getA().apply(instance.getLifetime())) { + if (tuple.getA().apply(instance.self().getLifetime())) { instance.setLastTimeline(i + 1); executes(instance, tuple.getB()); break; diff --git a/src/main/java/org/mesdag/particlestorm/data/component/ParticleLifetimeExpression.java b/src/main/java/org/mesdag/particlestorm/data/component/ParticleLifetimeExpression.java index 019e1ff..ecfa7f7 100644 --- a/src/main/java/org/mesdag/particlestorm/data/component/ParticleLifetimeExpression.java +++ b/src/main/java/org/mesdag/particlestorm/data/component/ParticleLifetimeExpression.java @@ -39,14 +39,14 @@ public List getAllMolangExp() { @Override public void update(IMolangParticleInstance instance) { if (expirationExpression.initialized() && expirationExpression.getVariable().get(instance) != 0.0) { - instance.remove(); + instance.self().remove(); } } @Override public void apply(IMolangParticleInstance instance) { if (maxLifetime.initialized()) { - instance.setLifetime(Math.max((int) (maxLifetime.calculate(instance) * 20), 1)); + instance.self().setLifetime(Math.max((int) (maxLifetime.calculate(instance) * 20), 1)); } } diff --git a/src/main/java/org/mesdag/particlestorm/data/component/ParticleLifetimeKillPlane.java b/src/main/java/org/mesdag/particlestorm/data/component/ParticleLifetimeKillPlane.java index 240f824..0489050 100644 --- a/src/main/java/org/mesdag/particlestorm/data/component/ParticleLifetimeKillPlane.java +++ b/src/main/java/org/mesdag/particlestorm/data/component/ParticleLifetimeKillPlane.java @@ -38,7 +38,7 @@ public ParticleLifetimeKillPlane(float A, float B, float C, float D) { public void update(IMolangParticleInstance instance) { if (instance.getPreset().motionDynamic) return; if (distanceSqr(instance.getX(), instance.getY(), instance.getZ()) > killDistanceSqr == instance.isInsideKillPlane()) { - instance.remove(); + instance.self().remove(); } } diff --git a/src/main/java/org/mesdag/particlestorm/data/component/ParticleMotionCollision.java b/src/main/java/org/mesdag/particlestorm/data/component/ParticleMotionCollision.java index b4e0e9f..3ffcf13 100644 --- a/src/main/java/org/mesdag/particlestorm/data/component/ParticleMotionCollision.java +++ b/src/main/java/org/mesdag/particlestorm/data/component/ParticleMotionCollision.java @@ -69,8 +69,8 @@ public void apply(IMolangParticleInstance instance) { instance.setCollisionDrag(collisionDrag * instance.getInvTickRate()); instance.setCoefficientOfRestitution(coefficientOfRestitution); float radius = Math.max(collisionRadius, Mth.EPSILON); - instance.setBoundingBox(instance.getBoundingBox().inflate(radius, 0.0, radius)); - instance.setLocationFromBoundingbox(); + instance.self().setBoundingBox(instance.self().getBoundingBox().inflate(radius, 0.0, radius)); + instance.self().setLocationFromBoundingbox(); instance.setExpireOnContact(expireOnContact); } diff --git a/src/main/java/org/mesdag/particlestorm/data/component/ParticleMotionDynamic.java b/src/main/java/org/mesdag/particlestorm/data/component/ParticleMotionDynamic.java index ade3bf1..4e5bcff 100644 --- a/src/main/java/org/mesdag/particlestorm/data/component/ParticleMotionDynamic.java +++ b/src/main/java/org/mesdag/particlestorm/data/component/ParticleMotionDynamic.java @@ -76,7 +76,7 @@ public void apply(IMolangParticleInstance instance) { double zd = instance.getZd(); acceleration.add(c * (float) xd * tickRate, c * (float) yd * tickRate, c * (float) zd * tickRate); float v = invTickRate * invTickRate; - instance.setParticleSpeed( + instance.self().setParticleSpeed( xd + acceleration.x * v, yd + acceleration.y * v, zd + acceleration.z * v diff --git a/src/main/java/org/mesdag/particlestorm/data/component/ParticleMotionParametric.java b/src/main/java/org/mesdag/particlestorm/data/component/ParticleMotionParametric.java index f88067d..642c63a 100644 --- a/src/main/java/org/mesdag/particlestorm/data/component/ParticleMotionParametric.java +++ b/src/main/java/org/mesdag/particlestorm/data/component/ParticleMotionParametric.java @@ -51,7 +51,7 @@ public void update(IMolangParticleInstance instance) { instance.moveDirectly(pos[0], pos[1], pos[2]); if (direction != FloatMolangExp3.ZERO) { float[] dir = direction.calculate(instance); - instance.setParticleSpeed(dir[0], dir[1], dir[2]); + instance.self().setParticleSpeed(dir[0], dir[1], dir[2]); } instance.setZRot(rotation.calculate(instance)); } diff --git a/src/main/java/org/mesdag/particlestorm/data/description/ParticleDescription.java b/src/main/java/org/mesdag/particlestorm/data/description/ParticleDescription.java index f32e948..bc2df0b 100644 --- a/src/main/java/org/mesdag/particlestorm/data/description/ParticleDescription.java +++ b/src/main/java/org/mesdag/particlestorm/data/description/ParticleDescription.java @@ -2,11 +2,19 @@ import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.minecraft.core.particles.ParticleType; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.resources.ResourceLocation; +import org.mesdag.particlestorm.ParticleStorm; -public record ParticleDescription(ResourceLocation identifier, DescriptionParameters parameters) { +public record ParticleDescription(ResourceLocation identifier, DescriptionParameters parameters, ParticleType type) { public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( ResourceLocation.CODEC.fieldOf("identifier").forGetter(ParticleDescription::identifier), - DescriptionParameters.CODEC.fieldOf("basic_render_parameters").forGetter(ParticleDescription::parameters) + DescriptionParameters.CODEC.fieldOf("basic_render_parameters").forGetter(ParticleDescription::parameters), + BuiltInRegistries.PARTICLE_TYPE.byNameCodec().fieldOf("type").orElseGet(ParticleStorm.MOLANG).forGetter(ParticleDescription::type) ).apply(instance, ParticleDescription::new)); + + public ParticleDescription(ResourceLocation identifier, DescriptionParameters parameters) { + this(identifier, parameters, ParticleStorm.MOLANG.get()); + } } diff --git a/src/main/java/org/mesdag/particlestorm/mixin/LivingEntityMixin.java b/src/main/java/org/mesdag/particlestorm/mixin/LivingEntityMixin.java index fa4f6c4..919916b 100644 --- a/src/main/java/org/mesdag/particlestorm/mixin/LivingEntityMixin.java +++ b/src/main/java/org/mesdag/particlestorm/mixin/LivingEntityMixin.java @@ -2,6 +2,7 @@ import com.llamalad7.mixinextras.injector.v2.WrapWithCondition; import net.minecraft.core.particles.ParticleOptions; +import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.level.Level; import org.mesdag.particlestorm.PSGameClient; @@ -13,8 +14,8 @@ public abstract class LivingEntityMixin { @WrapWithCondition(method = "tickEffects", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;addParticle(Lnet/minecraft/core/particles/ParticleOptions;DDDDDD)V")) private boolean modify(Level instance, ParticleOptions particleData, double x, double y, double z, double xSpeed, double ySpeed, double zSpeed) { - if (particleData instanceof MolangParticleOption molang) { - PSGameClient.LOADER.addTrackedEmitter((LivingEntity) (Object) this, molang.getId()); + if (particleData instanceof MolangParticleOption(ResourceLocation id)) { + PSGameClient.LOADER.addTrackedEmitter((LivingEntity) (Object) this, id); return false; } return true; diff --git a/src/main/java/org/mesdag/particlestorm/mixin/ParticleEngineMixin.java b/src/main/java/org/mesdag/particlestorm/mixin/ParticleEngineMixin.java index 0c23b2a..c026ba8 100644 --- a/src/main/java/org/mesdag/particlestorm/mixin/ParticleEngineMixin.java +++ b/src/main/java/org/mesdag/particlestorm/mixin/ParticleEngineMixin.java @@ -1,16 +1,15 @@ package org.mesdag.particlestorm.mixin; import net.minecraft.client.particle.ParticleEngine; -import net.minecraft.client.particle.ParticleProvider; import net.minecraft.client.renderer.texture.SpriteLoader; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.resources.ResourceLocation; import org.mesdag.particlestorm.PSGameClient; import org.mesdag.particlestorm.ParticleStorm; +import org.mesdag.particlestorm.api.RegisterCustomParticleTypeEvent; import org.mesdag.particlestorm.data.DefinedParticleEffect; import org.mesdag.particlestorm.mixed.IParticleEngine; import org.mesdag.particlestorm.particle.ExtendMutableSpriteSet; -import org.mesdag.particlestorm.particle.MolangParticleInstance; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -27,9 +26,6 @@ public abstract class ParticleEngineMixin implements IParticleEngine { @Shadow @Final private Map spriteSets; - @Shadow - @Final - private Map> providers; @Unique private volatile SpriteLoader.Preparations particlestorm$preparations; @@ -53,9 +49,7 @@ public abstract class ParticleEngineMixin implements IParticleEngine { @Inject(method = "registerProviders", at = @At("TAIL")) private void registerCustom(CallbackInfo ci) { - ExtendMutableSpriteSet extendMutableSpriteSet = new ExtendMutableSpriteSet(); - spriteSets.put(ParticleStorm.MOLANG.getId(), extendMutableSpriteSet); - providers.put(ParticleStorm.MOLANG.getId(), new MolangParticleInstance.Provider(extendMutableSpriteSet)); + RegisterCustomParticleTypeEvent.postEvent(spriteSets); } @ModifyArg(method = "lambda$reload$9", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/texture/TextureAtlas;upload(Lnet/minecraft/client/renderer/texture/SpriteLoader$Preparations;)V")) diff --git a/src/main/java/org/mesdag/particlestorm/particle/EmitterPreset.java b/src/main/java/org/mesdag/particlestorm/particle/EmitterPreset.java index a940f8c..62cbaf4 100644 --- a/src/main/java/org/mesdag/particlestorm/particle/EmitterPreset.java +++ b/src/main/java/org/mesdag/particlestorm/particle/EmitterPreset.java @@ -1,5 +1,6 @@ package org.mesdag.particlestorm.particle; +import net.minecraft.core.particles.ParticleType; import org.mesdag.particlestorm.api.IEmitterComponent; import org.mesdag.particlestorm.api.IEventNode; import org.mesdag.particlestorm.data.MathHelper; @@ -17,7 +18,7 @@ import java.util.Map; public class EmitterPreset { - public final MolangParticleOption option; + public final ParticleType type; public final List components; public final Map> events; public final VariableTable vars; @@ -28,8 +29,13 @@ public class EmitterPreset { public boolean localVelocity = false; public EmitterLifetimeEvents lifetimeEvents; + @Deprecated public EmitterPreset(MolangParticleOption option, List components, Map> events) { - this.option = option; + this(option.getType(), components, events); + } + + public EmitterPreset(ParticleType type, List components, Map> events) { + this.type = type; this.components = components; this.events = events; VariableTable table = new VariableTable(addDefaultVariables(), null); diff --git a/src/main/java/org/mesdag/particlestorm/particle/FaceCameraMode.java b/src/main/java/org/mesdag/particlestorm/particle/FaceCameraMode.java index 87063e5..8c679a2 100644 --- a/src/main/java/org/mesdag/particlestorm/particle/FaceCameraMode.java +++ b/src/main/java/org/mesdag/particlestorm/particle/FaceCameraMode.java @@ -7,6 +7,7 @@ import org.joml.Matrix4f; import org.joml.Quaternionf; import org.joml.Vector3f; +import org.mesdag.particlestorm.api.IMolangParticleInstance; import org.mesdag.particlestorm.data.MathHelper; import javax.annotation.ParametersAreNonnullByDefault; @@ -22,7 +23,7 @@ public enum FaceCameraMode implements SingleQuadParticle.FacingCameraMode { public void setRotation(Quaternionf quaternion, Camera camera, float partialTick) {} @Override - public void setRotation(MolangParticleInstance instance, Quaternionf quaternion, Camera camera, float partialTick) { + public void setRotation(IMolangParticleInstance instance, Quaternionf quaternion, Camera camera, float partialTick) { Vector3f xd = camera.getPosition().toVector3f().sub( (float) instance.getX(), (float) instance.getY(), @@ -43,7 +44,7 @@ public void setRotation(MolangParticleInstance instance, Quaternionf quaternion, public void setRotation(Quaternionf quaternion, Camera camera, float partialTick) {} @Override - public void setRotation(MolangParticleInstance instance, Quaternionf quaternion, Camera camera, float partialTick) { + public void setRotation(IMolangParticleInstance instance, Quaternionf quaternion, Camera camera, float partialTick) { LOOKAT_XYZ.setRotation(instance, quaternion, camera, partialTick); quaternion.x = 0.0F; quaternion.z = 0.0F; @@ -86,12 +87,12 @@ public void setRotation(Quaternionf quaternion, Camera camera, float partialTick public void setRotation(Quaternionf quaternion, Camera camera, float partialTick) {} @Override - public void setRotation(MolangParticleInstance instance, Quaternionf quaternion, Camera camera, float partialTick) { - MathHelper.setFromUnitVectors(X, instance.facingDirection, quaternion); - instance.xRot = Math.atan2( + public void setRotation(IMolangParticleInstance instance, Quaternionf quaternion, Camera camera, float partialTick) { + MathHelper.setFromUnitVectors(X, instance.getFacingDirection(), quaternion); + instance.setXRot(Math.atan2( (float) (instance.getX() - camera.getPosition().y), (float) (camera.getPosition().z - instance.getZ()) - ); + )); } }, EMITTER_TRANSFORM_XY { @@ -113,7 +114,7 @@ public void setRotation(Quaternionf quaternion, Camera camera, float partialTick } }; - public void setRotation(MolangParticleInstance instance, Quaternionf quaternion, Camera camera, float partialTick) { + public void setRotation(IMolangParticleInstance instance, Quaternionf quaternion, Camera camera, float partialTick) { setRotation(quaternion, camera, partialTick); } } diff --git a/src/main/java/org/mesdag/particlestorm/particle/MolangParticleInstance.java b/src/main/java/org/mesdag/particlestorm/particle/MolangParticleInstance.java index 928928e..cddaa3e 100644 --- a/src/main/java/org/mesdag/particlestorm/particle/MolangParticleInstance.java +++ b/src/main/java/org/mesdag/particlestorm/particle/MolangParticleInstance.java @@ -3,7 +3,6 @@ import com.mojang.blaze3d.vertex.VertexConsumer; import net.minecraft.client.Camera; import net.minecraft.client.multiplayer.ClientLevel; -import net.minecraft.client.particle.ParticleProvider; import net.minecraft.client.particle.ParticleRenderType; import net.minecraft.client.particle.TextureSheetParticle; import net.minecraft.client.renderer.texture.TextureAtlasSprite; @@ -18,7 +17,6 @@ import org.jetbrains.annotations.Nullable; import org.joml.Quaternionf; import org.joml.Vector3f; -import org.mesdag.particlestorm.PSGameClient; import org.mesdag.particlestorm.api.IEventNode; import org.mesdag.particlestorm.api.IMolangParticleInstance; import org.mesdag.particlestorm.api.IParticleComponent; @@ -88,6 +86,12 @@ public MolangParticleInstance(ParticlePreset preset, ClientLevel level, double x this.particleRandom4 = random.nextDouble(); } + @Override + public int getAge() { + return age; + } + + @Override public void setEmitter(ParticleEmitter emitter) { this.emitter = emitter; this.vars = new ParticleVariableTable(preset.vars, emitter.vars); @@ -401,10 +405,6 @@ protected float getV1() { return UV == null ? super.getV1() : UV[3]; } - public int getAge() { - return age; - } - @Override public void tick() { super.tick(); @@ -529,17 +529,4 @@ protected int getLightColor(float partialTick) { public Optional getParticleGroup() { return Optional.ofNullable(particleGroup); } - - public static class Provider implements ParticleProvider { - private final ExtendMutableSpriteSet sprites; - - public Provider(ExtendMutableSpriteSet sprites) { - this.sprites = sprites; - } - - @Override - public TextureSheetParticle createParticle(MolangParticleOption option, ClientLevel level, double x, double y, double z, double xSpeed, double ySpeed, double zSpeed) { - return new MolangParticleInstance(PSGameClient.LOADER.id2Particle().get(option.getId()), level, x, y, z, sprites); - } - } } diff --git a/src/main/java/org/mesdag/particlestorm/particle/MolangParticleLoader.java b/src/main/java/org/mesdag/particlestorm/particle/MolangParticleLoader.java index 5238792..23b78e3 100644 --- a/src/main/java/org/mesdag/particlestorm/particle/MolangParticleLoader.java +++ b/src/main/java/org/mesdag/particlestorm/particle/MolangParticleLoader.java @@ -201,7 +201,7 @@ public CompletableFuture reload(PreparationBarrier preparationBarrier, Res id2Effect.put(id, effect); id2Particle.put(id, new ParticlePreset(effect)); id2Emitter.put(id, new EmitterPreset( - new MolangParticleOption(effect.description.identifier()), + effect.description.type(), effect.orderedEmitterComponents, effect.events )); diff --git a/src/main/java/org/mesdag/particlestorm/particle/MolangParticleOption.java b/src/main/java/org/mesdag/particlestorm/particle/MolangParticleOption.java index d3ac109..b48338c 100644 --- a/src/main/java/org/mesdag/particlestorm/particle/MolangParticleOption.java +++ b/src/main/java/org/mesdag/particlestorm/particle/MolangParticleOption.java @@ -8,29 +8,12 @@ import net.minecraft.resources.ResourceLocation; import org.mesdag.particlestorm.ParticleStorm; -import java.util.function.Supplier; - -public class MolangParticleOption implements ParticleOptions { - public static final MapCodec CODEC = ResourceLocation.CODEC.fieldOf("id").xmap(MolangParticleOption::new, MolangParticleOption::getId); - public static final StreamCodec STREAM_CODEC = ResourceLocation.STREAM_CODEC.map(MolangParticleOption::new, MolangParticleOption::getId); - private final Supplier> type; - private final ResourceLocation id; - - private MolangParticleOption(Supplier> type, ResourceLocation id) { - this.type = type; - this.id = id; - } - - public MolangParticleOption(ResourceLocation id) { - this(ParticleStorm.MOLANG, id); - } - - public ResourceLocation getId() { - return id; - } +public record MolangParticleOption(ResourceLocation id) implements ParticleOptions { + public static final MapCodec CODEC = ResourceLocation.CODEC.fieldOf("id").xmap(MolangParticleOption::new, MolangParticleOption::id); + public static final StreamCodec STREAM_CODEC = ResourceLocation.STREAM_CODEC.map(MolangParticleOption::new, MolangParticleOption::id); @Override public ParticleType getType() { - return type.get(); + return ParticleStorm.MOLANG.get(); } } diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg index 1425b8b..309cfa6 100644 --- a/src/main/resources/META-INF/accesstransformer.cfg +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -6,4 +6,3 @@ public net.minecraft.client.particle.ParticleEngine$MutableSpriteSet protected net.minecraft.client.particle.ParticleEngine$MutableSpriteSet sprites protected net.minecraft.client.particle.ParticleEngine$MutableSpriteSet ()V public net.minecraft.client.particle.ParticleEngine trackedParticleCounts -public net.minecraft.client.particle.ParticleEngine makeParticle(Lnet/minecraft/core/particles/ParticleOptions;DDDDDD)Lnet/minecraft/client/particle/Particle; From b8c76b1e690024cb244912cb17c756545e13e61d Mon Sep 17 00:00:00 2001 From: westernat Date: Mon, 24 Nov 2025 16:39:14 +0800 Subject: [PATCH 11/22] =?UTF-8?q?=E5=B0=8F=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gradle.properties | 2 +- .../particlestorm/api/IMolangParticleInstance.java | 3 ++- .../data/component/ParticleAppearanceBillboard.java | 13 +++++++++---- .../particle/MolangParticleInstance.java | 2 +- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/gradle.properties b/gradle.properties index a6a8604..dd1a7bc 100644 --- a/gradle.properties +++ b/gradle.properties @@ -31,7 +31,7 @@ mod_name=ParticleStorm # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=LGPL-3.0 # The mod version. See https://semver.org/ -mod_version=1.2.1 +mod_version=1.2.2 # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. # See https://maven.apache.org/guides/mini/guide-naming-conventions.html diff --git a/src/main/java/org/mesdag/particlestorm/api/IMolangParticleInstance.java b/src/main/java/org/mesdag/particlestorm/api/IMolangParticleInstance.java index 3030ddb..3bfffcb 100644 --- a/src/main/java/org/mesdag/particlestorm/api/IMolangParticleInstance.java +++ b/src/main/java/org/mesdag/particlestorm/api/IMolangParticleInstance.java @@ -3,6 +3,7 @@ import net.minecraft.client.particle.Particle; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.core.particles.ParticleGroup; +import org.jetbrains.annotations.Nullable; import org.joml.Vector3f; import org.mesdag.particlestorm.particle.ParticleEmitter; import org.mesdag.particlestorm.particle.ParticlePreset; @@ -20,7 +21,7 @@ default Particle self() { ParticlePreset getPreset(); - TextureAtlasSprite getSprite(); + @Nullable TextureAtlasSprite getSprite(); Vector3f getAcceleration(); diff --git a/src/main/java/org/mesdag/particlestorm/data/component/ParticleAppearanceBillboard.java b/src/main/java/org/mesdag/particlestorm/data/component/ParticleAppearanceBillboard.java index 327302d..ca25374 100644 --- a/src/main/java/org/mesdag/particlestorm/data/component/ParticleAppearanceBillboard.java +++ b/src/main/java/org/mesdag/particlestorm/data/component/ParticleAppearanceBillboard.java @@ -2,6 +2,7 @@ import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.resources.ResourceLocation; import net.minecraft.util.ExtraCodecs; import net.minecraft.util.Mth; @@ -113,19 +114,23 @@ public boolean requireUpdate() { } private void updateSimpleUV(IMolangParticleInstance instance) { + TextureAtlasSprite sprite = instance.getSprite(); + if (sprite == null) return; float[] base = uv.uv.calculate(instance); float[] size = uv.uvSize.calculate(instance); - int x = instance.getSprite().getX(); - int y = instance.getSprite().getY(); + int x = sprite.getX(); + int y = sprite.getY(); instance.setUV(x + base[0], y + base[1], size[0] * instance.getScaleU(), size[1] * instance.getScaleV()); } private void updateFlipbookUV(IMolangParticleInstance instance) { + TextureAtlasSprite sprite = instance.getSprite(); + if (sprite == null) return; float[] base = uv.flipbook.baseUV.calculate(instance); float u = instance.getUvStep()[0] * instance.getCurrentFrame(); float v = instance.getUvStep()[1] * instance.getCurrentFrame(); - int x = instance.getSprite().getX(); - int y = instance.getSprite().getY(); + int x = sprite.getX(); + int y = sprite.getY(); instance.setUV(x + base[0] + u, y + base[1] + v, instance.getUvSize()[0], instance.getUvSize()[1]); } diff --git a/src/main/java/org/mesdag/particlestorm/particle/MolangParticleInstance.java b/src/main/java/org/mesdag/particlestorm/particle/MolangParticleInstance.java index cddaa3e..9e00e54 100644 --- a/src/main/java/org/mesdag/particlestorm/particle/MolangParticleInstance.java +++ b/src/main/java/org/mesdag/particlestorm/particle/MolangParticleInstance.java @@ -362,7 +362,7 @@ public double getRandom4() { @Override public ResourceLocation getIdentity() { - return preset.effect.description.identifier(); + return emitter.particleId; } @Override From a3b69dbc136e329fc173757c4ccea8116165953b Mon Sep 17 00:00:00 2001 From: westernat Date: Mon, 24 Nov 2025 22:06:47 +0800 Subject: [PATCH 12/22] =?UTF-8?q?=E5=AE=8C=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gradle.properties | 2 +- .../mesdag/particlestorm/ParticleStorm.java | 30 ++++--- .../api/IMolangParticleInstance.java | 40 ++++++++- .../api/ParticlePresetLoadedEvent.java | 16 ++++ .../ParticleAppearanceBillboard.java | 88 +++++++++---------- .../data/molang/FloatMolangExp2.java | 1 + .../particle/FaceCameraMode.java | 3 - .../particle/MolangParticleInstance.java | 47 ++-------- .../particle/ParticlePreset.java | 42 ++++++--- 9 files changed, 152 insertions(+), 117 deletions(-) create mode 100644 src/main/java/org/mesdag/particlestorm/api/ParticlePresetLoadedEvent.java diff --git a/gradle.properties b/gradle.properties index dd1a7bc..bf0c42f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -31,7 +31,7 @@ mod_name=ParticleStorm # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=LGPL-3.0 # The mod version. See https://semver.org/ -mod_version=1.2.2 +mod_version=1.2.4 # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. # See https://maven.apache.org/guides/mini/guide-naming-conventions.html diff --git a/src/main/java/org/mesdag/particlestorm/ParticleStorm.java b/src/main/java/org/mesdag/particlestorm/ParticleStorm.java index b62b111..3ff3fe7 100644 --- a/src/main/java/org/mesdag/particlestorm/ParticleStorm.java +++ b/src/main/java/org/mesdag/particlestorm/ParticleStorm.java @@ -45,18 +45,8 @@ public final class ParticleStorm { public static final Logger LOGGER = LoggerFactory.getLogger("ParticleStorm"); public static final boolean DEBUG = Boolean.getBoolean("particlestorm.debug"); - public static final DeferredRegister> PARTICLE = DeferredRegister.create(BuiltInRegistries.PARTICLE_TYPE, MODID); - public static final DeferredHolder, ParticleType> MOLANG = PARTICLE.register("molang", () -> new ParticleType<>(false) { - @Override - public MapCodec codec() { - return MolangParticleOption.CODEC; - } - - @Override - public StreamCodec streamCodec() { - return MolangParticleOption.STREAM_CODEC; - } - }); + private static final DeferredRegister> REGISTER = DeferredRegister.create(BuiltInRegistries.PARTICLE_TYPE, MODID); + public static final DeferredHolder, ParticleType> MOLANG = registerParticleType(REGISTER, "molang"); public static final Codec> STRING_LIST_CODEC = Codec.either(Codec.STRING, Codec.STRING.listOf()).xmap( either -> either.map(Collections::singletonList, Function.identity()), l -> l.size() == 1 ? Either.left(l.getFirst()) : Either.right(l) @@ -65,7 +55,7 @@ public StreamCodec streamCodec() { public ParticleStorm(IEventBus bus, ModContainer container) { PSClientConfigs.register(container); - PARTICLE.register(bus); + REGISTER.register(bus); registerGeoTest(bus); bus.addListener(ParticleStorm::registerPayloadHandlers); NeoForge.EVENT_BUS.addListener(ParticleStorm::registerCommands); @@ -110,4 +100,18 @@ private static void registerGeoTest(IEventBus bus) { public static ResourceLocation asResource(String path) { return ResourceLocation.fromNamespaceAndPath(MODID, path); } + + public static DeferredHolder, ParticleType> registerParticleType(DeferredRegister> register, String name) { + return register.register(name, () -> new ParticleType<>(false) { + @Override + public MapCodec codec() { + return MolangParticleOption.CODEC; + } + + @Override + public StreamCodec streamCodec() { + return MolangParticleOption.STREAM_CODEC; + } + }); + } } diff --git a/src/main/java/org/mesdag/particlestorm/api/IMolangParticleInstance.java b/src/main/java/org/mesdag/particlestorm/api/IMolangParticleInstance.java index 3bfffcb..01cc805 100644 --- a/src/main/java/org/mesdag/particlestorm/api/IMolangParticleInstance.java +++ b/src/main/java/org/mesdag/particlestorm/api/IMolangParticleInstance.java @@ -3,6 +3,9 @@ import net.minecraft.client.particle.Particle; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.core.particles.ParticleGroup; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.phys.Vec3; import org.jetbrains.annotations.Nullable; import org.joml.Vector3f; import org.mesdag.particlestorm.particle.ParticleEmitter; @@ -99,5 +102,40 @@ default Particle self() { void setCollision(boolean bool); - void moveDirectly(double x, double y, double z); + // region default + default void moveDirectly(double x, double y, double z) { + self().setBoundingBox(self().getBoundingBox().move(x, y, z)); + self().setLocationFromBoundingbox(); + } + + @Override + default float tickAge() { + return getAge() * getInvTickRate(); + } + + @Override + default float tickLifetime() { + return self().getLifetime() * getInvTickRate(); + } + + @Override + default ResourceLocation getIdentity() { + return getEmitter().particleId; + } + + @Override + default Vec3 getPosition() { + return self().getPos(); + } + + @Override + default @Nullable Entity getAttachedEntity() { + return getEmitter().getAttachedEntity(); + } + + @Override + default float getInvTickRate() { + return getEmitter().invTickRate; + } + // endregion } diff --git a/src/main/java/org/mesdag/particlestorm/api/ParticlePresetLoadedEvent.java b/src/main/java/org/mesdag/particlestorm/api/ParticlePresetLoadedEvent.java new file mode 100644 index 0000000..a889155 --- /dev/null +++ b/src/main/java/org/mesdag/particlestorm/api/ParticlePresetLoadedEvent.java @@ -0,0 +1,16 @@ +package org.mesdag.particlestorm.api; + +import net.neoforged.bus.api.Event; +import org.mesdag.particlestorm.particle.ParticlePreset; + +public class ParticlePresetLoadedEvent extends Event { + private final ParticlePreset preset; + + public ParticlePresetLoadedEvent(ParticlePreset preset) { + this.preset = preset; + } + + public ParticlePreset getPreset() { + return preset; + } +} diff --git a/src/main/java/org/mesdag/particlestorm/data/component/ParticleAppearanceBillboard.java b/src/main/java/org/mesdag/particlestorm/data/component/ParticleAppearanceBillboard.java index ca25374..10375e9 100644 --- a/src/main/java/org/mesdag/particlestorm/data/component/ParticleAppearanceBillboard.java +++ b/src/main/java/org/mesdag/particlestorm/data/component/ParticleAppearanceBillboard.java @@ -23,7 +23,7 @@ public record ParticleAppearanceBillboard(FloatMolangExp2 size, FaceCameraMode f public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( FloatMolangExp2.CODEC.fieldOf("size").forGetter(ParticleAppearanceBillboard::size), DuplicateFieldDecoder.fieldOf("face_camera_mode", "facing_camera_mode", FaceCameraMode.CODEC).forGetter(ParticleAppearanceBillboard::faceCameraMode), - Direction.CODEC.fieldOf("direction").orElseGet(() -> new Direction(Direction.Mode.DERIVE_FROM_VELOCITY, 0.01F, FloatMolangExp3.ZERO)).forGetter(ParticleAppearanceBillboard::direction), + Direction.CODEC.lenientOptionalFieldOf("direction", Direction.DEFAULT).forGetter(ParticleAppearanceBillboard::direction), UV.CODEC.fieldOf("uv").orElse(UV.EMPTY).forGetter(ParticleAppearanceBillboard::uv) ).apply(instance, ParticleAppearanceBillboard::new)); @@ -35,9 +35,14 @@ public Codec codec() { @Override public List getAllMolangExp() { return List.of( - size.exp1(), size.exp2(), direction.customDirection.exp1(), direction.customDirection.exp2(), direction.customDirection.exp3(), - uv.uv.exp1(), uv.uv.exp2(), uv.uvSize.exp1(), uv.uvSize.exp2(), uv.flipbook.baseUV.exp1(), uv.flipbook.baseUV.exp2(), - uv.flipbook.sizeUV.exp1(), uv.flipbook.sizeUV.exp2(), uv.flipbook.stepUV.exp1(), uv.flipbook.stepUV.exp2(), uv.flipbook.maxFrame + size.exp1(), size.exp2(), + direction.customDirection.exp1(), direction.customDirection.exp2(), direction.customDirection.exp3(), + uv.uv.exp1(), uv.uv.exp2(), + uv.uvSize.exp1(), uv.uvSize.exp2(), + uv.flipbook.baseUV.exp1(), uv.flipbook.baseUV.exp2(), + uv.flipbook.sizeUV.exp1(), uv.flipbook.sizeUV.exp2(), + uv.flipbook.stepUV.exp1(), uv.flipbook.stepUV.exp2(), + uv.flipbook.maxFrame ); } @@ -45,25 +50,24 @@ public List getAllMolangExp() { public void update(IMolangParticleInstance instance) { doFacingCameraMode(instance); doSize(instance); - if (uv != UV.EMPTY) { - UV.Flipbook flipbook = uv.flipbook; - if (flipbook == UV.Flipbook.EMPTY) { - updateSimpleUV(instance); - } else if (flipbook.stretchToLifetime) { - updateFlipbookUV(instance); - instance.setMaxFrame((int) flipbook.maxFrame.calculate(instance)); - instance.setCurrentFrame(instance.getMaxFrame() * instance.getAge() / instance.self().getLifetime()); - } else if (instance.getLevel().getGameTime() % flipbook.framesPerTick < 1.0F) { - updateFlipbookUV(instance); - instance.setMaxFrame((int) flipbook.maxFrame.calculate(instance)); - if (instance.getCurrentFrame() < instance.getMaxFrame()) { - instance.setCurrentFrame(instance.getCurrentFrame() + 1); - if (flipbook.loop && instance.getCurrentFrame() == instance.getMaxFrame()) { - instance.setCurrentFrame(0); - } - } else { - instance.setCurrentFrame(instance.getMaxFrame() - 1); + if (uv == UV.EMPTY) return; + UV.Flipbook flipbook = uv.flipbook; + if (flipbook == UV.Flipbook.EMPTY) { + updateSimpleUV(instance); + } else if (flipbook.stretchToLifetime) { + updateFlipbookUV(instance); + instance.setMaxFrame((int) flipbook.maxFrame.calculate(instance)); + instance.setCurrentFrame(instance.getMaxFrame() * instance.getAge() / instance.self().getLifetime()); + } else if (instance.getLevel().getGameTime() % flipbook.framesPerTick < 1.0F) { + updateFlipbookUV(instance); + instance.setMaxFrame((int) flipbook.maxFrame.calculate(instance)); + if (instance.getCurrentFrame() < instance.getMaxFrame()) { + instance.setCurrentFrame(instance.getCurrentFrame() + 1); + if (flipbook.loop && instance.getCurrentFrame() == instance.getMaxFrame()) { + instance.setCurrentFrame(0); } + } else { + instance.setCurrentFrame(instance.getMaxFrame() - 1); } } } @@ -72,18 +76,17 @@ public void update(IMolangParticleInstance instance) { public void apply(IMolangParticleInstance instance) { doFacingCameraMode(instance); doSize(instance); - if (uv != UV.EMPTY) { - if (uv.flipbook == UV.Flipbook.EMPTY) { - updateSimpleUV(instance); - } else { - instance.setUvSize(uv.flipbook.getSizeUV(instance)); - instance.getUvSize()[0] *= instance.getScaleU(); - instance.getUvSize()[1] *= instance.getScaleV(); - instance.setUvStep(uv.flipbook.getStepUV(instance)); - instance.getUvStep()[0] *= instance.getScaleU(); - instance.getUvStep()[1] *= instance.getScaleV(); - updateFlipbookUV(instance); - } + if (uv == UV.EMPTY) return; + if (uv.flipbook == UV.Flipbook.EMPTY) { + updateSimpleUV(instance); + } else { + instance.setUvSize(uv.flipbook.getSizeUV(instance)); + instance.getUvSize()[0] *= instance.getScaleU(); + instance.getUvSize()[1] *= instance.getScaleV(); + instance.setUvStep(uv.flipbook.getStepUV(instance)); + instance.getUvStep()[0] *= instance.getScaleU(); + instance.getUvStep()[1] *= instance.getScaleV(); + updateFlipbookUV(instance); } } @@ -94,18 +97,14 @@ private void doFacingCameraMode(IMolangParticleInstance instance) { instance.setXRot(values[0]); instance.setYRot(values[1]); instance.setZRot(values[2]); - } else { - if (direction.minSpeedThreshold > 0.0F && Mth.lengthSquared(instance.getXd(), instance.getYd(), instance.getZd()) > instance.getPreset().minSpeedThresholdSqr) { - instance.getFacingDirection().set(instance.getXd(), instance.getYd(), instance.getZd()).normalize(); - } + } else if (direction.minSpeedThreshold > 0.0F && Mth.lengthSquared(instance.getXd(), instance.getYd(), instance.getZd()) > instance.getPreset().minSpeedThresholdSqr) { + instance.getFacingDirection().set(instance.getXd(), instance.getYd(), instance.getZd()).normalize(); } } } private void doSize(IMolangParticleInstance instance) { - if (size.initialized()) { - instance.setBillboardSize(size.calculate(instance)); - } + instance.setBillboardSize(size.calculate(instance)); } @Override @@ -175,6 +174,7 @@ public String toString() { } public record Direction(Mode mode, float minSpeedThreshold, FloatMolangExp3 customDirection) { + public static final Direction DEFAULT = new Direction(Direction.Mode.DERIVE_FROM_VELOCITY, 0.01F, FloatMolangExp3.ZERO); public static final Codec CODEC = Mode.CODEC.dispatchMap( Direction::mode, mode -> mode == Mode.CUSTOM_DIRECTION ? RecordCodecBuilder.mapCodec(instance -> instance.group( @@ -269,7 +269,7 @@ public static class Flipbook { private final boolean stretchToLifetime; private final boolean loop; - private float framesPerTick = 1.0F; + private final float framesPerTick; /** * @param baseUV Upper-left corner of starting UV patch @@ -289,9 +289,7 @@ public Flipbook(FloatMolangExp2 baseUV, FloatMolangExp2 sizeUV, FloatMolangExp2 this.stretchToLifetime = stretchToLifetime; this.loop = loop; - if (framesPerSecond != 0.0F) { - this.framesPerTick = 20.0F / framesPerSecond; - } + this.framesPerTick = framesPerSecond == 0.0F ? 1.0F : 20.0F / framesPerSecond; } public float[] getSizeUV(IMolangParticleInstance instance) { diff --git a/src/main/java/org/mesdag/particlestorm/data/molang/FloatMolangExp2.java b/src/main/java/org/mesdag/particlestorm/data/molang/FloatMolangExp2.java index ea02f35..6c3a3ec 100644 --- a/src/main/java/org/mesdag/particlestorm/data/molang/FloatMolangExp2.java +++ b/src/main/java/org/mesdag/particlestorm/data/molang/FloatMolangExp2.java @@ -16,6 +16,7 @@ public float[] calculate(MolangInstance instance) { return new float[]{exp1.calculate(instance), exp2.calculate(instance)}; } + @Deprecated public boolean initialized() { return exp1.initialized() && exp2.initialized(); } diff --git a/src/main/java/org/mesdag/particlestorm/particle/FaceCameraMode.java b/src/main/java/org/mesdag/particlestorm/particle/FaceCameraMode.java index 8c679a2..55cb4ca 100644 --- a/src/main/java/org/mesdag/particlestorm/particle/FaceCameraMode.java +++ b/src/main/java/org/mesdag/particlestorm/particle/FaceCameraMode.java @@ -10,9 +10,6 @@ import org.mesdag.particlestorm.api.IMolangParticleInstance; import org.mesdag.particlestorm.data.MathHelper; -import javax.annotation.ParametersAreNonnullByDefault; - -@ParametersAreNonnullByDefault public enum FaceCameraMode implements SingleQuadParticle.FacingCameraMode { LOOKAT_XYZ { private final Vector3f wd = new Vector3f(); diff --git a/src/main/java/org/mesdag/particlestorm/particle/MolangParticleInstance.java b/src/main/java/org/mesdag/particlestorm/particle/MolangParticleInstance.java index 9e00e54..f21e59e 100644 --- a/src/main/java/org/mesdag/particlestorm/particle/MolangParticleInstance.java +++ b/src/main/java/org/mesdag/particlestorm/particle/MolangParticleInstance.java @@ -7,14 +7,12 @@ import net.minecraft.client.particle.TextureSheetParticle; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.core.particles.ParticleGroup; -import net.minecraft.resources.ResourceLocation; import net.minecraft.util.Mth; import net.minecraft.util.RandomSource; import net.minecraft.world.entity.Entity; import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; import net.neoforged.fml.ModList; -import org.jetbrains.annotations.Nullable; import org.joml.Quaternionf; import org.joml.Vector3f; import org.mesdag.particlestorm.api.IEventNode; @@ -178,8 +176,8 @@ public float getScaleV() { } @Override - public void setBillboardSize(float[] billboardSize) { - this.billboardSize = billboardSize; + public void setBillboardSize(float[] size) { + this.billboardSize = size; } @Override @@ -315,12 +313,6 @@ public void setCollision(boolean bool) { this.hasCollision = bool; } - @Override - public void moveDirectly(double x, double y, double z) { - setBoundingBox(getBoundingBox().move(x, y, z)); - setLocationFromBoundingbox(); - } - @Override public VariableTable getVars() { return vars; @@ -331,15 +323,6 @@ public Level getLevel() { return level; } - public float tickAge() { - return age * emitter.invTickRate; - } - - @Override - public float tickLifetime() { - return lifetime * emitter.invTickRate; - } - @Override public double getRandom1() { return particleRandom1; @@ -360,26 +343,6 @@ public double getRandom4() { return particleRandom4; } - @Override - public ResourceLocation getIdentity() { - return emitter.particleId; - } - - @Override - public Vec3 getPosition() { - return getPos(); - } - - @Override - public @Nullable Entity getAttachedEntity() { - return emitter.getAttachedEntity(); - } - - @Override - public float getInvTickRate() { - return emitter.invTickRate; - } - @Override public ParticleEmitter getEmitter() { return emitter; @@ -418,13 +381,13 @@ public void tick() { } @Override - public void render(VertexConsumer buffer, Camera renderInfo, float partialTicks) { + public void render(VertexConsumer buffer, Camera camera, float partialTicks) { Quaternionf quaternionf = new Quaternionf(); - getFacingCameraMode().setRotation(this, quaternionf, renderInfo, partialTicks); + getFacingCameraMode().setRotation(this, quaternionf, camera, partialTicks); if (xRot != 0.0F) quaternionf.rotateX(Mth.lerp(partialTicks, xRotO, xRot)); if (yRot != 0.0F) quaternionf.rotateY(Mth.lerp(partialTicks, yRotO, yRot)); if (roll != 0.0F) quaternionf.rotateZ(Mth.lerp(partialTicks, oRoll, roll)); - renderRotatedQuad(buffer, renderInfo, quaternionf, partialTicks); + renderRotatedQuad(buffer, camera, quaternionf, partialTicks); } @Override diff --git a/src/main/java/org/mesdag/particlestorm/particle/ParticlePreset.java b/src/main/java/org/mesdag/particlestorm/particle/ParticlePreset.java index e1cd0dd..57499de 100644 --- a/src/main/java/org/mesdag/particlestorm/particle/ParticlePreset.java +++ b/src/main/java/org/mesdag/particlestorm/particle/ParticlePreset.java @@ -2,10 +2,13 @@ import com.google.common.collect.Iterables; import net.minecraft.client.particle.ParticleRenderType; +import net.minecraft.util.Mth; +import net.neoforged.neoforge.common.NeoForge; +import org.jetbrains.annotations.Nullable; import org.mesdag.particlestorm.PSGameClient; -import org.mesdag.particlestorm.api.IComponent; import org.mesdag.particlestorm.api.IParticleComponent; import org.mesdag.particlestorm.api.MolangInstance; +import org.mesdag.particlestorm.api.ParticlePresetLoadedEvent; import org.mesdag.particlestorm.data.DefinedParticleEffect; import org.mesdag.particlestorm.data.MathHelper; import org.mesdag.particlestorm.data.component.*; @@ -18,10 +21,7 @@ import org.mesdag.particlestorm.data.molang.compiler.value.Variable; import org.mesdag.particlestorm.data.molang.compiler.value.VariableAssignment; -import java.util.ArrayList; -import java.util.Hashtable; -import java.util.List; -import java.util.Map; +import java.util.*; import static org.mesdag.particlestorm.data.molang.compiler.MolangQueries.applyPrefixAliases; @@ -40,6 +40,9 @@ public class ParticlePreset { public final VariableTable vars; public final List assignments; + /// For custom preset data + protected Map, Object> tickets; + public ParticlePreset(DefinedParticleEffect effect) { this.effect = effect; this.renderType = switch (effect.description.parameters().material()) { @@ -51,13 +54,17 @@ public ParticlePreset(DefinedParticleEffect effect) { case CUSTOM -> ParticleRenderType.CUSTOM; default -> ParticleRenderType.NO_RENDER; }; - IComponent component1 = effect.components.get(ParticleAppearanceBillboard.ID); - if (component1 == null) throw new NullPointerException("No particle_appearance_billboard here"); - ParticleAppearanceBillboard particleAppearanceBillboard = (ParticleAppearanceBillboard) component1; - this.facingCameraMode = FaceCameraMode.valueOf(particleAppearanceBillboard.faceCameraMode().name()); - this.minSpeedThresholdSqr = particleAppearanceBillboard.direction().minSpeedThreshold() * particleAppearanceBillboard.direction().minSpeedThreshold(); - this.invTextureWidth = 1.0F / particleAppearanceBillboard.uv().texturewidth(); - this.invTextureHeight = 1.0F / particleAppearanceBillboard.uv().textureheight(); + if (effect.components.get(ParticleAppearanceBillboard.ID) instanceof ParticleAppearanceBillboard component) { + this.facingCameraMode = FaceCameraMode.valueOf(component.faceCameraMode().name()); + this.minSpeedThresholdSqr = Mth.square(component.direction().minSpeedThreshold()); + this.invTextureWidth = 1.0F / component.uv().texturewidth(); + this.invTextureHeight = 1.0F / component.uv().textureheight(); + } else { + this.facingCameraMode = FaceCameraMode.ROTATE_XYZ; + this.minSpeedThresholdSqr = 0; + this.invTextureWidth = 1; + this.invTextureHeight = 1; + } this.environmentLighting = effect.components.containsValue(ParticleAppearanceLighting.INSTANCE); this.lifeTimeEvents = (ParticleLifeTimeEvents) effect.components.get(ParticleLifeTimeEvents.ID); ParticleMotionCollision motionCollision = (ParticleMotionCollision) effect.components.get(ParticleMotionCollision.ID); @@ -92,6 +99,17 @@ public ParticlePreset(DefinedParticleEffect effect) { } this.vars = table; this.assignments = toInit; + NeoForge.EVENT_BUS.post(new ParticlePresetLoadedEvent(this)); + } + + public void setTicket(Class clazz, T value) { + if (tickets == null) this.tickets = new HashMap<>(); + tickets.put(clazz, value); + } + + @SuppressWarnings("unchecked") + public @Nullable T getTicket(Class clazz) { + return tickets == null ? null : (T) tickets.get(clazz); } private static Hashtable addDefaultVariables() { From 57eb08609588313d9273d44a0c554dfcceadd7c5 Mon Sep 17 00:00:00 2001 From: westernat Date: Wed, 26 Nov 2025 20:14:21 +0800 Subject: [PATCH 13/22] =?UTF-8?q?=E4=BF=AEbug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gradle.properties | 2 +- .../api/MolangParticleLoadEvent.java | 32 ++++++ .../api/RegisterCustomParticleTypeEvent.java | 4 +- .../ParticleAppearanceBillboard.java | 95 ++++-------------- .../description/DescriptionParameters.java | 7 +- .../data/description/ParticleDescription.java | 2 +- .../mixin/ParticleEngineMixin.java | 3 +- .../particle/MolangParticleLoader.java | 8 +- .../textures/particle/missing.png | Bin 0 -> 209 bytes 9 files changed, 70 insertions(+), 83 deletions(-) create mode 100644 src/main/java/org/mesdag/particlestorm/api/MolangParticleLoadEvent.java create mode 100644 src/main/resources/assets/particlestorm/textures/particle/missing.png diff --git a/gradle.properties b/gradle.properties index bf0c42f..89a196e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -31,7 +31,7 @@ mod_name=ParticleStorm # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=LGPL-3.0 # The mod version. See https://semver.org/ -mod_version=1.2.4 +mod_version=1.1.3 # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. # See https://maven.apache.org/guides/mini/guide-naming-conventions.html diff --git a/src/main/java/org/mesdag/particlestorm/api/MolangParticleLoadEvent.java b/src/main/java/org/mesdag/particlestorm/api/MolangParticleLoadEvent.java new file mode 100644 index 0000000..72458ea --- /dev/null +++ b/src/main/java/org/mesdag/particlestorm/api/MolangParticleLoadEvent.java @@ -0,0 +1,32 @@ +package org.mesdag.particlestorm.api; + +import net.neoforged.bus.api.Event; +import net.neoforged.fml.event.IModBusEvent; + +import java.util.concurrent.Executor; + +public abstract class MolangParticleLoadEvent extends Event implements IModBusEvent { + private final Executor executor; + + public MolangParticleLoadEvent(Executor executor) { + this.executor = executor; + } + + public Executor getExecutor() { + return executor; + } + + /// In Background Executor {@link net.minecraft.Util#backgroundExecutor()} + public static class Pre extends MolangParticleLoadEvent { + public Pre(Executor executor) { + super(executor); + } + } + + /// In Game Executor {@link net.minecraft.client.Minecraft} + public static class Post extends MolangParticleLoadEvent { + public Post(Executor executor) { + super(executor); + } + } +} diff --git a/src/main/java/org/mesdag/particlestorm/api/RegisterCustomParticleTypeEvent.java b/src/main/java/org/mesdag/particlestorm/api/RegisterCustomParticleTypeEvent.java index f385c19..3b6f652 100644 --- a/src/main/java/org/mesdag/particlestorm/api/RegisterCustomParticleTypeEvent.java +++ b/src/main/java/org/mesdag/particlestorm/api/RegisterCustomParticleTypeEvent.java @@ -63,9 +63,8 @@ public interface Provider { V create(ParticleEmitter emitter, ParticlePreset particlePreset, ClientLevel level, double x, double y, double z); /// @see Provider#create(ParticleEmitter, ParticlePreset, ClientLevel, double, double, double) - @Contract("_, _, _, _, _, _, _ -> fail") default V create(ParticleEmitter emitter, ParticlePreset particlePreset, ClientLevel level, double x, double y, double z, ExtendMutableSpriteSet sprites) { - throw new UnsupportedOperationException(); + return create(emitter, particlePreset, level, x, y, z); } } @@ -73,6 +72,7 @@ default V create(ParticleEmitter emitter, ParticlePreset particlePreset, ClientL public interface ProviderWithSprites extends Provider { /// @see ProviderWithSprites#create(ParticleEmitter, ParticlePreset, ClientLevel, double, double, double, ExtendMutableSpriteSet) @Contract("_, _, _, _, _, _ -> fail") + @Override default V create(ParticleEmitter emitter, ParticlePreset particlePreset, ClientLevel level, double x, double y, double z) { throw new UnsupportedOperationException(); } diff --git a/src/main/java/org/mesdag/particlestorm/data/component/ParticleAppearanceBillboard.java b/src/main/java/org/mesdag/particlestorm/data/component/ParticleAppearanceBillboard.java index 10375e9..559f3a0 100644 --- a/src/main/java/org/mesdag/particlestorm/data/component/ParticleAppearanceBillboard.java +++ b/src/main/java/org/mesdag/particlestorm/data/component/ParticleAppearanceBillboard.java @@ -58,16 +58,17 @@ public void update(IMolangParticleInstance instance) { updateFlipbookUV(instance); instance.setMaxFrame((int) flipbook.maxFrame.calculate(instance)); instance.setCurrentFrame(instance.getMaxFrame() * instance.getAge() / instance.self().getLifetime()); - } else if (instance.getLevel().getGameTime() % flipbook.framesPerTick < 1.0F) { - updateFlipbookUV(instance); - instance.setMaxFrame((int) flipbook.maxFrame.calculate(instance)); - if (instance.getCurrentFrame() < instance.getMaxFrame()) { - instance.setCurrentFrame(instance.getCurrentFrame() + 1); - if (flipbook.loop && instance.getCurrentFrame() == instance.getMaxFrame()) { - instance.setCurrentFrame(0); + } else { + float gameTime = (float) (int) (instance.getLevel().getGameTime() & 0b11111111); + if (gameTime % (instance.getLevel().tickRateManager().tickrate() / flipbook.framesPerSecond) < 1.0F) { + updateFlipbookUV(instance); + instance.setMaxFrame((int) flipbook.maxFrame.calculate(instance)); + int currentFrame = instance.getCurrentFrame() + 1; + if (currentFrame < instance.getMaxFrame()) { + instance.setCurrentFrame(currentFrame); + } else { + instance.setCurrentFrame(flipbook.loop ? 0 : instance.getMaxFrame() - 1); } - } else { - instance.setCurrentFrame(instance.getMaxFrame() - 1); } } } @@ -246,51 +247,27 @@ public String toString() { '}'; } - /** - * Alternate way via specifying a flipbook animation

- * A flipbook animation uses pieces of the texture to animate, by stepping over time from one frame to another - */ - public static class Flipbook { + /// Alternate way via specifying a flipbook animation + /// A flipbook animation uses pieces of the texture to animate, by stepping over time from one `frame` to another + /// + /// @param baseUV Upper-left corner of starting UV patch + /// @param sizeUV Size of UV patch + /// @param stepUV How far to move the UV patch each frame + /// @param framesPerSecond Default frames per second + /// @param maxFrame Maximum frame number, with first frame being frame 1 + /// @param stretchToLifetime Optional, adjust fps to match lifetime of particle. Default=false + /// @param loop Optional, makes the animation loop when it reaches the end? Default=false + public record Flipbook(FloatMolangExp2 baseUV, FloatMolangExp2 sizeUV, FloatMolangExp2 stepUV, float framesPerSecond, FloatMolangExp maxFrame, boolean stretchToLifetime, boolean loop) { public static final Flipbook EMPTY = new Flipbook(FloatMolangExp2.ZERO, FloatMolangExp2.ZERO, FloatMolangExp2.ZERO, 0, FloatMolangExp.ZERO, false, false); public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( FloatMolangExp2.CODEC.lenientOptionalFieldOf("base_UV", FloatMolangExp2.ZERO).forGetter(Flipbook::baseUV), FloatMolangExp2.CODEC.lenientOptionalFieldOf("size_UV", FloatMolangExp2.ZERO).forGetter(Flipbook::sizeUV), FloatMolangExp2.CODEC.lenientOptionalFieldOf("step_UV", FloatMolangExp2.ZERO).forGetter(Flipbook::stepUV), - Codec.FLOAT.lenientOptionalFieldOf("frames_per_second", 1.0F).forGetter(Flipbook::framesPerSecond), + ExtraCodecs.POSITIVE_FLOAT.lenientOptionalFieldOf("frames_per_second", 1.0F).forGetter(Flipbook::framesPerSecond), FloatMolangExp.CODEC.lenientOptionalFieldOf("max_frame", FloatMolangExp.ZERO).forGetter(Flipbook::maxFrame), Codec.BOOL.lenientOptionalFieldOf("stretch_to_lifetime", false).forGetter(Flipbook::stretchToLifetime), Codec.BOOL.lenientOptionalFieldOf("loop", false).forGetter(Flipbook::loop) ).apply(instance, Flipbook::new)); - private final FloatMolangExp2 baseUV; - private final FloatMolangExp2 sizeUV; - private final FloatMolangExp2 stepUV; - private final float framesPerSecond; - private final FloatMolangExp maxFrame; - private final boolean stretchToLifetime; - private final boolean loop; - - private final float framesPerTick; - - /** - * @param baseUV Upper-left corner of starting UV patch - * @param sizeUV Size of UV patch - * @param stepUV How far to move the UV patch each frame - * @param framesPerSecond Default frames per second - * @param maxFrame Maximum frame number, with first frame being frame 1 - * @param stretchToLifetime Optional, adjust fps to match lifetime of particle. Default=false - * @param loop Optional, makes the animation loop when it reaches the end? Default=false - */ - public Flipbook(FloatMolangExp2 baseUV, FloatMolangExp2 sizeUV, FloatMolangExp2 stepUV, float framesPerSecond, FloatMolangExp maxFrame, boolean stretchToLifetime, boolean loop) { - this.baseUV = baseUV; - this.sizeUV = sizeUV; - this.stepUV = stepUV; - this.framesPerSecond = framesPerSecond; - this.maxFrame = maxFrame; - this.stretchToLifetime = stretchToLifetime; - this.loop = loop; - - this.framesPerTick = framesPerSecond == 0.0F ? 1.0F : 20.0F / framesPerSecond; - } public float[] getSizeUV(IMolangParticleInstance instance) { return sizeUV.calculate(instance); @@ -300,34 +277,6 @@ public float[] getStepUV(IMolangParticleInstance instance) { return stepUV.calculate(instance); } - public FloatMolangExp2 baseUV() { - return baseUV; - } - - public FloatMolangExp2 sizeUV() { - return sizeUV; - } - - public FloatMolangExp2 stepUV() { - return stepUV; - } - - public float framesPerSecond() { - return framesPerSecond; - } - - public FloatMolangExp maxFrame() { - return maxFrame; - } - - public boolean stretchToLifetime() { - return stretchToLifetime; - } - - public boolean loop() { - return loop; - } - @Override public String toString() { return "Flipbook{" + diff --git a/src/main/java/org/mesdag/particlestorm/data/description/DescriptionParameters.java b/src/main/java/org/mesdag/particlestorm/data/description/DescriptionParameters.java index be0a02f..784c058 100644 --- a/src/main/java/org/mesdag/particlestorm/data/description/DescriptionParameters.java +++ b/src/main/java/org/mesdag/particlestorm/data/description/DescriptionParameters.java @@ -3,11 +3,14 @@ import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.resources.ResourceLocation; +import org.mesdag.particlestorm.ParticleStorm; public class DescriptionParameters { + public static final ResourceLocation MISSING_TEXTURE = ParticleStorm.asResource("missing"); + public static final DescriptionParameters EMPTY = new DescriptionParameters(DescriptionMaterial.CUSTOM, MISSING_TEXTURE); public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( - DescriptionMaterial.CODEC.fieldOf("material").orElse(DescriptionMaterial.PARTICLE_SHEET_TRANSLUCENT).forGetter(DescriptionParameters::material), - ResourceLocation.CODEC.fieldOf("texture").forGetter(DescriptionParameters::texture) + DescriptionMaterial.CODEC.lenientOptionalFieldOf("material", DescriptionMaterial.CUSTOM).orElse(DescriptionMaterial.PARTICLE_SHEET_TRANSLUCENT).forGetter(DescriptionParameters::material), + ResourceLocation.CODEC.lenientOptionalFieldOf("texture", MISSING_TEXTURE).forGetter(DescriptionParameters::texture) ).apply(instance, DescriptionParameters::new)); private final DescriptionMaterial material; private final ResourceLocation texture; diff --git a/src/main/java/org/mesdag/particlestorm/data/description/ParticleDescription.java b/src/main/java/org/mesdag/particlestorm/data/description/ParticleDescription.java index bc2df0b..c1f961b 100644 --- a/src/main/java/org/mesdag/particlestorm/data/description/ParticleDescription.java +++ b/src/main/java/org/mesdag/particlestorm/data/description/ParticleDescription.java @@ -10,7 +10,7 @@ public record ParticleDescription(ResourceLocation identifier, DescriptionParameters parameters, ParticleType type) { public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( ResourceLocation.CODEC.fieldOf("identifier").forGetter(ParticleDescription::identifier), - DescriptionParameters.CODEC.fieldOf("basic_render_parameters").forGetter(ParticleDescription::parameters), + DescriptionParameters.CODEC.lenientOptionalFieldOf("basic_render_parameters", DescriptionParameters.EMPTY).forGetter(ParticleDescription::parameters), BuiltInRegistries.PARTICLE_TYPE.byNameCodec().fieldOf("type").orElseGet(ParticleStorm.MOLANG).forGetter(ParticleDescription::type) ).apply(instance, ParticleDescription::new)); diff --git a/src/main/java/org/mesdag/particlestorm/mixin/ParticleEngineMixin.java b/src/main/java/org/mesdag/particlestorm/mixin/ParticleEngineMixin.java index c026ba8..55af078 100644 --- a/src/main/java/org/mesdag/particlestorm/mixin/ParticleEngineMixin.java +++ b/src/main/java/org/mesdag/particlestorm/mixin/ParticleEngineMixin.java @@ -39,8 +39,7 @@ public abstract class ParticleEngineMixin implements IParticleEngine { TextureAtlasSprite missing = particlestorm$preparations.missing(); spriteSet.bindMissing(missing); ResourceLocation texture = entry.getValue().description.parameters().bindTexture(i); - TextureAtlasSprite sprite = particlestorm$preparations.regions().get(texture); - spriteSet.addSprite(sprite == null ? missing : sprite); + spriteSet.addSprite(particlestorm$preparations.regions().getOrDefault(texture, missing)); i++; } } diff --git a/src/main/java/org/mesdag/particlestorm/particle/MolangParticleLoader.java b/src/main/java/org/mesdag/particlestorm/particle/MolangParticleLoader.java index 23b78e3..39147fd 100644 --- a/src/main/java/org/mesdag/particlestorm/particle/MolangParticleLoader.java +++ b/src/main/java/org/mesdag/particlestorm/particle/MolangParticleLoader.java @@ -1,6 +1,7 @@ package org.mesdag.particlestorm.particle; import com.google.common.collect.EvictingQueue; +import com.google.common.collect.Lists; import com.google.gson.JsonParseException; import com.mojang.serialization.JsonOps; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; @@ -22,17 +23,18 @@ import net.minecraft.util.profiling.ProfilerFiller; import net.minecraft.world.entity.Entity; import net.minecraft.world.level.Level; +import net.neoforged.fml.ModLoader; import org.jetbrains.annotations.Nullable; import org.mesdag.particlestorm.ParticleStorm; import org.mesdag.particlestorm.api.IParticleComponent; import org.mesdag.particlestorm.api.IntAllocator; +import org.mesdag.particlestorm.api.MolangParticleLoadEvent; import org.mesdag.particlestorm.data.DefinedParticleEffect; import org.mesdag.particlestorm.network.EmitterRemovalPacket; import org.mesdag.particlestorm.network.EmitterSynchronizePacket; import java.io.IOException; import java.io.Reader; -import java.util.ArrayList; import java.util.Hashtable; import java.util.List; import java.util.Map; @@ -180,7 +182,8 @@ public boolean contains(int id) { @Override public CompletableFuture reload(PreparationBarrier preparationBarrier, ResourceManager resourceManager, ProfilerFiller preparationsProfiler, ProfilerFiller reloadProfiler, Executor backgroundExecutor, Executor gameExecutor) { return CompletableFuture.supplyAsync(() -> PARTICLE_LISTER.listMatchingResources(resourceManager), backgroundExecutor).thenCompose(map -> { - List> list = new ArrayList<>(map.size()); + ModLoader.postEvent(new MolangParticleLoadEvent.Pre(backgroundExecutor)); + List> list = Lists.newArrayListWithExpectedSize(map.size()); for (Map.Entry entry : map.entrySet()) { ResourceLocation id = PARTICLE_LISTER.fileToId(entry.getKey()); list.add(CompletableFuture.supplyAsync(() -> { @@ -210,6 +213,7 @@ public CompletableFuture reload(PreparationBarrier preparationBarrier, Res this.id2Particle = id2Particle; this.id2Emitter = id2Emitter; this.initialized = false; + ModLoader.postEvent(new MolangParticleLoadEvent.Post(gameExecutor)); }, gameExecutor); } } diff --git a/src/main/resources/assets/particlestorm/textures/particle/missing.png b/src/main/resources/assets/particlestorm/textures/particle/missing.png new file mode 100644 index 0000000000000000000000000000000000000000..a374dbfe653f02590b4639950494c30a630b6b14 GIT binary patch literal 209 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1quc!8A`7#}Etuy^{>N4j6E_`mUdF^WtxLjpVfR z3CpJ~x*x>(Qd<7W$B8D!#!(MGEIMV+nELS*8{3qpUoTD;2oQT!Trro;Sz+;cMrDHu zYaO=e{%4RCv~*%Lk>A-Zu;P>Dgta${k8quC6n>nf-qn<|P7i1!gQu&X%Q~loCIJ82 BM;rhE literal 0 HcmV?d00001 From 8090af7550fa4363e427584b688bfad04e3b295d Mon Sep 17 00:00:00 2001 From: westernat Date: Thu, 27 Nov 2025 12:52:34 +0800 Subject: [PATCH 14/22] =?UTF-8?q?=E5=AE=8C=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gradle.properties | 2 +- .../data/DuplicateFieldDecoder.java | 111 +++++++++++------- .../ParticleAppearanceBillboard.java | 6 +- .../particle/FaceCameraMode.java | 13 ++ .../particle/ParticlePreset.java | 24 ++-- 5 files changed, 98 insertions(+), 58 deletions(-) diff --git a/gradle.properties b/gradle.properties index 89a196e..0b76aad 100644 --- a/gradle.properties +++ b/gradle.properties @@ -31,7 +31,7 @@ mod_name=ParticleStorm # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=LGPL-3.0 # The mod version. See https://semver.org/ -mod_version=1.1.3 +mod_version=1.1.1 # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. # See https://maven.apache.org/guides/mini/guide-naming-conventions.html diff --git a/src/main/java/org/mesdag/particlestorm/data/DuplicateFieldDecoder.java b/src/main/java/org/mesdag/particlestorm/data/DuplicateFieldDecoder.java index 13d211c..fc5a538 100644 --- a/src/main/java/org/mesdag/particlestorm/data/DuplicateFieldDecoder.java +++ b/src/main/java/org/mesdag/particlestorm/data/DuplicateFieldDecoder.java @@ -1,67 +1,94 @@ package org.mesdag.particlestorm.data; -import com.google.common.collect.Sets; import com.mojang.serialization.*; -import com.mojang.serialization.codecs.FieldEncoder; +import net.neoforged.neoforge.common.util.NeoForgeExtraCodecs; +import java.util.Arrays; import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.stream.Stream; -public class DuplicateFieldDecoder extends MapDecoder.Implementation { - protected final Set names; - private final Decoder elementCodec; +public class DuplicateFieldDecoder { + @Deprecated + public static MapCodec fieldOf(String defaultName, Set names, Codec codec) { + return fieldOf(codec, defaultName, names.toArray(new String[0])); + } - public DuplicateFieldDecoder(final Set names, final Decoder elementCodec) { - this.names = names; - this.elementCodec = elementCodec; + @Deprecated + public static MapCodec fieldOf(String defaultName, String another, Codec codec) { + return fieldOf(codec, defaultName, another); } - public static MapCodec fieldOf(String defaultName, Set names, Codec codec) { - Set set = Sets.newHashSet(names); - set.add(defaultName); - return MapCodec.of(new FieldEncoder<>(defaultName, codec), new DuplicateFieldDecoder<>(set, codec)); + public static MapCodec fieldOf(Codec codec, String defaultName, String... alias) { + String[] names = new String[alias.length + 1]; + names[0] = defaultName; + System.arraycopy(alias, 0, names, 1, alias.length); + return NeoForgeExtraCodecs.aliasedFieldOf(codec, names); } - public static MapCodec fieldOf(String defaultName, String another, Codec codec) { - return MapCodec.of(new FieldEncoder<>(defaultName, codec), new DuplicateFieldDecoder<>(Set.of(defaultName, another), codec)); + public static MapCodec> optionalFieldOf(Codec codec, String defaultName, String... alias) { + String[] names = new String[alias.length + 1]; + names[0] = defaultName; + System.arraycopy(alias, 0, names, 1, alias.length); + return new AliasOptionalFieldCodec<>(codec, names); } - @Override - public DataResult decode(final DynamicOps ops, final MapLike input) { - for (String name : names) { - final T value = input.get(name); - if (value != null) { - return elementCodec.parse(ops, value); + public static class AliasOptionalFieldCodec extends MapCodec> { + private final Codec elementCodec; + private final String[] names; + + public AliasOptionalFieldCodec(Codec elementCodec, String[] names) { + this.elementCodec = elementCodec; + this.names = Arrays.stream(names).distinct().sorted().toArray(String[]::new); + } + + @Override + public DataResult> decode(DynamicOps ops, MapLike input) { + for (String name : names) { + T t = input.get(name); + if (t == null) continue; + DataResult parsed = elementCodec.parse(ops, t); + if (parsed.isSuccess()) { + return parsed.map(Optional::of).setPartial(parsed.resultOrPartial()); + } } + return DataResult.success(Optional.empty()); } - return DataResult.error(() -> "No key " + names + " in " + input); - } - @Override - public Stream keys(final DynamicOps ops) { - return names.stream().map(ops::createString); - } + @Override + public RecordBuilder encode(Optional input, DynamicOps ops, RecordBuilder prefix) { + if (input.isEmpty()) return prefix; + return prefix.add(names[0], elementCodec.encodeStart(ops, input.get())); + } - @Override - public boolean equals(final Object o) { - if (this == o) { - return true; + @Override + public Stream keys(DynamicOps ops) { + return Arrays.stream(names).map(ops::createString); } - if (o == null || getClass() != o.getClass()) { - return false; + + @Override + public boolean equals(Object o) { + return o == this || ( + o instanceof AliasOptionalFieldCodec that && + Arrays.equals(names, that.names) && + elementCodec.equals(that.elementCodec) + ); } - final DuplicateFieldDecoder that = (DuplicateFieldDecoder) o; - return Objects.equals(names, that.names) && Objects.equals(elementCodec, that.elementCodec); - } - @Override - public int hashCode() { - return Objects.hash(names, elementCodec); - } + @Override + public int hashCode() { + int result = Objects.hashCode(names); + result = 31 * result + Objects.hashCode(elementCodec); + return result; + } - @Override - public String toString() { - return "DuplicateFieldDecoder[" + names + ": " + elementCodec + ']'; + @Override + public String toString() { + return "AliasOptionalFieldCodec{" + + "names='" + Arrays.toString(names) + '\'' + + ", elementCodec=" + elementCodec + + '}'; + } } } diff --git a/src/main/java/org/mesdag/particlestorm/data/component/ParticleAppearanceBillboard.java b/src/main/java/org/mesdag/particlestorm/data/component/ParticleAppearanceBillboard.java index 559f3a0..a772d40 100644 --- a/src/main/java/org/mesdag/particlestorm/data/component/ParticleAppearanceBillboard.java +++ b/src/main/java/org/mesdag/particlestorm/data/component/ParticleAppearanceBillboard.java @@ -22,7 +22,7 @@ public record ParticleAppearanceBillboard(FloatMolangExp2 size, FaceCameraMode f public static final ResourceLocation ID = ResourceLocation.withDefaultNamespace("particle_appearance_billboard"); public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( FloatMolangExp2.CODEC.fieldOf("size").forGetter(ParticleAppearanceBillboard::size), - DuplicateFieldDecoder.fieldOf("face_camera_mode", "facing_camera_mode", FaceCameraMode.CODEC).forGetter(ParticleAppearanceBillboard::faceCameraMode), + DuplicateFieldDecoder.fieldOf(FaceCameraMode.CODEC, "face_camera_mode", "facing_camera_mode").forGetter(ParticleAppearanceBillboard::faceCameraMode), Direction.CODEC.lenientOptionalFieldOf("direction", Direction.DEFAULT).forGetter(ParticleAppearanceBillboard::direction), UV.CODEC.fieldOf("uv").orElse(UV.EMPTY).forGetter(ParticleAppearanceBillboard::uv) ).apply(instance, ParticleAppearanceBillboard::new)); @@ -229,8 +229,8 @@ public String toString() { public record UV(int texturewidth, int textureheight, FloatMolangExp2 uv, FloatMolangExp2 uvSize, Flipbook flipbook) { public static final UV EMPTY = new UV(1, 1, FloatMolangExp2.ZERO, FloatMolangExp2.ZERO, Flipbook.EMPTY); public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( - DuplicateFieldDecoder.fieldOf("texturewidth", "texture_width", ExtraCodecs.POSITIVE_INT).orElse(1).forGetter(UV::texturewidth), - DuplicateFieldDecoder.fieldOf("textureheight", "texture_height", ExtraCodecs.POSITIVE_INT).orElse(1).forGetter(UV::textureheight), + DuplicateFieldDecoder.fieldOf(ExtraCodecs.POSITIVE_INT, "texturewidth", "texture_width").orElse(1).forGetter(UV::texturewidth), + DuplicateFieldDecoder.fieldOf(ExtraCodecs.POSITIVE_INT, "textureheight", "texture_height").orElse(1).forGetter(UV::textureheight), FloatMolangExp2.CODEC.fieldOf("uv").orElse(FloatMolangExp2.ZERO).forGetter(UV::uv), FloatMolangExp2.CODEC.fieldOf("uv_size").orElse(FloatMolangExp2.ZERO).forGetter(UV::uvSize), Flipbook.CODEC.fieldOf("flipbook").orElse(Flipbook.EMPTY).forGetter(UV::flipbook) diff --git a/src/main/java/org/mesdag/particlestorm/particle/FaceCameraMode.java b/src/main/java/org/mesdag/particlestorm/particle/FaceCameraMode.java index 55cb4ca..199528b 100644 --- a/src/main/java/org/mesdag/particlestorm/particle/FaceCameraMode.java +++ b/src/main/java/org/mesdag/particlestorm/particle/FaceCameraMode.java @@ -9,8 +9,13 @@ import org.joml.Vector3f; import org.mesdag.particlestorm.api.IMolangParticleInstance; import org.mesdag.particlestorm.data.MathHelper; +import org.mesdag.particlestorm.data.component.ParticleAppearanceBillboard; public enum FaceCameraMode implements SingleQuadParticle.FacingCameraMode { + DO_NOTHING { + @Override + public void setRotation(Quaternionf quaternion, Camera camera, float partialTick) {} + }, LOOKAT_XYZ { private final Vector3f wd = new Vector3f(); private final Vector3f qd = new Vector3f(); @@ -114,4 +119,12 @@ public void setRotation(Quaternionf quaternion, Camera camera, float partialTick public void setRotation(IMolangParticleInstance instance, Quaternionf quaternion, Camera camera, float partialTick) { setRotation(quaternion, camera, partialTick); } + + public static FaceCameraMode fromComponent(ParticleAppearanceBillboard.FaceCameraMode faceCameraMode) { + try { + return FaceCameraMode.valueOf(faceCameraMode.name()); + } catch (Exception e) { + return DO_NOTHING; + } + } } diff --git a/src/main/java/org/mesdag/particlestorm/particle/ParticlePreset.java b/src/main/java/org/mesdag/particlestorm/particle/ParticlePreset.java index 57499de..2efaa03 100644 --- a/src/main/java/org/mesdag/particlestorm/particle/ParticlePreset.java +++ b/src/main/java/org/mesdag/particlestorm/particle/ParticlePreset.java @@ -26,19 +26,19 @@ import static org.mesdag.particlestorm.data.molang.compiler.MolangQueries.applyPrefixAliases; public class ParticlePreset { - public final DefinedParticleEffect effect; - public final ParticleRenderType renderType; - public final FaceCameraMode facingCameraMode; - public final float minSpeedThresholdSqr; - public final boolean environmentLighting; + public DefinedParticleEffect effect; + public ParticleRenderType renderType; + public FaceCameraMode facingCameraMode; + public float minSpeedThresholdSqr; + public boolean environmentLighting; public ParticleLifeTimeEvents lifeTimeEvents; public List collisionEvents = List.of(); - public final float invTextureWidth; - public final float invTextureHeight; - public final boolean motionDynamic; + public float invTextureWidth; + public float invTextureHeight; + public boolean motionDynamic; - public final VariableTable vars; - public final List assignments; + public VariableTable vars; + public List assignments; /// For custom preset data protected Map, Object> tickets; @@ -55,12 +55,12 @@ public ParticlePreset(DefinedParticleEffect effect) { default -> ParticleRenderType.NO_RENDER; }; if (effect.components.get(ParticleAppearanceBillboard.ID) instanceof ParticleAppearanceBillboard component) { - this.facingCameraMode = FaceCameraMode.valueOf(component.faceCameraMode().name()); + this.facingCameraMode = FaceCameraMode.fromComponent(component.faceCameraMode()); this.minSpeedThresholdSqr = Mth.square(component.direction().minSpeedThreshold()); this.invTextureWidth = 1.0F / component.uv().texturewidth(); this.invTextureHeight = 1.0F / component.uv().textureheight(); } else { - this.facingCameraMode = FaceCameraMode.ROTATE_XYZ; + this.facingCameraMode = FaceCameraMode.DO_NOTHING; this.minSpeedThresholdSqr = 0; this.invTextureWidth = 1; this.invTextureHeight = 1; From 9a85b72101062968810914e762916bd30943b380 Mon Sep 17 00:00:00 2001 From: westernat Date: Thu, 27 Nov 2025 13:05:21 +0800 Subject: [PATCH 15/22] =?UTF-8?q?=E7=A7=BB=E9=99=A4=E5=A4=9A=E4=BD=99?= =?UTF-8?q?=E9=83=A8=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gradle.properties | 2 +- .../org/mesdag/particlestorm/data/DuplicateFieldDecoder.java | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/gradle.properties b/gradle.properties index 0b76aad..b49c254 100644 --- a/gradle.properties +++ b/gradle.properties @@ -31,7 +31,7 @@ mod_name=ParticleStorm # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=LGPL-3.0 # The mod version. See https://semver.org/ -mod_version=1.1.1 +mod_version=1.1.2 # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. # See https://maven.apache.org/guides/mini/guide-naming-conventions.html diff --git a/src/main/java/org/mesdag/particlestorm/data/DuplicateFieldDecoder.java b/src/main/java/org/mesdag/particlestorm/data/DuplicateFieldDecoder.java index fc5a538..5c32971 100644 --- a/src/main/java/org/mesdag/particlestorm/data/DuplicateFieldDecoder.java +++ b/src/main/java/org/mesdag/particlestorm/data/DuplicateFieldDecoder.java @@ -27,10 +27,7 @@ public static MapCodec fieldOf(Codec codec, String defaultName, String return NeoForgeExtraCodecs.aliasedFieldOf(codec, names); } - public static MapCodec> optionalFieldOf(Codec codec, String defaultName, String... alias) { - String[] names = new String[alias.length + 1]; - names[0] = defaultName; - System.arraycopy(alias, 0, names, 1, alias.length); + public static MapCodec> optionalFieldOf(Codec codec, String... names) { return new AliasOptionalFieldCodec<>(codec, names); } From 52235a6d009d9770f91995a17aacc06f4ec1756b Mon Sep 17 00:00:00 2001 From: westernat Date: Fri, 12 Dec 2025 16:10:37 +0800 Subject: [PATCH 16/22] 1.1.2 --- .../api/RegisterCustomEmitterTypeEvent.java | 42 ++++++ .../data/component/EmitterInitialization.java | 10 +- .../data/component/EmitterLifetime.java | 44 +++---- .../data/component/EmitterLifetimeEvents.java | 28 ++-- .../data/component/EmitterLocalSpace.java | 24 ++-- .../data/component/EmitterRate.java | 12 +- .../data/component/EmitterShape.java | 120 +++++------------- .../ParticleAppearanceBillboard.java | 23 ++-- .../component/ParticleAppearanceLighting.java | 4 +- .../component/ParticleExpireIfInBlocks.java | 7 +- .../ParticleExpireIfNotInBlocks.java | 1 - .../data/component/ParticleInitialSpeed.java | 8 +- .../data/component/ParticleInitialSpin.java | 10 +- .../component/ParticleInitialization.java | 4 +- .../component/ParticleLifeTimeEvents.java | 15 +-- .../component/ParticleLifetimeExpression.java | 20 ++- .../component/ParticleLifetimeKillPlane.java | 13 +- .../component/ParticleMotionCollision.java | 39 +++--- .../data/component/ParticleMotionDynamic.java | 46 +++---- .../component/ParticleMotionParametric.java | 28 ++-- .../particle/MolangParticleLoader.java | 3 +- 21 files changed, 228 insertions(+), 273 deletions(-) create mode 100644 src/main/java/org/mesdag/particlestorm/api/RegisterCustomEmitterTypeEvent.java diff --git a/src/main/java/org/mesdag/particlestorm/api/RegisterCustomEmitterTypeEvent.java b/src/main/java/org/mesdag/particlestorm/api/RegisterCustomEmitterTypeEvent.java new file mode 100644 index 0000000..5ccbbaa --- /dev/null +++ b/src/main/java/org/mesdag/particlestorm/api/RegisterCustomEmitterTypeEvent.java @@ -0,0 +1,42 @@ +package org.mesdag.particlestorm.api; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.Tag; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.Level; +import net.neoforged.bus.api.Event; +import net.neoforged.fml.ModLoader; +import net.neoforged.fml.event.IModBusEvent; +import org.mesdag.particlestorm.particle.ParticleEmitter; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.function.BiFunction; + +public class RegisterCustomEmitterTypeEvent extends Event implements IModBusEvent { + public static final String TYPE_KEY = "type"; + private static Map> map; + + private RegisterCustomEmitterTypeEvent() {} + + public static void postEvent() { + map = new HashMap<>(); + ModLoader.postEvent(new RegisterCustomEmitterTypeEvent()); + } + + public void register(ResourceLocation id, BiFunction factory) { + map.put(id, factory); + } + + public static ParticleEmitter create(Level level, CompoundTag tag) { + if (tag.contains(TYPE_KEY, Tag.TAG_STRING)) { + ResourceLocation id = ResourceLocation.tryParse(Objects.requireNonNull(tag.get(TYPE_KEY)).getAsString()); + BiFunction factory = map.get(id); + if (factory != null) { + return factory.apply(level, tag); + } + } + return new ParticleEmitter(level, tag); + } +} diff --git a/src/main/java/org/mesdag/particlestorm/data/component/EmitterInitialization.java b/src/main/java/org/mesdag/particlestorm/data/component/EmitterInitialization.java index 9ea73f5..06df93e 100644 --- a/src/main/java/org/mesdag/particlestorm/data/component/EmitterInitialization.java +++ b/src/main/java/org/mesdag/particlestorm/data/component/EmitterInitialization.java @@ -8,12 +8,10 @@ import java.util.List; -/** - * This component allows the emitter to run some Molang at creation, primarily to populate any Molang variables that get used later. - * - * @param creationExpression This is run once at emitter startup - * @param perUpdateExpression This is run once per emitter update - */ +/// This component allows the emitter to run some Molang at creation, primarily to populate any Molang variables that get used later. +/// +/// @param creationExpression This is run once at emitter startup +/// @param perUpdateExpression This is run once per emitter update public record EmitterInitialization(MolangExp creationExpression, MolangExp perUpdateExpression) implements IEmitterComponent { public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( MolangExp.CODEC.fieldOf("creation_expression").orElse(MolangExp.EMPTY).forGetter(EmitterInitialization::creationExpression), diff --git a/src/main/java/org/mesdag/particlestorm/data/component/EmitterLifetime.java b/src/main/java/org/mesdag/particlestorm/data/component/EmitterLifetime.java index e621119..4195334 100644 --- a/src/main/java/org/mesdag/particlestorm/data/component/EmitterLifetime.java +++ b/src/main/java/org/mesdag/particlestorm/data/component/EmitterLifetime.java @@ -10,11 +10,9 @@ import java.util.List; public abstract sealed class EmitterLifetime implements IEmitterComponent permits EmitterLifetime.Expression, EmitterLifetime.Looping, EmitterLifetime.Once { - /** - * Emitter will turn 'on' when the activation expression is non-zero, and will turn 'off' when it's zero. - *

- * This is useful for situations like driving an entity-attached emitter from an entity variable. - */ + /// Emitter will turn 'on' when the activation expression is non-zero, and will turn 'off' when it's zero. + /// + /// This is useful for situations like driving an entity-attached emitter from an entity variable. public static final class Expression extends EmitterLifetime { public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( FloatMolangExp.CODEC.fieldOf("activation_expression").orElse(FloatMolangExp.ONE).forGetter(Expression::getActivationExpression), @@ -28,20 +26,16 @@ public Expression(FloatMolangExp activationExpression, FloatMolangExp expiration this.expirationExpression = expirationExpression; } - /** - * When the expression is non-zero, the emitter will emit particles. - *

- * Evaluated every frame - */ + /// When the expression is non-zero, the emitter will emit particles. + /// + /// Evaluated every frame public FloatMolangExp getActivationExpression() { return activationExpression; } - /** - * Emitter will expire if the expression is non-zero. - *

- * Evaluated every frame - */ + /// Emitter will expire if the expression is non-zero. + /// + /// Evaluated every frame public FloatMolangExp getExpirationExpression() { return expirationExpression; } @@ -79,9 +73,7 @@ public String toString() { } } - /** - * Emitter will loop until it is removed. - */ + /// Emitter will loop until it is removed. public static final class Looping extends EmitterLifetime { public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( FloatMolangExp.CODEC.fieldOf("active_time").orElseGet(() -> FloatMolangExp.ofConstant(10)).forGetter(Looping::getActiveTime), @@ -95,20 +87,16 @@ public Looping(FloatMolangExp activeTime, FloatMolangExp sleepTime) { this.sleepTime = sleepTime; } - /** - * Emitter will emit particles for this time per loop - *

- * Evaluated once per particle emitter loop - */ + /// Emitter will emit particles for this time per loop + /// + /// Evaluated once per particle emitter loop public FloatMolangExp getActiveTime() { return activeTime; } - /** - * Emitter will pause emitting particles for this time per loop - *

- * Evaluated once per particle emitter loop - */ + /// Emitter will pause emitting particles for this time per loop + /// + /// Evaluated once per particle emitter loop public FloatMolangExp getSleepTime() { return sleepTime; } diff --git a/src/main/java/org/mesdag/particlestorm/data/component/EmitterLifetimeEvents.java b/src/main/java/org/mesdag/particlestorm/data/component/EmitterLifetimeEvents.java index 1069657..a6a8967 100644 --- a/src/main/java/org/mesdag/particlestorm/data/component/EmitterLifetimeEvents.java +++ b/src/main/java/org/mesdag/particlestorm/data/component/EmitterLifetimeEvents.java @@ -15,11 +15,11 @@ import java.util.Map; import java.util.function.Function; -/** - * Allows for lifetime events on the emitter to trigger certain events.

- * All events use the event names in the event section

- * All events can be an array or a string - */ +/// Allows for lifetime events on the emitter to trigger certain events. +/// +/// All events use the event names in the event section +/// +/// All events can be an array or a string public final class EmitterLifetimeEvents implements IEmitterComponent { public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( ParticleStorm.STRING_LIST_CODEC.fieldOf("creation_event").orElseGet(List::of).forGetter(events -> events.creationEvent), @@ -37,16 +37,14 @@ public final class EmitterLifetimeEvents implements IEmitterComponent { public final List, List>> sortedTimeline; public final List, List>> sortedTravelDistance; - /** - * @param creationEvent Fires when the emitter is created - * @param expirationEvent Fires when the emitter expires (does not wait for particles to expire too) - * @param timeline A series of times, e.g. 0.0 or 1.0, that trigger the event.

- * These get fired on every loop the emitter goes through - * @param travelDistanceEvents S series of distances, e.g. 0.0 or 1.0, that trigger the event.

- * These get fired when the emitter has moved by the specified input - * @param loopingTravelDistanceEvents A series of events that occur at set intervals.

- * These get fired every time the emitter has moved the specified input distance from the last time it was fired. - */ + /// @param creationEvent Fires when the emitter is created + /// @param expirationEvent Fires when the emitter expires (does not wait for particles to expire too) + /// @param timeline A series of times, e.g. 0.0 or 1.0, that trigger the event.

+ /// These get fired on every loop the emitter goes through + /// @param travelDistanceEvents S series of distances, e.g. 0.0 or 1.0, that trigger the event.

+ /// These get fired when the emitter has moved by the specified input + /// @param loopingTravelDistanceEvents A series of events that occur at set intervals.

+ /// These get fired every time the emitter has moved the specified input distance from the last time it was fired. public EmitterLifetimeEvents(List creationEvent, List expirationEvent, Map> timeline, Map> travelDistanceEvents, List loopingTravelDistanceEvents) { this.creationEvent = creationEvent; this.expirationEvent = expirationEvent; diff --git a/src/main/java/org/mesdag/particlestorm/data/component/EmitterLocalSpace.java b/src/main/java/org/mesdag/particlestorm/data/component/EmitterLocalSpace.java index cd009c1..d5ff702 100644 --- a/src/main/java/org/mesdag/particlestorm/data/component/EmitterLocalSpace.java +++ b/src/main/java/org/mesdag/particlestorm/data/component/EmitterLocalSpace.java @@ -7,15 +7,19 @@ import java.util.List; -/** - * This component specifies the frame of reference of the emitter.

- * Applies only when the emitter is attached to an entity.

- * When 'position' is true, the particles will simulate in entity space, otherwise they will simulate in world space.

- * Rotation works the same way for rotation.

- * Default is false for both, which makes the particles emit relative to the emitter, then simulate independently of the emitter.

- * Note that rotation = true and position = false is an invalid option.

- * Velocity will add the emitter's velocity to the initial particle velocity. - */ +/// This component specifies the frame of reference of the emitter. +/// +/// Applies only when the emitter is attached to an entity. +/// +/// When `position` is true, the particles will simulate in entity space, otherwise they will simulate in world space. +/// +/// `rotation` works the same way for `rotation`. +/// +/// Default is false for both, which makes the particles emit relative to the emitter, then simulate independently of the emitter. +/// +/// Note that `rotation` = true and `position` = false is an invalid option. +/// +/// `velocity` will add the emitter's velocity to the initial particle velocity. public record EmitterLocalSpace(boolean position, boolean rotation, boolean velocity) implements IEmitterComponent { public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( Codec.BOOL.fieldOf("position").orElse(false).forGetter(EmitterLocalSpace::position), @@ -33,7 +37,7 @@ public EmitterLocalSpace(boolean position, boolean rotation, boolean velocity) { @Override public Codec codec() { - return null; + return CODEC; } @Override diff --git a/src/main/java/org/mesdag/particlestorm/data/component/EmitterRate.java b/src/main/java/org/mesdag/particlestorm/data/component/EmitterRate.java index 151e38e..5eb44e1 100644 --- a/src/main/java/org/mesdag/particlestorm/data/component/EmitterRate.java +++ b/src/main/java/org/mesdag/particlestorm/data/component/EmitterRate.java @@ -22,9 +22,7 @@ public enum Type { MANUAL } - /** - * All particles come out at once, then no more unless the emitter loops. - */ + /// All particles come out at once, then no more unless the emitter loops. public static final class Instant extends EmitterRate { public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( FloatMolangExp.CODEC.fieldOf("num_particles").orElseGet(() -> FloatMolangExp.ofConstant(10)).forGetter(Instant::getNumParticles) @@ -68,9 +66,7 @@ public String toString() { } } - /** - * Particles come out at a steady or Molang rate over time. - */ + /// Particles come out at a steady or Molang rate over time. public static final class Steady extends EmitterRate { public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( FloatMolangExp.CODEC.fieldOf("spawn_rate").orElse(FloatMolangExp.ONE).forGetter(Steady::getSpawnRate), @@ -127,9 +123,7 @@ public String toString() { } } - /** - * Particle emission will occur only when the emitter is told to emit via the game itself. This is mostly used by legacy particle effects. - */ + /// Particle emission will occur only when the emitter is told to emit via the game itself. This is mostly used by legacy particle effects. public static final class Manual extends EmitterRate { public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( FloatMolangExp.CODEC.fieldOf("max_particles").orElse(FloatMolangExp.ZERO).forGetter(Manual::getMaxParticles) diff --git a/src/main/java/org/mesdag/particlestorm/data/component/EmitterShape.java b/src/main/java/org/mesdag/particlestorm/data/component/EmitterShape.java index 74522eb..3550936 100644 --- a/src/main/java/org/mesdag/particlestorm/data/component/EmitterShape.java +++ b/src/main/java/org/mesdag/particlestorm/data/component/EmitterShape.java @@ -32,9 +32,7 @@ protected EmitterShape(boolean surfaceOnly) { this.surfaceOnly = surfaceOnly; } - /** - * Emit only from the edge of the shape - */ + /// Emit only from the edge of the shape public boolean isSurfaceOnly() { return surfaceOnly; } @@ -121,9 +119,7 @@ private static boolean hasSpaceInParticleLimit(ParticleEmitter emitter) { return Minecraft.getInstance().particleEngine.trackedParticleCounts.getInt(particleGroup) < particleGroup.getLimit(); } - /** - * This component spawns particles using a disc shape, particles can be spawned inside the shape or on its outer perimeter. - */ + /// This component spawns particles using a disc shape, particles can be spawned inside the shape or on its outer perimeter. public static final class Disc extends EmitterShape { public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( FloatMolangExp3.CODEC.fieldOf("offset").orElseGet(() -> FloatMolangExp3.ZERO).forGetter(disc -> disc.offset), @@ -132,25 +128,17 @@ public static final class Disc extends EmitterShape { Direction.CODEC.fieldOf("direction").orElse(Direction.OUTWARDS).forGetter(disc -> disc.direction), Codec.BOOL.fieldOf("surface_only").orElse(false).forGetter(EmitterShape::isSurfaceOnly) ).apply(instance, Disc::new)); - /** - * Specifies the offset from the emitter to emit the particles - *

- * Evaluated once per particle emitted - */ + /// Specifies the offset from the emitter to emit the particles + /// + /// Evaluated once per particle emitted public final FloatMolangExp3 offset; - /** - * Disc radius - *

- * Evaluated once per particle emitted - */ + /// Disc radius + /// + /// Evaluated once per particle emitted public final FloatMolangExp radius; - /** - * Specifies the normal of the disc plane, the disc will be perpendicular to this direction - */ + /// Specifies the normal of the disc plane, the disc will be perpendicular to this direction public final PlaneNormal planeNormal; - /** - * Specifies the direction of particles. - */ + /// Specifies the direction of particles. public final Direction direction; public Disc(FloatMolangExp3 offset, FloatMolangExp radius, PlaneNormal planeNormal, Direction direction, boolean surfaceOnly) { @@ -201,10 +189,8 @@ public String toString() { '}'; } - /** - * Custom direction for the normal - */ - public static class PlaneNormal { + /// Custom direction for the normal + public record PlaneNormal(String name, FloatMolangExp3 plane) { public static final PlaneNormal X = new PlaneNormal("x", FloatMolangExp3.X); public static final PlaneNormal Y = new PlaneNormal("y", FloatMolangExp3.Y); public static final PlaneNormal Z = new PlaneNormal("z", FloatMolangExp3.Z); @@ -217,13 +203,6 @@ public static class PlaneNormal { }, list -> new PlaneNormal("custom", list)), plane -> Either.right(plane.plane) ); - public final String name; - public final FloatMolangExp3 plane; - - PlaneNormal(String name, FloatMolangExp3 list) { - this.name = name; - this.plane = list; - } public boolean isCustom() { return "custom".equals(name); @@ -239,9 +218,7 @@ public String toString() { } } - /** - * All particles come out of a box of the specified size from the emitter. - */ + /// All particles come out of a box of the specified size from the emitter. public static final class Box extends EmitterShape { public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( FloatMolangExp3.CODEC.fieldOf("offset").orElse(FloatMolangExp3.ZERO).forGetter(box -> box.offset), @@ -249,15 +226,11 @@ public static final class Box extends EmitterShape { Direction.CODEC.fieldOf("direction").orElse(Direction.OUTWARDS).forGetter(box -> box.direction), Codec.BOOL.fieldOf("surface_only").orElse(false).forGetter(EmitterShape::isSurfaceOnly) ).apply(instance, Box::new)); - /** - * Specifies the offset from the emitter to emit the particles

- * Evaluated once per particle emitted - */ + /// Specifies the offset from the emitter to emit the particles + /// Evaluated once per particle emitted public final FloatMolangExp3 offset; public final FloatMolangExp3 halfDimensions; - /** - * Specifies the direction of particles. - */ + /// Specifies the direction of particles. public final Direction direction; public Box(FloatMolangExp3 offset, FloatMolangExp3 halfDimensions, Direction direction, boolean surfaceOnly) { @@ -304,9 +277,7 @@ public String toString() { } } - /** - * All particles come out of the axis-aligned bounding box (AABB) for the entity the emitter is attached to, or the emitter point if no entity. - */ + /// All particles come out of the axis-aligned bounding box AABB for the entity the emitter is attached to, or the emitter point if no entity. public static final class EntityAABB extends EmitterShape { public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( Direction.CODEC.fieldOf("direction").orElse(Direction.OUTWARDS).forGetter(entityAABB -> entityAABB.direction), @@ -354,23 +325,17 @@ public String toString() { } } - /** - * All particles come out of a point offset from the emitter. - */ + /// All particles come out of a point offset from the emitter. public static final class Point extends EmitterShape { public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( FloatMolangExp3.CODEC.fieldOf("offset").orElse(FloatMolangExp3.ZERO).forGetter(point -> point.offset), Direction.CODEC.fieldOf("direction").orElse(Direction.OUTWARDS).forGetter(point -> point.direction) ).apply(instance, Point::new)); - /** - * Specifies the offset from the emitter to emit the particles - *

- * Evaluated once per particle emitted - */ + /// Specifies the offset from the emitter to emit the particles + /// + /// Evaluated once per particle emitted public final FloatMolangExp3 offset; - /** - * Specifies the direction of particles. - */ + /// Specifies the direction of particles. public final Direction direction; public Point(FloatMolangExp3 offset, Direction direction) { @@ -420,21 +385,15 @@ public static final class Sphere extends EmitterShape { Direction.CODEC.fieldOf("direction").orElse(Direction.OUTWARDS).forGetter(sphere -> sphere.direction), Codec.BOOL.fieldOf("surface_only").orElse(false).forGetter(EmitterShape::isSurfaceOnly) ).apply(instance, Sphere::new)); - /** - * Specifies the offset from the emitter to emit the particles - *

- * Evaluated once per particle emitted - */ + /// Specifies the offset from the emitter to emit the particles + /// + /// Evaluated once per particle emitted public final FloatMolangExp3 offset; - /** - * Sphere radius - *

- * Evaluated once per particle emitted - */ + /// Sphere radius + /// + /// Evaluated once per particle emitted public final FloatMolangExp radius; - /** - * Specifies the direction of particles. - */ + /// Specifies the direction of particles. public final Direction direction; public Sphere(FloatMolangExp3 offset, FloatMolangExp radius, Direction direction, boolean surfaceOnly) { @@ -477,30 +436,17 @@ public String toString() { } } - /** - * Evaluated once per particle emitted - */ - public static class Direction implements StringRepresentable { - /** - * Particle direction towards center of shape - */ + /// Evaluated once per particle emitted + public record Direction(String name, FloatMolangExp3 direct) implements StringRepresentable { + /// Particle direction towards center of shape public static final Direction INWARDS = new Direction("inwards", FloatMolangExp3.ZERO); - /** - * Particle direction away from center of shape - */ + /// Particle direction away from center of shape public static final Direction OUTWARDS = new Direction("outwards", FloatMolangExp3.ZERO); public static final Codec DIRECTION_CODEC = StringRepresentable.fromValues(() -> new Direction[]{INWARDS, OUTWARDS}); public static final Codec CODEC = Codec.either(DIRECTION_CODEC, FloatMolangExp3.CODEC).xmap( either -> either.map(dir -> dir, list -> new Direction("custom", list)), dir -> dir.direct == FloatMolangExp3.ZERO ? Either.left(dir) : Either.right(dir.direct) ); - public final String name; - public final FloatMolangExp3 direct; - - Direction(String name, FloatMolangExp3 direct) { - this.name = name; - this.direct = direct; - } @Override public String getSerializedName() { diff --git a/src/main/java/org/mesdag/particlestorm/data/component/ParticleAppearanceBillboard.java b/src/main/java/org/mesdag/particlestorm/data/component/ParticleAppearanceBillboard.java index a772d40..dc08f4d 100644 --- a/src/main/java/org/mesdag/particlestorm/data/component/ParticleAppearanceBillboard.java +++ b/src/main/java/org/mesdag/particlestorm/data/component/ParticleAppearanceBillboard.java @@ -59,7 +59,7 @@ public void update(IMolangParticleInstance instance) { instance.setMaxFrame((int) flipbook.maxFrame.calculate(instance)); instance.setCurrentFrame(instance.getMaxFrame() * instance.getAge() / instance.self().getLifetime()); } else { - float gameTime = (float) (int) (instance.getLevel().getGameTime() & 0b11111111); + float gameTime = (float) ((int) instance.getLevel().getGameTime() & 0b11111111); if (gameTime % (instance.getLevel().tickRateManager().tickrate() / flipbook.framesPerSecond) < 1.0F) { updateFlipbookUV(instance); instance.setMaxFrame((int) flipbook.maxFrame.calculate(instance)); @@ -215,17 +215,15 @@ public String toString() { } } - /** - * Specifies the UVs for the particle. - * - * @param texturewidth - * @param textureheight Specifies the assumed texture width/height, defaults to 1

- * When set to 1, UV's work just like normalized UV's

- * When set to the texture width/height, this works like texels - * @param uv - * @param uvSize Assuming the specified texture width and height, use these uv coordinates.

- * Evaluated every frame - */ + /// Specifies the UVs for the particle. + /// + /// @param texturewidth + /// @param textureheight Specifies the assumed texture width/height, defaults to 1

+ /// When set to 1, UV's work just like normalized UV's

+ /// When set to the texture width/height, this works like texels + /// @param uv + /// @param uvSize Assuming the specified texture width and height, use these uv coordinates.

+ /// Evaluated every frame public record UV(int texturewidth, int textureheight, FloatMolangExp2 uv, FloatMolangExp2 uvSize, Flipbook flipbook) { public static final UV EMPTY = new UV(1, 1, FloatMolangExp2.ZERO, FloatMolangExp2.ZERO, Flipbook.EMPTY); public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( @@ -248,6 +246,7 @@ public String toString() { } /// Alternate way via specifying a flipbook animation + /// /// A flipbook animation uses pieces of the texture to animate, by stepping over time from one `frame` to another /// /// @param baseUV Upper-left corner of starting UV patch diff --git a/src/main/java/org/mesdag/particlestorm/data/component/ParticleAppearanceLighting.java b/src/main/java/org/mesdag/particlestorm/data/component/ParticleAppearanceLighting.java index 4fc05ad..f929548 100644 --- a/src/main/java/org/mesdag/particlestorm/data/component/ParticleAppearanceLighting.java +++ b/src/main/java/org/mesdag/particlestorm/data/component/ParticleAppearanceLighting.java @@ -9,9 +9,7 @@ import java.util.List; -/** - * When this component exists, particle will be tinted by local lighting conditions in-game. - */ +/// When this component exists, particle will be tinted by local lighting conditions in-game. public final class ParticleAppearanceLighting implements IParticleComponent { public static final ParticleAppearanceLighting INSTANCE = new ParticleAppearanceLighting(); public static final Codec CODEC = MapCodec.of(Encoder.empty(), Decoder.unit(ParticleAppearanceLighting.INSTANCE)).codec(); diff --git a/src/main/java/org/mesdag/particlestorm/data/component/ParticleExpireIfInBlocks.java b/src/main/java/org/mesdag/particlestorm/data/component/ParticleExpireIfInBlocks.java index d895d12..001a438 100644 --- a/src/main/java/org/mesdag/particlestorm/data/component/ParticleExpireIfInBlocks.java +++ b/src/main/java/org/mesdag/particlestorm/data/component/ParticleExpireIfInBlocks.java @@ -17,10 +17,9 @@ import java.util.List; import java.util.Set; -/** - * Particles expire when in a block of the type in the list.

- * Note: this component can exist alongside particle_lifetime_expression. - */ +/// Particles expire when in a block of the type in the list. +/// +/// Note: this component can exist alongside particle_lifetime_expression. public final class ParticleExpireIfInBlocks implements IParticleComponent { public static final Codec CODEC = Codec.list(Codec.STRING).xmap( states -> new ParticleExpireIfInBlocks(new HashSet<>(states)), diff --git a/src/main/java/org/mesdag/particlestorm/data/component/ParticleExpireIfNotInBlocks.java b/src/main/java/org/mesdag/particlestorm/data/component/ParticleExpireIfNotInBlocks.java index 238fe90..03cbcfc 100644 --- a/src/main/java/org/mesdag/particlestorm/data/component/ParticleExpireIfNotInBlocks.java +++ b/src/main/java/org/mesdag/particlestorm/data/component/ParticleExpireIfNotInBlocks.java @@ -61,5 +61,4 @@ public String toString() { return "ParticleExpireIfNotInBlocks[" + "blocks=" + ids + ']'; } - } diff --git a/src/main/java/org/mesdag/particlestorm/data/component/ParticleInitialSpeed.java b/src/main/java/org/mesdag/particlestorm/data/component/ParticleInitialSpeed.java index 131303e..e7b165e 100644 --- a/src/main/java/org/mesdag/particlestorm/data/component/ParticleInitialSpeed.java +++ b/src/main/java/org/mesdag/particlestorm/data/component/ParticleInitialSpeed.java @@ -10,11 +10,9 @@ import java.util.List; -/** - * Starts the particle with a specified speed, using the direction specified by the emitter shape. - * - * @param speed Evaluated once - */ +/// Starts the particle with a specified speed, using the direction specified by the emitter shape. +/// +/// @param speed Evaluated once public record ParticleInitialSpeed(Either speed) implements IParticleComponent { public static final Codec CODEC = Codec.either(FloatMolangExp.CODEC, FloatMolangExp3.CODEC).xmap( either -> either.map(f -> new ParticleInitialSpeed(Either.left(f)), l -> new ParticleInitialSpeed(Either.right(l))), diff --git a/src/main/java/org/mesdag/particlestorm/data/component/ParticleInitialSpin.java b/src/main/java/org/mesdag/particlestorm/data/component/ParticleInitialSpin.java index 1784bbc..43df051 100644 --- a/src/main/java/org/mesdag/particlestorm/data/component/ParticleInitialSpin.java +++ b/src/main/java/org/mesdag/particlestorm/data/component/ParticleInitialSpin.java @@ -10,12 +10,10 @@ import java.util.List; -/** - * Starts the particle with a specified orientation and rotation rate. - * - * @param rotation Specifies the initial rotation in degrees. Evaluated once - * @param rotationRate Specifies the spin rate in degrees/second. Evaluated once - */ +/// Starts the particle with a specified orientation and rotation rate. +/// +/// @param rotation Specifies the initial rotation in degrees. Evaluated once +/// @param rotationRate Specifies the spin rate in degrees/second. Evaluated once public record ParticleInitialSpin(FloatMolangExp rotation, FloatMolangExp rotationRate) implements IParticleComponent { public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( FloatMolangExp.CODEC.fieldOf("rotation").orElse(FloatMolangExp.ZERO).forGetter(ParticleInitialSpin::rotation), diff --git a/src/main/java/org/mesdag/particlestorm/data/component/ParticleInitialization.java b/src/main/java/org/mesdag/particlestorm/data/component/ParticleInitialization.java index 988bd87..6f35f8e 100644 --- a/src/main/java/org/mesdag/particlestorm/data/component/ParticleInitialization.java +++ b/src/main/java/org/mesdag/particlestorm/data/component/ParticleInitialization.java @@ -9,9 +9,7 @@ import java.util.List; -/** - * Starts the particle with a specified render expression. - */ +/// Starts the particle with a specified render expression. public record ParticleInitialization(FloatMolangExp perRenderExpression) implements IParticleComponent { public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( FloatMolangExp.CODEC.fieldOf("per_render_expression").forGetter(ParticleInitialization::perRenderExpression) diff --git a/src/main/java/org/mesdag/particlestorm/data/component/ParticleLifeTimeEvents.java b/src/main/java/org/mesdag/particlestorm/data/component/ParticleLifeTimeEvents.java index f440638..00773c8 100644 --- a/src/main/java/org/mesdag/particlestorm/data/component/ParticleLifeTimeEvents.java +++ b/src/main/java/org/mesdag/particlestorm/data/component/ParticleLifeTimeEvents.java @@ -16,10 +16,9 @@ import java.util.Map; import java.util.function.Function; -/** - * All events use the event names in the event section

- * All events can be either an array or a string - */ +/// All events use the event names in the event section +/// +/// All events can be either an array or a string public final class ParticleLifeTimeEvents implements IParticleComponent { public static final ResourceLocation ID = ResourceLocation.withDefaultNamespace("particle_lifetime_events"); public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( @@ -33,11 +32,9 @@ public final class ParticleLifeTimeEvents implements IParticleComponent { public final List, List>> sortedTimeline; - /** - * @param creationEvent Fires when the particle is created - * @param expirationEvent Fires when the particle expires (does not wait for particles to expire too) - * @param timeline A series of times, e.g. 0.0 or 1.0, that trigger the event - */ + /// @param creationEvent Fires when the particle is created + /// @param expirationEvent Fires when the particle expires (does not wait for particles to expire too) + /// @param timeline A series of times, e.g. 0.0 or 1.0, that trigger the event public ParticleLifeTimeEvents(List creationEvent, List expirationEvent, Map> timeline) { this.creationEvent = creationEvent; this.expirationEvent = expirationEvent; diff --git a/src/main/java/org/mesdag/particlestorm/data/component/ParticleLifetimeExpression.java b/src/main/java/org/mesdag/particlestorm/data/component/ParticleLifetimeExpression.java index ecfa7f7..a3381d9 100644 --- a/src/main/java/org/mesdag/particlestorm/data/component/ParticleLifetimeExpression.java +++ b/src/main/java/org/mesdag/particlestorm/data/component/ParticleLifetimeExpression.java @@ -9,17 +9,15 @@ import java.util.List; -/** - * Standard lifetime component. These expressions control the lifetime of the particle. - * - * @param expirationExpression This expression makes the particle expire when true (non-zero)

- * The float/expr is evaluated once per particle

- * Evaluated every frame - * @param maxLifetime Alternate way to express lifetime

- * Particle will expire after this much time

- * Evaluated once

- * Available value is [0.05, infinite) - */ +/// Standard lifetime component. These expressions control the lifetime of the particle. +/// +/// @param expirationExpression This expression makes the particle expire when true (non-zero)

+/// The float/expr is evaluated once per particle

+/// Evaluated every frame

+/// @param maxLifetime Alternate way to express lifetime

+/// Particle will expire after this much time

+/// Evaluated once

+/// Available value is `[0.05, infinite)` public record ParticleLifetimeExpression(FloatMolangExp expirationExpression, FloatMolangExp maxLifetime) implements IParticleComponent { public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( FloatMolangExp.CODEC.fieldOf("expiration_expression").orElse(FloatMolangExp.ZERO).forGetter(ParticleLifetimeExpression::expirationExpression), diff --git a/src/main/java/org/mesdag/particlestorm/data/component/ParticleLifetimeKillPlane.java b/src/main/java/org/mesdag/particlestorm/data/component/ParticleLifetimeKillPlane.java index 0489050..e011b21 100644 --- a/src/main/java/org/mesdag/particlestorm/data/component/ParticleLifetimeKillPlane.java +++ b/src/main/java/org/mesdag/particlestorm/data/component/ParticleLifetimeKillPlane.java @@ -7,12 +7,13 @@ import java.util.List; -/** - * Particles that cross this plane expire.

- * The plane is relative to the emitter, but oriented in world space.

- * The four parameters are the usual 4 elements of a plane equation.

- * A*x + B*y + C*z + D = 0 with the parameters being [ A, B, C, D ] - */ +/// Particles that cross this plane expire. +/// +/// The plane is relative to the emitter, but oriented in world space. +/// +/// The four parameters are the usual 4 elements of a plane equation. +/// +/// `A*x + B*y + C*z + D = 0` with the parameters being `[ A, B, C, D ]` public final class ParticleLifetimeKillPlane implements IParticleComponent { public static final Codec CODEC = Codec.list(Codec.FLOAT, 4, 4).xmap( floats -> new ParticleLifetimeKillPlane(floats.getFirst(), floats.get(1), floats.get(2), floats.get(3)), diff --git a/src/main/java/org/mesdag/particlestorm/data/component/ParticleMotionCollision.java b/src/main/java/org/mesdag/particlestorm/data/component/ParticleMotionCollision.java index 3ffcf13..c238685 100644 --- a/src/main/java/org/mesdag/particlestorm/data/component/ParticleMotionCollision.java +++ b/src/main/java/org/mesdag/particlestorm/data/component/ParticleMotionCollision.java @@ -15,25 +15,26 @@ import java.util.List; import java.util.function.Function; -/** - * This component enables collisions between the terrain and the particle.

- * Collision detection in Minecraft consists of detecting an intersection,

- * moving to a nearby non-intersecting point for the particle (if possible),

- * and setting its direction to not be aimed towards the collision (usually perpendicular to the collision surface). - * - * @param enabled Enables collision when true/non-zero.

- * Evaluated every frame - * @param collisionDrag Alters the speed of the particle when it has collided

- * Useful for emulating friction/drag when colliding, e.g a particle that hits the ground would slow to a stop.

- * This drag slows down the particle by this amount in blocks/sec when in contact - * @param coefficientOfRestitution Used for bouncing/not-bouncing

- * Set to 0.0 to not bounce, 1.0 to bounce back up to original height and in-between to lose speed after bouncing.

- * Set to >1.0 to gain energy on each bounce - * @param collisionRadius Used to minimize interpenetration of particles with the environment

- * Note that this must be less than or equal to 1/2 block - * @param expireOnContact Triggers expiration on contact if true - * @param events Triggers an event array of individual events - */ +/// This component enables collisions between the terrain and the particle. +/// +/// Collision detection in Minecraft consists of detecting an intersection, +/// +/// moving to a nearby non-intersecting point for the particle (if possible), +/// +/// and setting its direction to not be aimed towards the collision (usually perpendicular to the collision surface). +/// +/// @param enabled Enables collision when true/non-zero.

+/// Evaluated every frame +/// @param collisionDrag Alters the speed of the particle when it has collided

+/// Useful for emulating friction/drag when colliding, e.g a particle that hits the ground would slow to a stop.

+/// This drag slows down the particle by this amount in blocks/sec when in contact +/// @param coefficientOfRestitution Used for bouncing/not-bouncing

+/// Set to 0.0 to not bounce, 1.0 to bounce back up to original height and in-between to lose speed after bouncing.

+/// Set to >1.0 to gain energy on each bounce +/// @param collisionRadius Used to minimize interpenetration of particles with the environment

+/// Note that this must be less than or equal to 1/2 block +/// @param expireOnContact Triggers expiration on contact if true +/// @param events Triggers an event array of individual events public record ParticleMotionCollision(BoolMolangExp enabled, float collisionDrag, float coefficientOfRestitution, float collisionRadius, boolean expireOnContact, List events) implements IParticleComponent { public static final ResourceLocation ID = ResourceLocation.withDefaultNamespace("particle_motion_collision"); public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( diff --git a/src/main/java/org/mesdag/particlestorm/data/component/ParticleMotionDynamic.java b/src/main/java/org/mesdag/particlestorm/data/component/ParticleMotionDynamic.java index 4e5bcff..ba974cb 100644 --- a/src/main/java/org/mesdag/particlestorm/data/component/ParticleMotionDynamic.java +++ b/src/main/java/org/mesdag/particlestorm/data/component/ParticleMotionDynamic.java @@ -12,29 +12,29 @@ import java.util.List; -/** - * This component specifies the dynamic properties of the particle, from a simulation standpoint what forces act upon the particle?

- * These dynamics alter the velocity of the particle, which is a combination of the direction of the particle and the speed.

- * Particle direction will always be in the direction of the velocity of the particle. - * - * @param linerAcceleration The linear acceleration applied to the particle, defaults to [0, 0, 0].

- * Units are blocks/sec/sec

- * An example would be gravity which is [0, -9.8, 0]

- * Evaluated every frame - * @param linearDragCoefficient Equation is acceleration = -linear_drag_coefficient*velocity

- * Where velocity is the current direction times speed

- * Think of this as air-drag. The higher the exp, the more drag

- * Evaluated every frame - * @param rotationAcceleration Acceleration applies to the rotation speed of the particle

- * Think of a disc spinning up or a smoke puff that starts rotating but slows down over time

- * Evaluated every frame

- * Acceleration is in degrees/sec/sec - * @param rotationDragCoefficient Drag applied to slow down rotation

- * Equation is rotation_acceleration += -rotation_rate*rotation_drag_coefficient

- * Useful to slow a rotation, or to limit the rotation acceleration

- * Think of a disc that speeds up (acceleration) but reaches a terminal speed (drag)

- * Another use is if you have a particle growing in size, having the rotation slow down due to drag can add "weight" to the particle's motion - */ +/// This component specifies the dynamic properties of the particle, from a simulation standpoint what forces act upon the particle? +/// +/// These dynamics alter the velocity of the particle, which is a combination of the direction of the particle and the speed. +/// +/// Particle direction will always be in the direction of the velocity of the particle. +/// +/// @param linerAcceleration The linear acceleration applied to the particle, defaults to `[0, 0, 0]`.

+/// Units are blocks/sec/sec

+/// An example would be gravity which is `[0, -9.8, 0]`

+/// Evaluated every frame +/// @param linearDragCoefficient Equation is `acceleration = -linear_drag_coefficient*velocity`

+/// Where velocity is the current direction times speed

+/// Think of this as air-drag. The higher the exp, the more drag

+/// Evaluated every frame +/// @param rotationAcceleration Acceleration applies to the rotation speed of the particle

+/// Think of a disc spinning up or a smoke puff that starts rotating but slows down over time

+/// Evaluated every frame

+/// Acceleration is in degrees/sec/sec +/// @param rotationDragCoefficient Drag applied to slow down rotation

+/// Equation is `rotation_acceleration += -rotation_rate*rotation_drag_coefficient`

+/// Useful to slow a rotation, or to limit the rotation acceleration

+/// Think of a disc that speeds up (acceleration) but reaches a terminal speed (drag)

+/// Another use is if you have a particle growing in size, having the rotation slow down due to drag can add "weight" to the particle's motion public record ParticleMotionDynamic(FloatMolangExp3 linerAcceleration, FloatMolangExp linearDragCoefficient, FloatMolangExp rotationAcceleration, FloatMolangExp rotationDragCoefficient) implements IParticleComponent { public static final ResourceLocation ID = ResourceLocation.withDefaultNamespace("particle_motion_dynamic"); diff --git a/src/main/java/org/mesdag/particlestorm/data/component/ParticleMotionParametric.java b/src/main/java/org/mesdag/particlestorm/data/component/ParticleMotionParametric.java index 642c63a..e725700 100644 --- a/src/main/java/org/mesdag/particlestorm/data/component/ParticleMotionParametric.java +++ b/src/main/java/org/mesdag/particlestorm/data/component/ParticleMotionParametric.java @@ -10,21 +10,19 @@ import java.util.List; -/** - * This component directly controls the particle. - * - * @param relativePosition Directly set the position relative to the emitter. Defaults to [0, 0, 0]

- * E.g. a spiral might be: - *

- * "relative_position": ["Math.cos(Params.LifeTime)", 1.0, "Math.sin(Params.Lifetime)"] - *

- * Evaluated every frame - * @param direction Directly set the 3d direction of the particle

- * Doesn't affect direction if not specified

- * Evaluated every frame - * @param rotation Directly set the rotation of the particle

- * Evaluated every frame - */ +/// This component directly controls the particle. +/// +/// @param relativePosition Directly set the position relative to the emitter. Defaults to `[0, 0, 0]`

+/// E.g. a spiral might be: +/// ``` +/// "relative_position": ["Math.cos(Params.LifeTime)", 1.0, "Math.sin(Params.Lifetime)"] +/// ``` +/// Evaluated every frame +/// @param direction Directly set the 3d direction of the particle

+/// Doesn't affect direction if not specified

+/// Evaluated every frame +/// @param rotation Directly set the rotation of the particle

+/// Evaluated every frame public record ParticleMotionParametric(FloatMolangExp3 relativePosition, FloatMolangExp3 direction, FloatMolangExp rotation) implements IParticleComponent { public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( FloatMolangExp3.CODEC.fieldOf("relative_position").orElse(FloatMolangExp3.ZERO).forGetter(ParticleMotionParametric::relativePosition), diff --git a/src/main/java/org/mesdag/particlestorm/particle/MolangParticleLoader.java b/src/main/java/org/mesdag/particlestorm/particle/MolangParticleLoader.java index 39147fd..7165583 100644 --- a/src/main/java/org/mesdag/particlestorm/particle/MolangParticleLoader.java +++ b/src/main/java/org/mesdag/particlestorm/particle/MolangParticleLoader.java @@ -29,6 +29,7 @@ import org.mesdag.particlestorm.api.IParticleComponent; import org.mesdag.particlestorm.api.IntAllocator; import org.mesdag.particlestorm.api.MolangParticleLoadEvent; +import org.mesdag.particlestorm.api.RegisterCustomEmitterTypeEvent; import org.mesdag.particlestorm.data.DefinedParticleEffect; import org.mesdag.particlestorm.network.EmitterRemovalPacket; import org.mesdag.particlestorm.network.EmitterSynchronizePacket; @@ -121,7 +122,7 @@ public int totalEmitterCount() { } public void loadEmitter(Level level, int id, CompoundTag tag) { - ParticleEmitter emitter = new ParticleEmitter(level, tag); + ParticleEmitter emitter = RegisterCustomEmitterTypeEvent.create(level, tag); emitter.id = id; emitters.put(id, emitter); if (allocator.forceAllocate(id)) { From 3cc8e11a7be45a8926741a474c0b819a74b0790f Mon Sep 17 00:00:00 2001 From: westernat Date: Fri, 12 Dec 2025 19:15:03 +0800 Subject: [PATCH 17/22] =?UTF-8?q?=E5=8F=91=E5=B0=84=E5=99=A8=E7=8E=B0?= =?UTF-8?q?=E5=9C=A8=E5=8F=AF=E4=BB=A5=E5=9C=A8tick=20step=E4=B8=AD?= =?UTF-8?q?=E8=BF=90=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gradle.properties | 2 +- src/main/java/org/mesdag/particlestorm/PSGameClient.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle.properties b/gradle.properties index b49c254..89a196e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -31,7 +31,7 @@ mod_name=ParticleStorm # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=LGPL-3.0 # The mod version. See https://semver.org/ -mod_version=1.1.2 +mod_version=1.1.3 # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. # See https://maven.apache.org/guides/mini/guide-naming-conventions.html diff --git a/src/main/java/org/mesdag/particlestorm/PSGameClient.java b/src/main/java/org/mesdag/particlestorm/PSGameClient.java index 56b3988..5f08815 100644 --- a/src/main/java/org/mesdag/particlestorm/PSGameClient.java +++ b/src/main/java/org/mesdag/particlestorm/PSGameClient.java @@ -83,7 +83,7 @@ private static void tick(ClientTickEvent.Pre event) { LocalPlayer localPlayer = minecraft.player; if (localPlayer == null) { LOADER.removeAll(); - } else if (!minecraft.isPaused() && !localPlayer.level().tickRateManager().isFrozen()) { + } else if (!minecraft.isPaused() && localPlayer.level().tickRateManager().runsNormally()) { LOADER.tick(localPlayer); } } From d0ae6cbccacccad11db302338166a07f295c3430 Mon Sep 17 00:00:00 2001 From: westernat Date: Fri, 12 Dec 2025 20:12:59 +0800 Subject: [PATCH 18/22] =?UTF-8?q?=E4=BF=AEdirection=E7=9A=84codec?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gradle.properties | 2 +- .../component/ParticleAppearanceBillboard.java | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/gradle.properties b/gradle.properties index 89a196e..47f4633 100644 --- a/gradle.properties +++ b/gradle.properties @@ -31,7 +31,7 @@ mod_name=ParticleStorm # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=LGPL-3.0 # The mod version. See https://semver.org/ -mod_version=1.1.3 +mod_version=1.1.4 # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. # See https://maven.apache.org/guides/mini/guide-naming-conventions.html diff --git a/src/main/java/org/mesdag/particlestorm/data/component/ParticleAppearanceBillboard.java b/src/main/java/org/mesdag/particlestorm/data/component/ParticleAppearanceBillboard.java index dc08f4d..610c258 100644 --- a/src/main/java/org/mesdag/particlestorm/data/component/ParticleAppearanceBillboard.java +++ b/src/main/java/org/mesdag/particlestorm/data/component/ParticleAppearanceBillboard.java @@ -1,6 +1,7 @@ package org.mesdag.particlestorm.data.component; import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.resources.ResourceLocation; @@ -176,13 +177,14 @@ public String toString() { public record Direction(Mode mode, float minSpeedThreshold, FloatMolangExp3 customDirection) { public static final Direction DEFAULT = new Direction(Direction.Mode.DERIVE_FROM_VELOCITY, 0.01F, FloatMolangExp3.ZERO); + public static final MapCodec CUSTOM_MODE_CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group( + FloatMolangExp3.CODEC.fieldOf("custom_direction").orElse(FloatMolangExp3.ZERO).forGetter(Direction::customDirection) + ).apply(instance, l -> new Direction(Mode.CUSTOM_DIRECTION, 0, l))); + public static final MapCodec SPEED_MODE_CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group( + Codec.FLOAT.fieldOf("min_speed_threshold").orElse(0.01F).forGetter(Direction::minSpeedThreshold) + ).apply(instance, f -> new Direction(Mode.DERIVE_FROM_VELOCITY, f, FloatMolangExp3.ZERO))); public static final Codec CODEC = Mode.CODEC.dispatchMap( - Direction::mode, - mode -> mode == Mode.CUSTOM_DIRECTION ? RecordCodecBuilder.mapCodec(instance -> instance.group( - FloatMolangExp3.CODEC.fieldOf("custom_direction").orElse(FloatMolangExp3.ZERO).forGetter(Direction::customDirection) - ).apply(instance, l -> new Direction(mode, 0, l))) : RecordCodecBuilder.mapCodec(instance -> instance.group( - Codec.FLOAT.fieldOf("min_speed_threshold").orElse(0.01F).forGetter(Direction::minSpeedThreshold) - ).apply(instance, f -> new Direction(mode, f, FloatMolangExp3.ZERO))) + "mode", Direction::mode, mode -> mode == Mode.CUSTOM_DIRECTION ? CUSTOM_MODE_CODEC : SPEED_MODE_CODEC ).codec(); @Override From 8b7cefb95617ccb98477dd667f455f3b27c69583 Mon Sep 17 00:00:00 2001 From: westernat Date: Sat, 13 Dec 2025 16:34:32 +0800 Subject: [PATCH 19/22] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dlookat=5Fdirection?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gradle.properties | 2 +- .../mesdag/particlestorm/PSGameClient.java | 1 + .../mesdag/particlestorm/api/IEventNode.java | 1 + .../ParticleAppearanceBillboard.java | 1 + .../data/event/NodeMolangExp.java | 27 +++++++- .../data/event/ParticleEffect.java | 62 +++++-------------- .../particlestorm/data/molang/MolangExp.java | 15 ++++- .../data/molang/compiler/MolangQueries.java | 9 +-- .../particle/FaceCameraMode.java | 38 +++++++----- .../particle/MolangParticleInstance.java | 4 +- .../particle/ParticleEmitter.java | 61 ++++++++++++++++-- .../resources/META-INF/accesstransformer.cfg | 1 + 12 files changed, 138 insertions(+), 84 deletions(-) diff --git a/gradle.properties b/gradle.properties index 47f4633..f37a0d6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -31,7 +31,7 @@ mod_name=ParticleStorm # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=LGPL-3.0 # The mod version. See https://semver.org/ -mod_version=1.1.4 +mod_version=1.1.2.1 # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. # See https://maven.apache.org/guides/mini/guide-naming-conventions.html diff --git a/src/main/java/org/mesdag/particlestorm/PSGameClient.java b/src/main/java/org/mesdag/particlestorm/PSGameClient.java index 5f08815..72f409f 100644 --- a/src/main/java/org/mesdag/particlestorm/PSGameClient.java +++ b/src/main/java/org/mesdag/particlestorm/PSGameClient.java @@ -167,5 +167,6 @@ private static void registerEventNodes() { IEventNode.register("particle_effect", ParticleEffect.CODEC.codec()); IEventNode.register("sound_effect", SoundEffect.CODEC.codec()); IEventNode.register("expression", NodeMolangExp.CODEC); + IEventNode.register("log", EventLog.CODEC); } } diff --git a/src/main/java/org/mesdag/particlestorm/api/IEventNode.java b/src/main/java/org/mesdag/particlestorm/api/IEventNode.java index 642d01b..975847e 100644 --- a/src/main/java/org/mesdag/particlestorm/api/IEventNode.java +++ b/src/main/java/org/mesdag/particlestorm/api/IEventNode.java @@ -19,6 +19,7 @@ static Codec getCodec(String name) { return codec; } + @SuppressWarnings("unchecked") static void register(String name, Codec codec) { MAP.put(name, (Codec) codec); } diff --git a/src/main/java/org/mesdag/particlestorm/data/component/ParticleAppearanceBillboard.java b/src/main/java/org/mesdag/particlestorm/data/component/ParticleAppearanceBillboard.java index 610c258..937085c 100644 --- a/src/main/java/org/mesdag/particlestorm/data/component/ParticleAppearanceBillboard.java +++ b/src/main/java/org/mesdag/particlestorm/data/component/ParticleAppearanceBillboard.java @@ -146,6 +146,7 @@ public String toString() { } public enum FaceCameraMode implements StringRepresentable { + DO_NOTHING, ROTATE_XYZ, ROTATE_Y, LOOKAT_XYZ, diff --git a/src/main/java/org/mesdag/particlestorm/data/event/NodeMolangExp.java b/src/main/java/org/mesdag/particlestorm/data/event/NodeMolangExp.java index 5fe1581..18999e1 100644 --- a/src/main/java/org/mesdag/particlestorm/data/event/NodeMolangExp.java +++ b/src/main/java/org/mesdag/particlestorm/data/event/NodeMolangExp.java @@ -1,16 +1,34 @@ package org.mesdag.particlestorm.data.event; +import com.mojang.datafixers.util.Either; import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import org.mesdag.particlestorm.ParticleStorm; import org.mesdag.particlestorm.api.IEventNode; import org.mesdag.particlestorm.api.MolangInstance; import org.mesdag.particlestorm.data.molang.MolangExp; import org.mesdag.particlestorm.data.molang.compiler.MolangParser; +import java.util.function.Function; + public final class NodeMolangExp extends MolangExp implements IEventNode { - public static final Codec CODEC = Codec.STRING.xmap(NodeMolangExp::new, NodeMolangExp::getExpStr); + public static final Codec DIRECT_CODEC = RecordCodecBuilder.create(instance -> instance.group( + Codec.STRING.fieldOf("exp").forGetter(NodeMolangExp::getExpStr), + Codec.BOOL.lenientOptionalFieldOf("log", false).forGetter(NodeMolangExp::shouldLog) + ).apply(instance, NodeMolangExp::new)); + public static final Codec CODEC = Codec.either(DIRECT_CODEC, Codec.STRING).xmap( + either -> either.map(Function.identity(), s -> new NodeMolangExp(s, false)), + e -> e.log ? Either.right(e.expStr) : Either.left(e) + ); + private final boolean log; - public NodeMolangExp(String expStr) { + public NodeMolangExp(String expStr, boolean log) { super(expStr); + this.log = log; + } + + public boolean shouldLog() { + return log; } @Override @@ -20,7 +38,10 @@ public void execute(MolangInstance instance) { this.variable = parser.compileMolang(expStr); } if (variable != null) { - variable.get(instance); + double v = variable.get(instance); + if (log) { + ParticleStorm.LOGGER.info("{}[{}]: {}={}", instance.getIdentity(), instance.getPosition(), expStr, v); + } } } } diff --git a/src/main/java/org/mesdag/particlestorm/data/event/ParticleEffect.java b/src/main/java/org/mesdag/particlestorm/data/event/ParticleEffect.java index e765927..3c12962 100644 --- a/src/main/java/org/mesdag/particlestorm/data/event/ParticleEffect.java +++ b/src/main/java/org/mesdag/particlestorm/data/event/ParticleEffect.java @@ -13,7 +13,7 @@ import org.mesdag.particlestorm.api.IEventNode; import org.mesdag.particlestorm.api.MolangInstance; import org.mesdag.particlestorm.data.molang.MolangExp; -import org.mesdag.particlestorm.data.molang.compiler.value.Variable; +import org.mesdag.particlestorm.data.molang.compiler.MolangQueries; import org.mesdag.particlestorm.particle.ParticleEmitter; import java.util.List; @@ -26,7 +26,10 @@ public record ParticleEffect(ResourceLocation effect, Type type, MolangExp preEf Type.CODEC.fieldOf("type").forGetter(ParticleEffect::type), MolangExp.CODEC.fieldOf("pre_effect_expression").orElse(MolangExp.EMPTY).forGetter(ParticleEffect::preEffectExpression), Codec.STRING.listOf().lenientOptionalFieldOf("shared_vars", List.of()).forGetter(ParticleEffect::sharedVars) - ).apply(instance, ParticleEffect::new)); + ).apply(instance, (rl, t, e, l) -> { + l = l.stream().map(s -> MolangQueries.applyPrefixAliases(s, "variable.", "v.")).toList(); + return new ParticleEffect(rl, t, e, l); + })); public ParticleEffect(ResourceLocation effect, Type type, MolangExp preEffectExpression) { this(effect, type, preEffectExpression, List.of()); @@ -34,36 +37,7 @@ public ParticleEffect(ResourceLocation effect, Type type, MolangExp preEffectExp @Override public void execute(MolangInstance instance) { - ParticleEmitter emitter = new ParticleEmitter(instance.getLevel(), instance.getPosition(), effect, preEffectExpression); - emitter.afterParentInit = parent -> { - switch (type) { - case EMITTER -> {} - case EMITTER_BOUND -> { - emitter.attachEntity(parent.getAttachedEntity()); - emitter.attachedBlock = parent.attachedBlock; - emitter.offsetPos = parent.offsetPos; - emitter.offsetRot = parent.offsetRot; - emitter.parentPosition = parent.parentPosition; - emitter.parentRotation = parent.parentRotation; - emitter.parentMode = parent.parentMode; - } - case PARTICLE -> emitter.isManual = true; - case PARTICLE_WITH_VELOCITY -> { - emitter.isManual = true; - if (parent.getAttachedEntity() != null) { - emitter.inheritedParticleSpeed = parent.getAttachedEntity().getDeltaMovement().toVector3f(); - } - } - } - }; - ParticleEmitter parent = instance.getEmitter(); - emitter.addParent(parent); - for (String name : sharedVars) { - Variable variable = parent.getVars().table.get(name); - if (variable == null) throw new IllegalArgumentException("Shared vars must defined in parent directly!"); - emitter.getVars().setValue(name, variable); - } - PSGameClient.LOADER.addEmitter(emitter, false); + PSGameClient.LOADER.addEmitter(new ParticleEmitter(instance.getEmitter(), this), false); } @Override @@ -77,25 +51,17 @@ public String toString() { } public enum Type implements StringRepresentable { - /** - * Create an emitter of the specified particle effect at the event's world location - */ + /// Create an emitter of the specified particle effect at the event's world location EMITTER, - /** - * Create an emitter of the specified particle effect at the event's location. - *

- * If the firing emitter is bound to an entity or locator, the new emitter will be bound to the same entity or locator. - */ + /// Create an emitter of the specified particle effect at the event's location. + /// + /// If the firing emitter is bound to an entity or locator, the new emitter will be bound to the same entity or locator. EMITTER_BOUND, - /** - * Manually emit a particle on an emitter of the specified type at the event location, creating the emitter if it doesn't already exist. - *

- * Make sure to use the Spawn Amount mode "Manual" on the child particle effect. - */ + /// Manually emit a particle on an emitter of the specified type at the event location, creating the emitter if it doesn't already exist. + /// + /// Make sure to use the Spawn Amount mode "Manual" on the child particle effect. PARTICLE, - /** - * The same as "Particle" except the new particle will inherit the spawning particle's velocity. - */ + /// The same as "Particle" except the new particle will inherit the spawning particle's velocity. PARTICLE_WITH_VELOCITY; public static final Codec CODEC = StringRepresentable.fromEnum(Type::values); diff --git a/src/main/java/org/mesdag/particlestorm/data/molang/MolangExp.java b/src/main/java/org/mesdag/particlestorm/data/molang/MolangExp.java index 04fdb3c..01585c4 100644 --- a/src/main/java/org/mesdag/particlestorm/data/molang/MolangExp.java +++ b/src/main/java/org/mesdag/particlestorm/data/molang/MolangExp.java @@ -8,6 +8,7 @@ import org.mesdag.particlestorm.api.MolangInstance; import org.mesdag.particlestorm.data.molang.compiler.MathValue; import org.mesdag.particlestorm.data.molang.compiler.MolangParser; +import org.mesdag.particlestorm.data.molang.compiler.MolangQueries; import org.mesdag.particlestorm.data.molang.compiler.value.Constant; import java.util.Map; @@ -24,18 +25,26 @@ public MolangExp(String expStr) { } public MolangExp(String key, double value) { - if (!key.startsWith("variable.")) key = "variable." + key; - this.expStr = key + "=" + value + ";"; + this.expStr = MolangQueries.applyPrefixAliases(key, "variable.", "v.") + "=" + value; } public MolangExp(Map exps) { StringBuilder builder = new StringBuilder(); + int i = 0; for (Map.Entry entry : exps.entrySet()) { - builder.append(entry.getKey()).append('=').append(entry.getValue()).append(';'); + builder.append(entry.getKey()).append('=').append(entry.getValue()); + if (++i < exps.size()) { + builder.append(';'); + } } this.expStr = builder.toString(); } + public MolangExp(MathValue variable) { + this.expStr = variable.toString(); + this.variable = variable; + } + public String getExpStr() { return expStr; } diff --git a/src/main/java/org/mesdag/particlestorm/data/molang/compiler/MolangQueries.java b/src/main/java/org/mesdag/particlestorm/data/molang/compiler/MolangQueries.java index d6d181d..091142a 100644 --- a/src/main/java/org/mesdag/particlestorm/data/molang/compiler/MolangQueries.java +++ b/src/main/java/org/mesdag/particlestorm/data/molang/compiler/MolangQueries.java @@ -8,6 +8,7 @@ import org.mesdag.particlestorm.api.RegisterMolangQueriesEvent; import org.mesdag.particlestorm.data.molang.compiler.value.Variable; +import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -79,13 +80,7 @@ private static void setDefaultQueryValues() { registerQueryVariable("query.time_of_day", p -> p.getLevel().getDayTime() / 24000f); registerQueryVariable("query.time_stamp", p -> p.getLevel().getGameTime()); registerQueryVariable("query.total_emitter_count", p -> PSGameClient.LOADER.totalEmitterCount()); - registerQueryVariable("query.total_particle_count", p -> { - int sum = 0; - for (Integer value : Minecraft.getInstance().particleEngine.trackedParticleCounts.values()) { - sum += value; - } - return sum; - }); + registerQueryVariable("query.total_particle_count", p -> Minecraft.getInstance().particleEngine.particles.values().stream().mapToInt(Collection::size).sum()); registerQueryVariable("query.attached_x", p -> p.getAttachedEntity() == null ? 0.0 : p.getAttachedEntity().getX()); registerQueryVariable("query.attached_y", p -> p.getAttachedEntity() == null ? 0.0 : p.getAttachedEntity().getY()); registerQueryVariable("query.attached_z", p -> p.getAttachedEntity() == null ? 0.0 : p.getAttachedEntity().getZ()); diff --git a/src/main/java/org/mesdag/particlestorm/particle/FaceCameraMode.java b/src/main/java/org/mesdag/particlestorm/particle/FaceCameraMode.java index 199528b..4b6c8da 100644 --- a/src/main/java/org/mesdag/particlestorm/particle/FaceCameraMode.java +++ b/src/main/java/org/mesdag/particlestorm/particle/FaceCameraMode.java @@ -3,10 +3,8 @@ import net.minecraft.client.Camera; import net.minecraft.client.particle.SingleQuadParticle; import net.minecraft.util.Mth; -import org.joml.Math; -import org.joml.Matrix4f; -import org.joml.Quaternionf; -import org.joml.Vector3f; +import net.minecraft.world.phys.Vec3; +import org.joml.*; import org.mesdag.particlestorm.api.IMolangParticleInstance; import org.mesdag.particlestorm.data.MathHelper; import org.mesdag.particlestorm.data.component.ParticleAppearanceBillboard; @@ -17,9 +15,10 @@ public enum FaceCameraMode implements SingleQuadParticle.FacingCameraMode { public void setRotation(Quaternionf quaternion, Camera camera, float partialTick) {} }, LOOKAT_XYZ { - private final Vector3f wd = new Vector3f(); - private final Vector3f qd = new Vector3f(); - private final Vector3f up = new Vector3f(0, 1, 0); + private static final Vector3f wd = new Vector3f(); + private static final Vector3f qd = new Vector3f(); + private static final Vector3f up = new Vector3f(0, 1, 0); + private static final Matrix3f mat = new Matrix3f(); @Override public void setRotation(Quaternionf quaternion, Camera camera, float partialTick) {} @@ -33,11 +32,10 @@ public void setRotation(IMolangParticleInstance instance, Quaternionf quaternion ).normalize(); up.cross(xd, wd).normalize(); xd.cross(wd, qd); - quaternion.setFromNormalized(new Matrix4f( - wd.x, qd.x, xd.x, 0, - wd.y, qd.y, xd.y, 0, - wd.z, qd.z, xd.z, 0, - 0, 0, 0, 1 + quaternion.setFromNormalized(mat.set( + wd.x, qd.x, xd.x, + wd.y, qd.y, xd.y, + wd.z, qd.z, xd.z ).invert()); } }, @@ -83,7 +81,9 @@ public void setRotation(Quaternionf quaternion, Camera camera, float partialTick } }, LOOKAT_DIRECTION { - private final Vector3f X = new Vector3f(1.0F, 0.0F, 0.0F); + private static final Vector3f X = new Vector3f(1.0F, 0.0F, 0.0F); + private static final Vector4f t = new Vector4f(); + private static final Matrix4f m = new Matrix4f(); @Override public void setRotation(Quaternionf quaternion, Camera camera, float partialTick) {} @@ -91,10 +91,14 @@ public void setRotation(Quaternionf quaternion, Camera camera, float partialTick @Override public void setRotation(IMolangParticleInstance instance, Quaternionf quaternion, Camera camera, float partialTick) { MathHelper.setFromUnitVectors(X, instance.getFacingDirection(), quaternion); - instance.setXRot(Math.atan2( - (float) (instance.getX() - camera.getPosition().y), - (float) (camera.getPosition().z - instance.getZ()) - )); + Vec3 pos = camera.getPosition(); + t.set( + pos.x - instance.getX(), + pos.y - instance.getY(), + pos.z - instance.getZ(), + 0 + ).mul(m.rotation(quaternion).invert()); + quaternion.rotateX((float) Mth.atan2(-t.y, t.z)); } }, EMITTER_TRANSFORM_XY { diff --git a/src/main/java/org/mesdag/particlestorm/particle/MolangParticleInstance.java b/src/main/java/org/mesdag/particlestorm/particle/MolangParticleInstance.java index f21e59e..599e64c 100644 --- a/src/main/java/org/mesdag/particlestorm/particle/MolangParticleInstance.java +++ b/src/main/java/org/mesdag/particlestorm/particle/MolangParticleInstance.java @@ -380,9 +380,11 @@ public void tick() { } } + private static final Quaternionf quaternionf = new Quaternionf(); + @Override public void render(VertexConsumer buffer, Camera camera, float partialTicks) { - Quaternionf quaternionf = new Quaternionf(); + quaternionf.identity(); getFacingCameraMode().setRotation(this, quaternionf, camera, partialTicks); if (xRot != 0.0F) quaternionf.rotateX(Mth.lerp(partialTicks, xRotO, xRot)); if (yRot != 0.0F) quaternionf.rotateY(Mth.lerp(partialTicks, yRotO, yRot)); diff --git a/src/main/java/org/mesdag/particlestorm/particle/ParticleEmitter.java b/src/main/java/org/mesdag/particlestorm/particle/ParticleEmitter.java index cede5fa..097aff6 100644 --- a/src/main/java/org/mesdag/particlestorm/particle/ParticleEmitter.java +++ b/src/main/java/org/mesdag/particlestorm/particle/ParticleEmitter.java @@ -18,16 +18,17 @@ import org.mesdag.particlestorm.data.MathHelper; import org.mesdag.particlestorm.data.component.EmitterLifetime; import org.mesdag.particlestorm.data.component.EmitterRate; +import org.mesdag.particlestorm.data.event.ParticleEffect; import org.mesdag.particlestorm.data.molang.MolangExp; import org.mesdag.particlestorm.data.molang.VariableTable; import org.mesdag.particlestorm.data.molang.compiler.MathValue; import org.mesdag.particlestorm.data.molang.compiler.MolangParser; +import org.mesdag.particlestorm.data.molang.compiler.value.Variable; import org.mesdag.particlestorm.data.molang.compiler.value.VariableAssignment; import org.mesdag.particlestorm.mixed.IEntity; import java.util.ArrayList; import java.util.List; -import java.util.function.Consumer; public class ParticleEmitter implements MolangInstance { public ResourceLocation particleId; @@ -42,7 +43,7 @@ public class ParticleEmitter implements MolangInstance { protected transient VariableTable vars; protected transient List components; public transient ParticleEmitter parent; - public transient @Nullable Consumer afterParentInit; + public transient @Nullable Runnable afterParentInit; public transient final List children = new ArrayList<>(); public transient Vector3f inheritedParticleSpeed; public transient boolean isManual; @@ -100,6 +101,46 @@ public ParticleEmitter(Level level, CompoundTag tag) { init(); } + public ParticleEmitter(ParticleEmitter parent, ParticleEffect effect) { + this.level = parent.level; + setPos(parent.pos); + this.posO = pos; + this.particleId = effect.effect(); + this.expression = effect.preEffectExpression(); + updateRandoms(level.random); + this.invTickRate = 1.0F / level.tickRateManager().tickrate(); + this.afterParentInit = () -> { + switch (effect.type()) { + case EMITTER -> {} + case EMITTER_BOUND -> { + attachEntity(parent.getAttachedEntity()); + this.attachedBlock = parent.attachedBlock; + this.offsetPos = parent.offsetPos; + this.offsetRot = parent.offsetRot; + this.parentPosition = parent.parentPosition; + this.parentRotation = parent.parentRotation; + this.parentMode = parent.parentMode; + } + case PARTICLE -> this.isManual = true; + case PARTICLE_WITH_VELOCITY -> { + this.isManual = true; + if (parent.getAttachedEntity() != null) { + this.inheritedParticleSpeed = parent.getAttachedEntity().getDeltaMovement().toVector3f(); + } + } + } + }; + addParent(parent); + createVars(); + for (String name : effect.sharedVars()) { + Variable variable = parent.getVars().table.get(name); + if (variable == null) throw new IllegalArgumentException("Shared vars must defined in parent directly!"); + vars.table.put(name, variable); + } + initVars(); + createComponents(); + } + public void attachEntity(@Nullable Entity entity) { if (entity == null) { this.vars = new VariableTable(vars.table, preset.vars); @@ -112,12 +153,21 @@ public void attachEntity(@Nullable Entity entity) { } } - private void init() { + protected void init() { + createVars(); + initVars(); + createComponents(); + } + + protected void createVars() { this.preset = PSGameClient.LOADER.id2Emitter().get(particleId); if (preset == null) { throw new IllegalArgumentException("Unknown particle id: '" + particleId + "'!"); } this.vars = new VariableTable(preset.vars); + } + + protected void initVars() { if (expression != null && !expression.initialized()) { expression.compile(new MolangParser(vars)); MathValue variable = expression.getVariable(); @@ -128,6 +178,9 @@ private void init() { MathHelper.redirect(toInit, vars); } MathHelper.redirect(preset.assignments, vars); + } + + protected void createComponents() { this.components = preset.components.stream().filter(e -> { e.apply(this); return e.requireUpdate(); @@ -186,7 +239,7 @@ public void tick() { } if (afterParentInit != null && parent != null) { - afterParentInit.accept(parent); + afterParentInit.run(); this.afterParentInit = null; } diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg index 309cfa6..083a960 100644 --- a/src/main/resources/META-INF/accesstransformer.cfg +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -6,3 +6,4 @@ public net.minecraft.client.particle.ParticleEngine$MutableSpriteSet protected net.minecraft.client.particle.ParticleEngine$MutableSpriteSet sprites protected net.minecraft.client.particle.ParticleEngine$MutableSpriteSet ()V public net.minecraft.client.particle.ParticleEngine trackedParticleCounts +public net.minecraft.client.particle.ParticleEngine particles From eec7c1d48e4c04f94cd8833ccaceb62484219cb1 Mon Sep 17 00:00:00 2001 From: westernat Date: Sun, 14 Dec 2025 19:49:05 +0800 Subject: [PATCH 20/22] 1.1.3 --- gradle.properties | 2 +- .../data/component/ParticleInitialization.java | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/gradle.properties b/gradle.properties index f37a0d6..89a196e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -31,7 +31,7 @@ mod_name=ParticleStorm # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=LGPL-3.0 # The mod version. See https://semver.org/ -mod_version=1.1.2.1 +mod_version=1.1.3 # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. # See https://maven.apache.org/guides/mini/guide-naming-conventions.html diff --git a/src/main/java/org/mesdag/particlestorm/data/component/ParticleInitialization.java b/src/main/java/org/mesdag/particlestorm/data/component/ParticleInitialization.java index 6f35f8e..cf4e171 100644 --- a/src/main/java/org/mesdag/particlestorm/data/component/ParticleInitialization.java +++ b/src/main/java/org/mesdag/particlestorm/data/component/ParticleInitialization.java @@ -12,8 +12,14 @@ /// Starts the particle with a specified render expression. public record ParticleInitialization(FloatMolangExp perRenderExpression) implements IParticleComponent { public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( - FloatMolangExp.CODEC.fieldOf("per_render_expression").forGetter(ParticleInitialization::perRenderExpression) - ).apply(instance, ParticleInitialization::new)); + FloatMolangExp.CODEC.fieldOf("per_render_expression").forGetter(ParticleInitialization::perRenderExpression), + FloatMolangExp.CODEC.lenientOptionalFieldOf("per_update_expression", FloatMolangExp.ZERO).forGetter(ParticleInitialization::perRenderExpression) + ).apply(instance, (render, update) -> { + if (update != FloatMolangExp.ZERO) { + throw new IllegalArgumentException("per_update_expression is not allowed here, please use per_render_expression instead"); + } + return new ParticleInitialization(render); + })); @Override public Codec codec() { From 900d9f149e48751eb735ab85e08ecf3f667c0d46 Mon Sep 17 00:00:00 2001 From: westernat Date: Sun, 14 Dec 2025 20:11:11 +0800 Subject: [PATCH 21/22] fix EmitterShape$Box --- .../particlestorm/data/component/EmitterShape.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/mesdag/particlestorm/data/component/EmitterShape.java b/src/main/java/org/mesdag/particlestorm/data/component/EmitterShape.java index 3550936..784dce7 100644 --- a/src/main/java/org/mesdag/particlestorm/data/component/EmitterShape.java +++ b/src/main/java/org/mesdag/particlestorm/data/component/EmitterShape.java @@ -252,16 +252,17 @@ public List getAllMolangExp() { @Override protected void initializeParticle(MolangInstance instance, Vector3f position, Vector3f speed) { - position.set(offset.calculate(instance)); + float[] offset = this.offset.calculate(instance); + position.set(offset); float[] n = halfDimensions.calculate(instance); RandomSource random = instance.getLevel().random; position.x += Mth.nextFloat(random, -n[0], n[0]); position.y += Mth.nextFloat(random, -n[1], n[1]); position.z += Mth.nextFloat(random, -n[2], n[2]); if (surfaceOnly) { - int r = random.nextInt(0, 3); - boolean i = random.nextBoolean(); - position.setComponent(r, n[r] * (i ? 1 : -1)); + int i = random.nextInt(0, 3); + boolean b = random.nextBoolean(); + position.setComponent(i, offset[i] + (b ? n[i] : -n[i])); } direction.apply(instance, this, position, speed); } From c416e98713d1b7c599e0d72a0b6066de3685e79a Mon Sep 17 00:00:00 2001 From: westernat Date: Fri, 19 Dec 2025 23:03:57 +0800 Subject: [PATCH 22/22] fix crush --- build.gradle | 2 +- gradle.properties | 4 +-- .../mesdag/particlestorm/PSGameClient.java | 9 +++---- .../mesdag/particlestorm/ParticleStorm.java | 15 +++-------- .../api/geckolib/GeckoLibHelper.java | 25 +++++++++++++++++++ .../particlestorm/api/geckolib/TestBlock.java | 3 +-- .../integration/geckolib/GeoBoneMixin.java | 1 - .../geckolib}/MolangQueriesAccessor.java | 6 +++-- src/main/resources/particlestorm.mixins.json | 2 +- 9 files changed, 41 insertions(+), 26 deletions(-) rename src/main/java/org/mesdag/particlestorm/mixin/{ => integration/geckolib}/MolangQueriesAccessor.java (62%) diff --git a/build.gradle b/build.gradle index 9d68194..f35e7fe 100644 --- a/build.gradle +++ b/build.gradle @@ -94,7 +94,7 @@ repositories { dependencies { compileOnly "software.bernie.geckolib:geckolib-neoforge-${minecraft_version}:${geckolib_version}" - localRuntime "software.bernie.geckolib:geckolib-neoforge-${minecraft_version}:${geckolib_version}" +// localRuntime "software.bernie.geckolib:geckolib-neoforge-${minecraft_version}:${geckolib_version}" } tasks.withType(ProcessResources).configureEach { diff --git a/gradle.properties b/gradle.properties index 89a196e..770f008 100644 --- a/gradle.properties +++ b/gradle.properties @@ -31,7 +31,7 @@ mod_name=ParticleStorm # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=LGPL-3.0 # The mod version. See https://semver.org/ -mod_version=1.1.3 +mod_version=1.1.4 # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. # See https://maven.apache.org/guides/mini/guide-naming-conventions.html @@ -41,7 +41,7 @@ mod_authors=Westernat # The description of the mod. This is a simple multiline text string that is used for display purposes in the mod list. mod_description=Uses a Bedrock Edition JSON format for particle effects. -geckolib_version=4.7.5.1 +geckolib_version=4.8.2 #systemProp.http.proxyHost=localhost #systemProp.http.proxyPort=7890 diff --git a/src/main/java/org/mesdag/particlestorm/PSGameClient.java b/src/main/java/org/mesdag/particlestorm/PSGameClient.java index 72f409f..4c14122 100644 --- a/src/main/java/org/mesdag/particlestorm/PSGameClient.java +++ b/src/main/java/org/mesdag/particlestorm/PSGameClient.java @@ -14,7 +14,6 @@ import net.minecraft.client.renderer.texture.TextureAtlas; import net.minecraft.client.renderer.texture.TextureManager; import net.minecraft.util.Mth; -import net.minecraft.world.entity.EntityType; import net.neoforged.api.distmarker.Dist; import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.fml.common.EventBusSubscriber; @@ -27,8 +26,7 @@ import net.neoforged.neoforge.common.NeoForge; import org.mesdag.particlestorm.api.IComponent; import org.mesdag.particlestorm.api.IEventNode; -import org.mesdag.particlestorm.api.geckolib.ExampleBlockEntityRenderer; -import org.mesdag.particlestorm.api.geckolib.ReplacedCreeperRenderer; +import org.mesdag.particlestorm.api.geckolib.GeckoLibHelper; import org.mesdag.particlestorm.data.component.*; import org.mesdag.particlestorm.data.event.*; import org.mesdag.particlestorm.particle.MolangParticleLoader; @@ -55,10 +53,9 @@ public String toString() { }; @SubscribeEvent - public static void registerRenderers(final EntityRenderersEvent.RegisterRenderers event) { + public static void registerRenderers(EntityRenderersEvent.RegisterRenderers event) { if (ParticleStorm.DEBUG) { - event.registerBlockEntityRenderer(ParticleStorm.TEST_ENTITY.get(), ExampleBlockEntityRenderer::new); - event.registerEntityRenderer(EntityType.CREEPER, ReplacedCreeperRenderer::new); + GeckoLibHelper.registerRenderers(event); } } diff --git a/src/main/java/org/mesdag/particlestorm/ParticleStorm.java b/src/main/java/org/mesdag/particlestorm/ParticleStorm.java index 3ff3fe7..6ee9648 100644 --- a/src/main/java/org/mesdag/particlestorm/ParticleStorm.java +++ b/src/main/java/org/mesdag/particlestorm/ParticleStorm.java @@ -10,11 +10,10 @@ import net.minecraft.network.codec.StreamCodec; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntityType; import net.neoforged.bus.api.IEventBus; import net.neoforged.fml.ModContainer; import net.neoforged.fml.common.Mod; +import net.neoforged.fml.loading.LoadingModList; import net.neoforged.neoforge.common.NeoForge; import net.neoforged.neoforge.event.RegisterCommandsEvent; import net.neoforged.neoforge.event.entity.player.PlayerEvent; @@ -23,7 +22,7 @@ import net.neoforged.neoforge.network.registration.PayloadRegistrar; import net.neoforged.neoforge.registries.DeferredHolder; import net.neoforged.neoforge.registries.DeferredRegister; -import org.mesdag.particlestorm.api.geckolib.TestBlock; +import org.mesdag.particlestorm.api.geckolib.GeckoLibHelper; import org.mesdag.particlestorm.network.EmitterAttachPacketS2C; import org.mesdag.particlestorm.network.EmitterCreationPacketS2C; import org.mesdag.particlestorm.network.EmitterRemovalPacket; @@ -43,7 +42,7 @@ public final class ParticleStorm { public static final String MODID = "particlestorm"; public static final Logger LOGGER = LoggerFactory.getLogger("ParticleStorm"); - public static final boolean DEBUG = Boolean.getBoolean("particlestorm.debug"); + public static final boolean DEBUG = Boolean.getBoolean("particlestorm.debug") && LoadingModList.get().getModFileById("geckolib") != null; private static final DeferredRegister> REGISTER = DeferredRegister.create(BuiltInRegistries.PARTICLE_TYPE, MODID); public static final DeferredHolder, ParticleType> MOLANG = registerParticleType(REGISTER, "molang"); @@ -51,7 +50,6 @@ public final class ParticleStorm { either -> either.map(Collections::singletonList, Function.identity()), l -> l.size() == 1 ? Either.left(l.getFirst()) : Either.right(l) ); - public static DeferredHolder, BlockEntityType> TEST_ENTITY; public ParticleStorm(IEventBus bus, ModContainer container) { PSClientConfigs.register(container); @@ -88,12 +86,7 @@ private static void playerLoggedIn(PlayerEvent.PlayerLoggedInEvent event) { private static void registerGeoTest(IEventBus bus) { if (DEBUG) { - DeferredRegister BLOCK = DeferredRegister.create(BuiltInRegistries.BLOCK, MODID); - DeferredRegister> ENTITY = DeferredRegister.create(BuiltInRegistries.BLOCK_ENTITY_TYPE, MODID); - DeferredHolder TEST = BLOCK.register("test_block", TestBlock::new); - TEST_ENTITY = ENTITY.register("test_entity", () -> BlockEntityType.Builder.of(TestBlock.Entity::new, TEST.get()).build(null)); - BLOCK.register(bus); - ENTITY.register(bus); + GeckoLibHelper.registerStuffs(bus); } } diff --git a/src/main/java/org/mesdag/particlestorm/api/geckolib/GeckoLibHelper.java b/src/main/java/org/mesdag/particlestorm/api/geckolib/GeckoLibHelper.java index 24f8951..f42d1a8 100644 --- a/src/main/java/org/mesdag/particlestorm/api/geckolib/GeckoLibHelper.java +++ b/src/main/java/org/mesdag/particlestorm/api/geckolib/GeckoLibHelper.java @@ -1,13 +1,22 @@ package org.mesdag.particlestorm.api.geckolib; import it.unimi.dsi.fastutil.ints.IntIterator; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.phys.Vec3; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.neoforge.client.event.EntityRenderersEvent; +import net.neoforged.neoforge.registries.DeferredHolder; +import net.neoforged.neoforge.registries.DeferredRegister; import org.joml.Vector3f; import org.mesdag.particlestorm.PSGameClient; +import org.mesdag.particlestorm.ParticleStorm; import org.mesdag.particlestorm.data.molang.MolangExp; import org.mesdag.particlestorm.data.molang.VariableTable; import org.mesdag.particlestorm.mixed.*; @@ -22,6 +31,22 @@ import java.util.List; public final class GeckoLibHelper { + public static DeferredHolder, BlockEntityType> TEST_ENTITY; + + public static void registerStuffs(IEventBus bus) { + DeferredRegister BLOCK = DeferredRegister.create(BuiltInRegistries.BLOCK, ParticleStorm.MODID); + DeferredRegister> ENTITY = DeferredRegister.create(BuiltInRegistries.BLOCK_ENTITY_TYPE, ParticleStorm.MODID); + DeferredHolder TEST = BLOCK.register("test_block", TestBlock::new); + TEST_ENTITY = ENTITY.register("test_entity", () -> BlockEntityType.Builder.of(TestBlock.Entity::new, TEST.get()).build(null)); + BLOCK.register(bus); + ENTITY.register(bus); + } + + public static void registerRenderers(EntityRenderersEvent.RegisterRenderers event) { + event.registerBlockEntityRenderer(GeckoLibHelper.TEST_ENTITY.get(), ExampleBlockEntityRenderer::new); + event.registerEntityRenderer(EntityType.CREEPER, ReplacedCreeperRenderer::new); + } + public static double[] getLocatorOffset(Object locatorValue) { LocatorValue value = (LocatorValue) locatorValue; if (value.locatorClass() == null) { diff --git a/src/main/java/org/mesdag/particlestorm/api/geckolib/TestBlock.java b/src/main/java/org/mesdag/particlestorm/api/geckolib/TestBlock.java index cbea6e0..a28ed1d 100644 --- a/src/main/java/org/mesdag/particlestorm/api/geckolib/TestBlock.java +++ b/src/main/java/org/mesdag/particlestorm/api/geckolib/TestBlock.java @@ -11,7 +11,6 @@ import net.minecraft.world.phys.shapes.Shapes; import net.minecraft.world.phys.shapes.VoxelShape; import org.jetbrains.annotations.Nullable; -import org.mesdag.particlestorm.ParticleStorm; import software.bernie.geckolib.animatable.GeoBlockEntity; import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache; import software.bernie.geckolib.animation.AnimatableManager; @@ -47,7 +46,7 @@ public static class Entity extends BlockEntity implements GeoBlockEntity { private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); public Entity(BlockPos pos, BlockState state) { - super(ParticleStorm.TEST_ENTITY.get(), pos, state); + super(GeckoLibHelper.TEST_ENTITY.get(), pos, state); } @Override diff --git a/src/main/java/org/mesdag/particlestorm/mixin/integration/geckolib/GeoBoneMixin.java b/src/main/java/org/mesdag/particlestorm/mixin/integration/geckolib/GeoBoneMixin.java index 434c99f..05c197e 100644 --- a/src/main/java/org/mesdag/particlestorm/mixin/integration/geckolib/GeoBoneMixin.java +++ b/src/main/java/org/mesdag/particlestorm/mixin/integration/geckolib/GeoBoneMixin.java @@ -2,7 +2,6 @@ import org.mesdag.particlestorm.mixed.IAnimatableInstanceCache; import org.mesdag.particlestorm.mixed.IGeoBone; -import org.mesdag.particlestorm.mixin.MolangQueriesAccessor; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Pseudo; import org.spongepowered.asm.mixin.Shadow; diff --git a/src/main/java/org/mesdag/particlestorm/mixin/MolangQueriesAccessor.java b/src/main/java/org/mesdag/particlestorm/mixin/integration/geckolib/MolangQueriesAccessor.java similarity index 62% rename from src/main/java/org/mesdag/particlestorm/mixin/MolangQueriesAccessor.java rename to src/main/java/org/mesdag/particlestorm/mixin/integration/geckolib/MolangQueriesAccessor.java index 4509622..d3e1f6a 100644 --- a/src/main/java/org/mesdag/particlestorm/mixin/MolangQueriesAccessor.java +++ b/src/main/java/org/mesdag/particlestorm/mixin/integration/geckolib/MolangQueriesAccessor.java @@ -1,10 +1,12 @@ -package org.mesdag.particlestorm.mixin; +package org.mesdag.particlestorm.mixin.integration.geckolib; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Pseudo; import org.spongepowered.asm.mixin.gen.Invoker; import software.bernie.geckolib.loading.math.MolangQueries; -@Mixin(MolangQueries.class) +@Pseudo +@Mixin(targets = "software.bernie.geckolib.loading.math.MolangQueries") public interface MolangQueriesAccessor { @Invoker static MolangQueries.Actor callGetActor() {throw new UnsupportedOperationException();} diff --git a/src/main/resources/particlestorm.mixins.json b/src/main/resources/particlestorm.mixins.json index bc94ae6..03e654f 100644 --- a/src/main/resources/particlestorm.mixins.json +++ b/src/main/resources/particlestorm.mixins.json @@ -5,7 +5,7 @@ "compatibilityLevel": "JAVA_17", "refmap": "particlestorm.refmap.json", "mixins": [ - "MolangQueriesAccessor" + "integration.geckolib.MolangQueriesAccessor" ], "client": [ "BlockEntityMixin",