From 5ec38d1945e651e0eb73423da9df951c7734179d Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Wed, 10 Apr 2024 14:37:55 +0100 Subject: [PATCH 01/19] Initial version --- .../access/ParticleMixinAccess.java | 8 ++ .../access/RegistryMixinAccess.java | 10 ++ .../clientizen/mixin/ParticleAccessor.java | 20 +++ .../mixin/ParticleManagerAccessor.java | 19 +++ .../clientizen/mixin/ParticleMixin.java | 34 +++++ .../clientizen/mixin/RegistryMixin.java | 102 +++++++++++++ .../objects/ClientizenObjectRegistry.java | 2 + .../clientizen/objects/ParticleTag.java | 133 +++++++++++++++++ .../ClientizenContainerRegistry.java | 1 + .../containers/ParticleScriptContainer.java | 136 ++++++++++++++++++ .../clientizen/util/impl/DenizenCoreImpl.java | 13 +- src/main/resources/clientizen.accesswidener | 1 + src/main/resources/clientizen.mixins.json | 9 +- 13 files changed, 482 insertions(+), 6 deletions(-) create mode 100644 src/main/java/com/denizenscript/clientizen/access/ParticleMixinAccess.java create mode 100644 src/main/java/com/denizenscript/clientizen/access/RegistryMixinAccess.java create mode 100644 src/main/java/com/denizenscript/clientizen/mixin/ParticleManagerAccessor.java create mode 100644 src/main/java/com/denizenscript/clientizen/mixin/ParticleMixin.java create mode 100644 src/main/java/com/denizenscript/clientizen/mixin/RegistryMixin.java create mode 100644 src/main/java/com/denizenscript/clientizen/objects/ParticleTag.java create mode 100644 src/main/java/com/denizenscript/clientizen/scripts/containers/ParticleScriptContainer.java diff --git a/src/main/java/com/denizenscript/clientizen/access/ParticleMixinAccess.java b/src/main/java/com/denizenscript/clientizen/access/ParticleMixinAccess.java new file mode 100644 index 0000000..ee7f850 --- /dev/null +++ b/src/main/java/com/denizenscript/clientizen/access/ParticleMixinAccess.java @@ -0,0 +1,8 @@ +package com.denizenscript.clientizen.access; + +import java.util.UUID; + +public interface ParticleMixinAccess { + + UUID clientizen$getUUID(); +} diff --git a/src/main/java/com/denizenscript/clientizen/access/RegistryMixinAccess.java b/src/main/java/com/denizenscript/clientizen/access/RegistryMixinAccess.java new file mode 100644 index 0000000..f550a52 --- /dev/null +++ b/src/main/java/com/denizenscript/clientizen/access/RegistryMixinAccess.java @@ -0,0 +1,10 @@ +package com.denizenscript.clientizen.access; + +import net.minecraft.util.Identifier; + +public interface RegistryMixinAccess { + + void clientizen$unfreeze(); + + void clientizen$remove(Identifier toRemove); +} diff --git a/src/main/java/com/denizenscript/clientizen/mixin/ParticleAccessor.java b/src/main/java/com/denizenscript/clientizen/mixin/ParticleAccessor.java index 3127930..1137e36 100644 --- a/src/main/java/com/denizenscript/clientizen/mixin/ParticleAccessor.java +++ b/src/main/java/com/denizenscript/clientizen/mixin/ParticleAccessor.java @@ -2,6 +2,7 @@ import net.minecraft.client.particle.Particle; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; import org.spongepowered.asm.mixin.gen.Invoker; @Mixin(Particle.class) @@ -9,4 +10,23 @@ public interface ParticleAccessor { @Invoker void invokeSetAlpha(float alpha); + + // MCDev plugin bug, need to specify the name in the annotation to avoid IDE errors + @Accessor("x") + double getX(); + + @Accessor("y") + double getY(); + + @Accessor("z") + double getZ(); + + @Accessor + double getVelocityX(); + + @Accessor + double getVelocityY(); + + @Accessor + double getVelocityZ(); } diff --git a/src/main/java/com/denizenscript/clientizen/mixin/ParticleManagerAccessor.java b/src/main/java/com/denizenscript/clientizen/mixin/ParticleManagerAccessor.java new file mode 100644 index 0000000..32185b9 --- /dev/null +++ b/src/main/java/com/denizenscript/clientizen/mixin/ParticleManagerAccessor.java @@ -0,0 +1,19 @@ +package com.denizenscript.clientizen.mixin; + +import net.minecraft.client.particle.ParticleManager; +import net.minecraft.client.texture.SpriteAtlasTexture; +import net.minecraft.util.Identifier; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.Map; + +@Mixin(ParticleManager.class) +public interface ParticleManagerAccessor { + + @Accessor("spriteAwareFactories") + Map getSpritesMap(); + + @Accessor("particleAtlasTexture") + SpriteAtlasTexture getParticlesAtlas(); +} diff --git a/src/main/java/com/denizenscript/clientizen/mixin/ParticleMixin.java b/src/main/java/com/denizenscript/clientizen/mixin/ParticleMixin.java new file mode 100644 index 0000000..3b140a0 --- /dev/null +++ b/src/main/java/com/denizenscript/clientizen/mixin/ParticleMixin.java @@ -0,0 +1,34 @@ +package com.denizenscript.clientizen.mixin; + +import com.denizenscript.clientizen.access.ParticleMixinAccess; +import com.denizenscript.clientizen.objects.ParticleTag; +import net.minecraft.client.particle.Particle; +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.UUID; + +@Mixin(Particle.class) +public abstract class ParticleMixin implements ParticleMixinAccess { + + @Unique + private final UUID clientizen$id = UUID.randomUUID(); + + @Inject(method = "(Lnet/minecraft/client/world/ClientWorld;DDD)V", at = @At("TAIL")) + private void clientizen$onParticleCreated(CallbackInfo ci) { + ParticleTag.particles.put(clientizen$id, (Particle) (Object) this); + } + + @Inject(method = "markDead", at = @At("TAIL")) + private void clientizen$onParticleRemoved(CallbackInfo ci) { + ParticleTag.particles.remove(clientizen$id); + } + + @Override + public UUID clientizen$getUUID() { + return clientizen$id; + } +} diff --git a/src/main/java/com/denizenscript/clientizen/mixin/RegistryMixin.java b/src/main/java/com/denizenscript/clientizen/mixin/RegistryMixin.java new file mode 100644 index 0000000..b6f58d6 --- /dev/null +++ b/src/main/java/com/denizenscript/clientizen/mixin/RegistryMixin.java @@ -0,0 +1,102 @@ +package com.denizenscript.clientizen.mixin; + +import com.denizenscript.clientizen.access.RegistryMixinAccess; +import com.denizenscript.denizencore.exceptions.InvalidArgumentsRuntimeException; +import com.mojang.serialization.Lifecycle; +import it.unimi.dsi.fastutil.objects.ObjectList; +import it.unimi.dsi.fastutil.objects.Reference2IntMap; +import net.minecraft.registry.Registry; +import net.minecraft.registry.RegistryKey; +import net.minecraft.registry.SimpleRegistry; +import net.minecraft.registry.entry.RegistryEntry; +import net.minecraft.util.Identifier; +import org.jetbrains.annotations.Nullable; +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.callback.CallbackInfo; + +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Map; + +@Mixin(SimpleRegistry.class) +public abstract class RegistryMixin implements RegistryMixinAccess { + + @Unique + boolean clientizen$isIntrusive; + + @Shadow + private boolean frozen; + + @Shadow + private @Nullable Map> intrusiveValueToEntry; + + @Shadow + public abstract RegistryKey> getKey(); + + @Shadow + public abstract @Nullable T get(@Nullable Identifier id); + + @Shadow + @Final + private ObjectList> rawIdToEntry; + + @Shadow + @Final + private Map> idToEntry; + + @Shadow + @Final + private Reference2IntMap entryToRawId; + + @Shadow + @Final + private Map, RegistryEntry.Reference> keyToEntry; + + @Shadow + @Final + private Map> valueToEntry; + + @Shadow + @Final + private Map entryToLifecycle; + + @Shadow + private @Nullable List> cachedEntries; + + @Inject(method = "(Lnet/minecraft/registry/RegistryKey;Lcom/mojang/serialization/Lifecycle;Z)V", at = @At("TAIL")) + private void clientizen$saveIsIntrusive(RegistryKey key, Lifecycle lifecycle, boolean intrusive, CallbackInfo ci) { + clientizen$isIntrusive = intrusive; + } + + @Override + public void clientizen$unfreeze() { + if (!frozen) { + return; + } + frozen = false; + if (clientizen$isIntrusive) { + intrusiveValueToEntry = new IdentityHashMap<>(); + } + } + + @Override + public void clientizen$remove(Identifier toRemove) { + RegistryEntry.Reference value = idToEntry.get(toRemove); + if (value == null) { + throw new InvalidArgumentsRuntimeException("Unable to remove '" + toRemove + "' from registry '" + getKey() + "': registry has no value by that key."); + } + RegistryKey key = RegistryKey.of(getKey(), toRemove); + keyToEntry.remove(key); + idToEntry.remove(toRemove); + valueToEntry.remove(value.value()); + rawIdToEntry.remove(value); + entryToRawId.removeInt(value.value()); + entryToLifecycle.remove(value.value()); + cachedEntries = null; + } +} diff --git a/src/main/java/com/denizenscript/clientizen/objects/ClientizenObjectRegistry.java b/src/main/java/com/denizenscript/clientizen/objects/ClientizenObjectRegistry.java index 37a25ac..5aa164e 100644 --- a/src/main/java/com/denizenscript/clientizen/objects/ClientizenObjectRegistry.java +++ b/src/main/java/com/denizenscript/clientizen/objects/ClientizenObjectRegistry.java @@ -10,6 +10,7 @@ public class ClientizenObjectRegistry { public static ObjectType TYPE_MATERIAL; public static ObjectType TYPE_ITEM; public static ObjectType TYPE_MOD; + public static ObjectType TYPE_PARTICLE; public static void registerObjects() { TYPE_ENTITY = ObjectFetcher.registerWithObjectFetcher(EntityTag.class, EntityTag.tagProcessor).setAsNOtherCode().generateBaseTag(); @@ -17,5 +18,6 @@ public static void registerObjects() { TYPE_MATERIAL = ObjectFetcher.registerWithObjectFetcher(MaterialTag.class, MaterialTag.tagProcessor).generateBaseTag(); TYPE_ITEM = ObjectFetcher.registerWithObjectFetcher(ItemTag.class, ItemTag.tagProcessor).setAsNOtherCode().generateBaseTag(); TYPE_MOD = ObjectFetcher.registerWithObjectFetcher(ModTag.class, ModTag.tagProcessor).setAsNOtherCode().setCanConvertStatic().generateBaseTag(); + TYPE_PARTICLE = ObjectFetcher.registerWithObjectFetcher(ParticleTag.class, ParticleTag.tagProcessor).setAsNOtherCode().generateBaseTag(); } } diff --git a/src/main/java/com/denizenscript/clientizen/objects/ParticleTag.java b/src/main/java/com/denizenscript/clientizen/objects/ParticleTag.java new file mode 100644 index 0000000..376a44b --- /dev/null +++ b/src/main/java/com/denizenscript/clientizen/objects/ParticleTag.java @@ -0,0 +1,133 @@ +package com.denizenscript.clientizen.objects; + +import com.denizenscript.clientizen.access.ParticleMixinAccess; +import com.denizenscript.clientizen.mixin.ParticleAccessor; +import com.denizenscript.clientizen.util.Utilities; +import com.denizenscript.denizencore.objects.Adjustable; +import com.denizenscript.denizencore.objects.Fetchable; +import com.denizenscript.denizencore.objects.Mechanism; +import com.denizenscript.denizencore.objects.ObjectTag; +import com.denizenscript.denizencore.tags.Attribute; +import com.denizenscript.denizencore.tags.ObjectTagProcessor; +import com.denizenscript.denizencore.tags.TagContext; +import com.denizenscript.denizencore.utilities.CoreUtilities; +import net.minecraft.client.particle.Particle; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +public class ParticleTag implements Adjustable { + + public static final Map particles = new HashMap<>(); + + @Fetchable("particle") + public static ParticleTag valueOf(String text, TagContext context) { + if (text.startsWith("particle@")) { + text = text.substring("particle@".length()); + } + UUID uuid = Utilities.uuidFromString(text); + if (uuid == null) { + Utilities.echoErrorByContext(context, "valueOf ParticleTag returning null: '" + text + "' isn't a valid UUID."); + return null; + } + Particle particle = particles.get(uuid); + if (particle == null) { + Utilities.echoErrorByContext(context, "valueOf ParticleTag returning null: UUID '" + uuid + "' is valid, but isn't matched to any particle."); + return null; + } + return new ParticleTag(particle); + } + + public static boolean matches(String text) { + if (text.startsWith("particle@")) { + return true; + } + return valueOf(text, CoreUtilities.noDebugContext) != null; + } + + public final Particle particle; + + public ParticleTag(Particle particle) { + this.particle = particle; + } + + public ParticleAccessor getAccessor() { + return (ParticleAccessor) particle; + } + + public static void register() { + tagProcessor.registerTag(LocationTag.class, "location", (attribute, object) -> { + ParticleAccessor particle = object.getAccessor(); + return new LocationTag(particle.getX(), particle.getY(), particle.getZ()); + }); + + tagProcessor.registerMechanism("location", false, LocationTag.class, (object, mechanism, input) -> { + object.particle.setPos(input.getX(), input.getY(), input.getZ()); + }); + + tagProcessor.registerTag(LocationTag.class, "velocity", (attribute, object) -> { + ParticleAccessor particle = object.getAccessor(); + return new LocationTag(particle.getVelocityX(), particle.getVelocityY(), particle.getVelocityZ()); + }); + + tagProcessor.registerMechanism("velocity", false, LocationTag.class, (object, mechanism, input) -> { + object.particle.setVelocity(input.getX(), input.getY(), input.getZ()); + }); + } + + public static final ObjectTagProcessor tagProcessor = new ObjectTagProcessor<>(); + + @Override + public ObjectTag getObjectAttribute(Attribute attribute) { + return tagProcessor.getObjectAttribute(this, attribute); + } + + @Override + public void adjust(Mechanism mechanism) { + tagProcessor.processMechanism(this, mechanism); + } + + @Override + public void applyProperty(Mechanism mechanism) { + mechanism.echoError("Cannot apply properties to a ParticleTag."); + } + + @Override + public boolean isUnique() { + return true; + } + + @Override + public String identify() { + return "particle@" + ((ParticleMixinAccess) particle).clientizen$getUUID(); + } + + @Override + public String identifySimple() { + return identify(); + } + + @Override + public String debuggable() { + return "particle@" + ((ParticleMixinAccess) particle).clientizen$getUUID(); + } + + @Override + public String toString() { + return identify(); + } + + String prefix; + + @Override + public String getPrefix() { + return prefix; + } + + @Override + public ObjectTag setPrefix(String prefix) { + this.prefix = prefix; + return this; + } +} diff --git a/src/main/java/com/denizenscript/clientizen/scripts/containers/ClientizenContainerRegistry.java b/src/main/java/com/denizenscript/clientizen/scripts/containers/ClientizenContainerRegistry.java index 22fd296..8d37b84 100644 --- a/src/main/java/com/denizenscript/clientizen/scripts/containers/ClientizenContainerRegistry.java +++ b/src/main/java/com/denizenscript/clientizen/scripts/containers/ClientizenContainerRegistry.java @@ -7,5 +7,6 @@ public class ClientizenContainerRegistry { public static void registerContainers() { ScriptRegistry._registerType("gui", GuiScriptContainer.class); + ScriptRegistry._registerType("particle", ParticleScriptContainer.class); } } diff --git a/src/main/java/com/denizenscript/clientizen/scripts/containers/ParticleScriptContainer.java b/src/main/java/com/denizenscript/clientizen/scripts/containers/ParticleScriptContainer.java new file mode 100644 index 0000000..6afe643 --- /dev/null +++ b/src/main/java/com/denizenscript/clientizen/scripts/containers/ParticleScriptContainer.java @@ -0,0 +1,136 @@ +package com.denizenscript.clientizen.scripts.containers; + +import com.denizenscript.clientizen.Clientizen; +import com.denizenscript.clientizen.access.RegistryMixinAccess; +import com.denizenscript.clientizen.mixin.ParticleManagerAccessor; +import com.denizenscript.clientizen.objects.LocationTag; +import com.denizenscript.clientizen.objects.ParticleTag; +import com.denizenscript.denizencore.DenizenCore; +import com.denizenscript.denizencore.objects.ObjectTag; +import com.denizenscript.denizencore.objects.core.ColorTag; +import com.denizenscript.denizencore.objects.core.DurationTag; +import com.denizenscript.denizencore.objects.core.ElementTag; +import com.denizenscript.denizencore.scripts.ScriptEntry; +import com.denizenscript.denizencore.scripts.containers.ScriptContainer; +import com.denizenscript.denizencore.scripts.queues.ContextSource; +import com.denizenscript.denizencore.utilities.CoreUtilities; +import com.denizenscript.denizencore.utilities.ScriptUtilities; +import com.denizenscript.denizencore.utilities.YamlConfiguration; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; +import net.fabricmc.fabric.api.client.particle.v1.ParticleFactoryRegistry; +import net.fabricmc.fabric.api.particle.v1.FabricParticleTypes; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.particle.*; +import net.minecraft.client.texture.Sprite; +import net.minecraft.client.texture.SpriteAtlasTexture; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.particle.DefaultParticleType; +import net.minecraft.registry.Registries; +import net.minecraft.registry.Registry; +import net.minecraft.util.Identifier; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class ParticleScriptContainer extends ScriptContainer { + + public static final List customParticles = new ArrayList<>(); + + public static void clearCustomParticles() { + RegistryMixinAccess particleRegistry = (RegistryMixinAccess) Registries.PARTICLE_TYPE; + particleRegistry.clientizen$unfreeze(); + for (ParticleScriptContainer particleScript : customParticles) { + particleRegistry.clientizen$remove(particleScript.getId()); + } + } + + public static void registerCustomParticles() { + if (MinecraftClient.getInstance().particleManager == null) { + ClientLifecycleEvents.CLIENT_STARTED.register(client -> ParticleScriptContainer.registerCustomParticles()); + return; + } + Map spritesMap = ((ParticleManagerAccessor) MinecraftClient.getInstance().particleManager).getSpritesMap(); + for (ParticleScriptContainer particleScript : customParticles) { + DefaultParticleType type = FabricParticleTypes.simple(); + Identifier particleId = particleScript.getId(); + Registry.register(Registries.PARTICLE_TYPE, particleId, type); + ParticleFactoryRegistry.getInstance().register(type, spriteProvider -> new ClientizenParticle.Factory(spriteProvider, particleScript)); + spritesMap.get(particleId).setSprites(particleScript.textures); + } + Registries.PARTICLE_TYPE.freeze(); + } + + public List textures; + public List tick; + + public ParticleScriptContainer(YamlConfiguration configurationSection, String scriptContainerName) { + super(configurationSection, scriptContainerName); + SpriteAtlasTexture particlesAtlas = (SpriteAtlasTexture) MinecraftClient.getInstance().getTextureManager().getTexture(SpriteAtlasTexture.PARTICLE_ATLAS_TEXTURE); + List textureInput = getStringList("textures", true); + textures = new ArrayList<>(textureInput.size()); + for (String texture : textureInput) { + Identifier textureId = Identifier.tryParse(texture); + if (textureId == null) { + Debug.echoError("Invalid texture id specified: " + texture + '.'); + continue; + } + Sprite sprite = particlesAtlas.getSprite(textureId); + if (sprite == null) { + Debug.echoError("Texture id '" + texture + "' is valid, but a texture with that id cannot be found."); + continue; + } + textures.add(sprite); + } + tick = getEntries(DenizenCore.implementation.getEmptyScriptEntryData(), "tick"); + customParticles.add(this); + } + + public Identifier getId() { + return Clientizen.id(CoreUtilities.toLowerCase(getName())); + } + + public static class ClientizenParticle extends SpriteBillboardParticle { + + SpriteProvider spriteProvider; + ParticleScriptContainer particleScript; + ContextSource.SimpleMap scriptContext; + + protected ClientizenParticle(ClientWorld world, double x, double y, double z, double velocityX, double velocityY, double velocityZ, SpriteProvider spriteProvider, ParticleScriptContainer particleScript) { + super(world, x, y, z, velocityX, velocityY, velocityZ); + this.spriteProvider = spriteProvider; + this.particleScript = particleScript; + this.scriptContext = new ContextSource.SimpleMap(); + scriptContext.contexts = Map.of("particle", new ParticleTag(this)); + setSprite(spriteProvider); + } + + @Override + public void tick() { + prevPosX = x; + prevPosY = y; + prevPosZ = z; + prevAngle = angle; + if (age++ >= maxAge) { + markDead(); + return; + } + ScriptUtilities.createAndStartQueueArbitrary(particleScript.getName() + "_TICK", particleScript.tick, DenizenCore.implementation.getEmptyScriptEntryData(), scriptContext, null); + } + + @Override + public ParticleTextureSheet getType() { + return ParticleTextureSheet.PARTICLE_SHEET_TRANSLUCENT; + } + + public record Factory(SpriteProvider spriteProvider, ParticleScriptContainer particleScript) implements ParticleFactory { + + @Override + public Particle createParticle(DefaultParticleType parameters, ClientWorld world, double x, double y, double z, double velocityX, double velocityY, double velocityZ) { + return new ClientizenParticle(world, x, y, z, velocityX, velocityY, velocityZ, spriteProvider, particleScript); + } + } + } +} diff --git a/src/main/java/com/denizenscript/clientizen/util/impl/DenizenCoreImpl.java b/src/main/java/com/denizenscript/clientizen/util/impl/DenizenCoreImpl.java index eb1fc7f..c99412c 100644 --- a/src/main/java/com/denizenscript/clientizen/util/impl/DenizenCoreImpl.java +++ b/src/main/java/com/denizenscript/clientizen/util/impl/DenizenCoreImpl.java @@ -3,6 +3,7 @@ import com.denizenscript.clientizen.Clientizen; import com.denizenscript.clientizen.debuggui.DebugConsole; import com.denizenscript.clientizen.objects.LocationTag; +import com.denizenscript.clientizen.scripts.containers.ParticleScriptContainer; import com.denizenscript.clientizen.tags.ClientTagBase; import com.denizenscript.clientizen.tags.ClientizenTagContext; import com.denizenscript.denizencore.DenizenImplementation; @@ -40,10 +41,14 @@ public String getImplementationName() { } @Override - public void preScriptReload() {} + public void preScriptReload() { + ParticleScriptContainer.clearCustomParticles(); + } @Override - public void onScriptReload() {} + public void onScriptReload() { + ParticleScriptContainer.registerCustomParticles(); + } @Override public String queueHeaderInfo(ScriptEntry scriptEntry) { @@ -61,7 +66,9 @@ public boolean handleCustomArgs(ScriptEntry scriptEntry, Argument argument) { } @Override - public void refreshScriptContainers() {} + public void refreshScriptContainers() { + ParticleScriptContainer.customParticles.clear(); + } @Override public TagContext getTagContext(ScriptContainer scriptContainer) { diff --git a/src/main/resources/clientizen.accesswidener b/src/main/resources/clientizen.accesswidener index 768b8c6..60d135a 100644 --- a/src/main/resources/clientizen.accesswidener +++ b/src/main/resources/clientizen.accesswidener @@ -1,3 +1,4 @@ accessWidener v2 named accessible class net/minecraft/client/gui/screen/pack/ExperimentalWarningScreen$DetailsScreen +accessible class net/minecraft/client/particle/ParticleManager$SimpleSpriteProvider diff --git a/src/main/resources/clientizen.mixins.json b/src/main/resources/clientizen.mixins.json index f3e9e5f..7be5b42 100644 --- a/src/main/resources/clientizen.mixins.json +++ b/src/main/resources/clientizen.mixins.json @@ -7,17 +7,20 @@ "client": [ "ClientPlayNetworkHandlerMixin", "ClientWorldAccessor", - "EntityRenderedMixin", "ClientWorldMixin", + "EntityRenderedMixin", "EventKeyBindingMixin", "IntPropertyAccessor", "LivingEntityMixin", "MinecraftClientMixin", + "ParticleAccessor", + "ParticleManagerAccessor", + "ParticleMixin", + "RegistryMixin", "SneakingKeyBindingMixin", "StickyKeyBindingAccessor", - "WorldRendererMixin", "WorldRendererAccessor", - "ParticleAccessor", + "WorldRendererMixin", "gui.WScrollPanelAccessor", "gui.WTextAccessor" ], From f24a63d9a6feeedc7582efc89c22109c569a21c8 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Thu, 11 Apr 2024 13:30:37 +0100 Subject: [PATCH 02/19] More texture-related features --- .../access/ParticleMixinAccess.java | 6 ++ .../{ => particle}/ParticleAccessor.java | 2 +- .../ParticleManagerAccessor.java | 8 +- .../mixin/particle/ParticleManagerMixin.java | 21 +++++ .../mixin/{ => particle}/ParticleMixin.java | 18 +++- .../SpriteBillboardParticleAccessor.java | 17 ++++ .../clientizen/objects/ParticleTag.java | 83 ++++++++++++++++++- .../scripts/commands/ParticleCommand.java | 2 +- .../containers/ParticleScriptContainer.java | 13 +-- src/main/resources/clientizen.mixins.json | 10 ++- 10 files changed, 154 insertions(+), 26 deletions(-) rename src/main/java/com/denizenscript/clientizen/mixin/{ => particle}/ParticleAccessor.java (92%) rename src/main/java/com/denizenscript/clientizen/mixin/{ => particle}/ParticleManagerAccessor.java (66%) create mode 100644 src/main/java/com/denizenscript/clientizen/mixin/particle/ParticleManagerMixin.java rename src/main/java/com/denizenscript/clientizen/mixin/{ => particle}/ParticleMixin.java (70%) create mode 100644 src/main/java/com/denizenscript/clientizen/mixin/particle/SpriteBillboardParticleAccessor.java diff --git a/src/main/java/com/denizenscript/clientizen/access/ParticleMixinAccess.java b/src/main/java/com/denizenscript/clientizen/access/ParticleMixinAccess.java index ee7f850..ef399c0 100644 --- a/src/main/java/com/denizenscript/clientizen/access/ParticleMixinAccess.java +++ b/src/main/java/com/denizenscript/clientizen/access/ParticleMixinAccess.java @@ -1,8 +1,14 @@ package com.denizenscript.clientizen.access; +import net.minecraft.particle.ParticleType; + import java.util.UUID; public interface ParticleMixinAccess { UUID clientizen$getUUID(); + + ParticleType clientizen$getType(); + + void clientizen$setType(ParticleType type); } diff --git a/src/main/java/com/denizenscript/clientizen/mixin/ParticleAccessor.java b/src/main/java/com/denizenscript/clientizen/mixin/particle/ParticleAccessor.java similarity index 92% rename from src/main/java/com/denizenscript/clientizen/mixin/ParticleAccessor.java rename to src/main/java/com/denizenscript/clientizen/mixin/particle/ParticleAccessor.java index 1137e36..52f168b 100644 --- a/src/main/java/com/denizenscript/clientizen/mixin/ParticleAccessor.java +++ b/src/main/java/com/denizenscript/clientizen/mixin/particle/ParticleAccessor.java @@ -1,4 +1,4 @@ -package com.denizenscript.clientizen.mixin; +package com.denizenscript.clientizen.mixin.particle; import net.minecraft.client.particle.Particle; import org.spongepowered.asm.mixin.Mixin; diff --git a/src/main/java/com/denizenscript/clientizen/mixin/ParticleManagerAccessor.java b/src/main/java/com/denizenscript/clientizen/mixin/particle/ParticleManagerAccessor.java similarity index 66% rename from src/main/java/com/denizenscript/clientizen/mixin/ParticleManagerAccessor.java rename to src/main/java/com/denizenscript/clientizen/mixin/particle/ParticleManagerAccessor.java index 32185b9..1d72735 100644 --- a/src/main/java/com/denizenscript/clientizen/mixin/ParticleManagerAccessor.java +++ b/src/main/java/com/denizenscript/clientizen/mixin/particle/ParticleManagerAccessor.java @@ -1,7 +1,6 @@ -package com.denizenscript.clientizen.mixin; +package com.denizenscript.clientizen.mixin.particle; import net.minecraft.client.particle.ParticleManager; -import net.minecraft.client.texture.SpriteAtlasTexture; import net.minecraft.util.Identifier; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; @@ -12,8 +11,5 @@ public interface ParticleManagerAccessor { @Accessor("spriteAwareFactories") - Map getSpritesMap(); - - @Accessor("particleAtlasTexture") - SpriteAtlasTexture getParticlesAtlas(); + Map getSpriteProviderMap(); } diff --git a/src/main/java/com/denizenscript/clientizen/mixin/particle/ParticleManagerMixin.java b/src/main/java/com/denizenscript/clientizen/mixin/particle/ParticleManagerMixin.java new file mode 100644 index 0000000..8b8c798 --- /dev/null +++ b/src/main/java/com/denizenscript/clientizen/mixin/particle/ParticleManagerMixin.java @@ -0,0 +1,21 @@ +package com.denizenscript.clientizen.mixin.particle; + +import com.denizenscript.clientizen.access.ParticleMixinAccess; +import net.minecraft.client.particle.Particle; +import net.minecraft.client.particle.ParticleManager; +import net.minecraft.particle.ParticleEffect; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(ParticleManager.class) +public abstract class ParticleManagerMixin { + + @Inject(method = "createParticle", at = @At("RETURN")) + private void clientizen$storeParticleType(T parameters, double x, double y, double z, double velocityX, double velocityY, double velocityZ, CallbackInfoReturnable cir) { + if (cir.getReturnValue() instanceof ParticleMixinAccess particle) { + particle.clientizen$setType(parameters.getType()); + } + } +} diff --git a/src/main/java/com/denizenscript/clientizen/mixin/ParticleMixin.java b/src/main/java/com/denizenscript/clientizen/mixin/particle/ParticleMixin.java similarity index 70% rename from src/main/java/com/denizenscript/clientizen/mixin/ParticleMixin.java rename to src/main/java/com/denizenscript/clientizen/mixin/particle/ParticleMixin.java index 3b140a0..c8cc5fb 100644 --- a/src/main/java/com/denizenscript/clientizen/mixin/ParticleMixin.java +++ b/src/main/java/com/denizenscript/clientizen/mixin/particle/ParticleMixin.java @@ -1,8 +1,9 @@ -package com.denizenscript.clientizen.mixin; +package com.denizenscript.clientizen.mixin.particle; import com.denizenscript.clientizen.access.ParticleMixinAccess; import com.denizenscript.clientizen.objects.ParticleTag; import net.minecraft.client.particle.Particle; +import net.minecraft.particle.ParticleType; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; @@ -15,7 +16,10 @@ public abstract class ParticleMixin implements ParticleMixinAccess { @Unique - private final UUID clientizen$id = UUID.randomUUID(); + final UUID clientizen$id = UUID.randomUUID(); + + @Unique + ParticleType clientizen$particleType; @Inject(method = "(Lnet/minecraft/client/world/ClientWorld;DDD)V", at = @At("TAIL")) private void clientizen$onParticleCreated(CallbackInfo ci) { @@ -31,4 +35,14 @@ public abstract class ParticleMixin implements ParticleMixinAccess { public UUID clientizen$getUUID() { return clientizen$id; } + + @Override + public ParticleType clientizen$getType() { + return clientizen$particleType; + } + + @Override + public void clientizen$setType(ParticleType type) { + clientizen$particleType = type; + } } diff --git a/src/main/java/com/denizenscript/clientizen/mixin/particle/SpriteBillboardParticleAccessor.java b/src/main/java/com/denizenscript/clientizen/mixin/particle/SpriteBillboardParticleAccessor.java new file mode 100644 index 0000000..ba4ab5b --- /dev/null +++ b/src/main/java/com/denizenscript/clientizen/mixin/particle/SpriteBillboardParticleAccessor.java @@ -0,0 +1,17 @@ +package com.denizenscript.clientizen.mixin.particle; + +import net.minecraft.client.particle.SpriteBillboardParticle; +import net.minecraft.client.texture.Sprite; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(SpriteBillboardParticle.class) +public interface SpriteBillboardParticleAccessor { + + @Accessor + Sprite getSprite(); + + @Invoker + void invokeSetSprite(Sprite sprite); +} diff --git a/src/main/java/com/denizenscript/clientizen/objects/ParticleTag.java b/src/main/java/com/denizenscript/clientizen/objects/ParticleTag.java index 376a44b..37d9c0e 100644 --- a/src/main/java/com/denizenscript/clientizen/objects/ParticleTag.java +++ b/src/main/java/com/denizenscript/clientizen/objects/ParticleTag.java @@ -1,17 +1,27 @@ package com.denizenscript.clientizen.objects; import com.denizenscript.clientizen.access.ParticleMixinAccess; -import com.denizenscript.clientizen.mixin.ParticleAccessor; +import com.denizenscript.clientizen.mixin.particle.ParticleAccessor; +import com.denizenscript.clientizen.mixin.particle.ParticleManagerAccessor; +import com.denizenscript.clientizen.mixin.particle.SpriteBillboardParticleAccessor; import com.denizenscript.clientizen.util.Utilities; import com.denizenscript.denizencore.objects.Adjustable; import com.denizenscript.denizencore.objects.Fetchable; import com.denizenscript.denizencore.objects.Mechanism; import com.denizenscript.denizencore.objects.ObjectTag; +import com.denizenscript.denizencore.objects.core.ElementTag; import com.denizenscript.denizencore.tags.Attribute; import com.denizenscript.denizencore.tags.ObjectTagProcessor; import com.denizenscript.denizencore.tags.TagContext; import com.denizenscript.denizencore.utilities.CoreUtilities; +import net.minecraft.client.MinecraftClient; import net.minecraft.client.particle.Particle; +import net.minecraft.client.particle.ParticleManager; +import net.minecraft.client.particle.SpriteBillboardParticle; +import net.minecraft.client.texture.Sprite; +import net.minecraft.client.texture.SpriteAtlasTexture; +import net.minecraft.registry.Registries; +import net.minecraft.util.Identifier; import java.util.HashMap; import java.util.Map; @@ -21,6 +31,14 @@ public class ParticleTag implements Adjustable { public static final Map particles = new HashMap<>(); + public static SpriteAtlasTexture getParticleAtlas() { + return (SpriteAtlasTexture) MinecraftClient.getInstance().getTextureManager().getTexture(SpriteAtlasTexture.PARTICLE_ATLAS_TEXTURE); + } + + public static Map getSpriteProviders() { + return ((ParticleManagerAccessor) MinecraftClient.getInstance().particleManager).getSpriteProviderMap(); + } + @Fetchable("particle") public static ParticleTag valueOf(String text, TagContext context) { if (text.startsWith("particle@")) { @@ -56,7 +74,23 @@ public ParticleAccessor getAccessor() { return (ParticleAccessor) particle; } + public ParticleMixinAccess getMixinAccess() { + return (ParticleMixinAccess) particle; + } + + public Identifier getTypeId() { + return Registries.PARTICLE_TYPE.getId(getMixinAccess().clientizen$getType()); + } + + public String getTypeString() { + return Utilities.idToString(getTypeId()); + } + public static void register() { + tagProcessor.registerTag(ElementTag.class, "type", (attribute, object) -> { + return new ElementTag(object.getTypeString(), true); + }); + tagProcessor.registerTag(LocationTag.class, "location", (attribute, object) -> { ParticleAccessor particle = object.getAccessor(); return new LocationTag(particle.getX(), particle.getY(), particle.getZ()); @@ -74,6 +108,49 @@ public static void register() { tagProcessor.registerMechanism("velocity", false, LocationTag.class, (object, mechanism, input) -> { object.particle.setVelocity(input.getX(), input.getY(), input.getZ()); }); + + tagProcessor.registerTag(ElementTag.class, "texture", (attribute, object) -> { + if (object.particle instanceof SpriteBillboardParticleAccessor spriteParticle) { + return new ElementTag(Utilities.idToString(spriteParticle.getSprite().getContents().getId()), true); + } + return null; + }); + + tagProcessor.registerMechanism("texture", false, ElementTag.class, (object, mechanism, input) -> { + if (!(object.particle instanceof SpriteBillboardParticleAccessor spriteParticle)) { + mechanism.echoError("Cannot set texture: particles of type '" + object.getTypeString() + "' don't support textures."); + return; + } + Identifier texture = Identifier.tryParse(input.asString()); + if (texture == null) { + mechanism.echoError("Invalid texture id specified: " + input + '.'); + return; + } + Sprite sprite = getParticleAtlas().getSprite(texture); + if (sprite == null) { + mechanism.echoError("Texture id '" + input + "' is valid, but doesn't match any texture."); + return; + } + spriteParticle.invokeSetSprite(sprite); + }); + + tagProcessor.registerMechanism("randomize_texture", false, (object, mechanism) -> { + if (!(object.particle instanceof SpriteBillboardParticle spriteParticle)) { + mechanism.echoError("Cannot randomize texture: particles of type '" + object.getTypeString() + "' don't have textures."); + return; + } + ParticleManager.SimpleSpriteProvider spriteProvider = getSpriteProviders().get(object.getTypeId()); + spriteParticle.setSprite(spriteProvider); + }); + + tagProcessor.registerMechanism("update_age_texture", false, (object, mechanism) -> { + if (!(object.particle instanceof SpriteBillboardParticle spriteParticle)) { + mechanism.echoError("Cannot update texture for age: particles of type '" + object.getTypeString() + "' don't have textures."); + return; + } + ParticleManager.SimpleSpriteProvider spriteProvider = getSpriteProviders().get(object.getTypeId()); + spriteParticle.setSpriteForAge(spriteProvider); + }); } public static final ObjectTagProcessor tagProcessor = new ObjectTagProcessor<>(); @@ -100,7 +177,7 @@ public boolean isUnique() { @Override public String identify() { - return "particle@" + ((ParticleMixinAccess) particle).clientizen$getUUID(); + return "particle@" + getMixinAccess().clientizen$getUUID(); } @Override @@ -110,7 +187,7 @@ public String identifySimple() { @Override public String debuggable() { - return "particle@" + ((ParticleMixinAccess) particle).clientizen$getUUID(); + return "particle@" + getMixinAccess().clientizen$getUUID() + " (" + getTypeString() + ")"; } @Override diff --git a/src/main/java/com/denizenscript/clientizen/scripts/commands/ParticleCommand.java b/src/main/java/com/denizenscript/clientizen/scripts/commands/ParticleCommand.java index 10577c3..074a28e 100644 --- a/src/main/java/com/denizenscript/clientizen/scripts/commands/ParticleCommand.java +++ b/src/main/java/com/denizenscript/clientizen/scripts/commands/ParticleCommand.java @@ -1,6 +1,6 @@ package com.denizenscript.clientizen.scripts.commands; -import com.denizenscript.clientizen.mixin.ParticleAccessor; +import com.denizenscript.clientizen.mixin.particle.ParticleAccessor; import com.denizenscript.clientizen.mixin.WorldRendererAccessor; import com.denizenscript.clientizen.objects.EntityTag; import com.denizenscript.clientizen.objects.ItemTag; diff --git a/src/main/java/com/denizenscript/clientizen/scripts/containers/ParticleScriptContainer.java b/src/main/java/com/denizenscript/clientizen/scripts/containers/ParticleScriptContainer.java index 6afe643..0d37ba4 100644 --- a/src/main/java/com/denizenscript/clientizen/scripts/containers/ParticleScriptContainer.java +++ b/src/main/java/com/denizenscript/clientizen/scripts/containers/ParticleScriptContainer.java @@ -2,14 +2,9 @@ import com.denizenscript.clientizen.Clientizen; import com.denizenscript.clientizen.access.RegistryMixinAccess; -import com.denizenscript.clientizen.mixin.ParticleManagerAccessor; -import com.denizenscript.clientizen.objects.LocationTag; +import com.denizenscript.clientizen.mixin.particle.ParticleManagerAccessor; import com.denizenscript.clientizen.objects.ParticleTag; import com.denizenscript.denizencore.DenizenCore; -import com.denizenscript.denizencore.objects.ObjectTag; -import com.denizenscript.denizencore.objects.core.ColorTag; -import com.denizenscript.denizencore.objects.core.DurationTag; -import com.denizenscript.denizencore.objects.core.ElementTag; import com.denizenscript.denizencore.scripts.ScriptEntry; import com.denizenscript.denizencore.scripts.containers.ScriptContainer; import com.denizenscript.denizencore.scripts.queues.ContextSource; @@ -29,7 +24,6 @@ import net.minecraft.registry.Registries; import net.minecraft.registry.Registry; import net.minecraft.util.Identifier; -import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; @@ -52,7 +46,7 @@ public static void registerCustomParticles() { ClientLifecycleEvents.CLIENT_STARTED.register(client -> ParticleScriptContainer.registerCustomParticles()); return; } - Map spritesMap = ((ParticleManagerAccessor) MinecraftClient.getInstance().particleManager).getSpritesMap(); + Map spritesMap = ParticleTag.getSpriteProviders(); for (ParticleScriptContainer particleScript : customParticles) { DefaultParticleType type = FabricParticleTypes.simple(); Identifier particleId = particleScript.getId(); @@ -68,7 +62,7 @@ public static void registerCustomParticles() { public ParticleScriptContainer(YamlConfiguration configurationSection, String scriptContainerName) { super(configurationSection, scriptContainerName); - SpriteAtlasTexture particlesAtlas = (SpriteAtlasTexture) MinecraftClient.getInstance().getTextureManager().getTexture(SpriteAtlasTexture.PARTICLE_ATLAS_TEXTURE); + SpriteAtlasTexture particlesAtlas = ParticleTag.getParticleAtlas(); List textureInput = getStringList("textures", true); textures = new ArrayList<>(textureInput.size()); for (String texture : textureInput) { @@ -117,6 +111,7 @@ public void tick() { markDead(); return; } + move(this.velocityX, this.velocityY, this.velocityZ); ScriptUtilities.createAndStartQueueArbitrary(particleScript.getName() + "_TICK", particleScript.tick, DenizenCore.implementation.getEmptyScriptEntryData(), scriptContext, null); } diff --git a/src/main/resources/clientizen.mixins.json b/src/main/resources/clientizen.mixins.json index 7be5b42..cdee21d 100644 --- a/src/main/resources/clientizen.mixins.json +++ b/src/main/resources/clientizen.mixins.json @@ -13,16 +13,18 @@ "IntPropertyAccessor", "LivingEntityMixin", "MinecraftClientMixin", - "ParticleAccessor", - "ParticleManagerAccessor", - "ParticleMixin", "RegistryMixin", "SneakingKeyBindingMixin", "StickyKeyBindingAccessor", "WorldRendererAccessor", "WorldRendererMixin", "gui.WScrollPanelAccessor", - "gui.WTextAccessor" + "gui.WTextAccessor", + "particle.ParticleAccessor", + "particle.ParticleManagerAccessor", + "particle.ParticleManagerMixin", + "particle.ParticleMixin", + "particle.SpriteBillboardParticleAccessor" ], "injectors": { "defaultRequire": 1 From 4de9fea5c59642aeee9ef7a119c740f716acd97d Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Thu, 11 Apr 2024 15:47:15 +0100 Subject: [PATCH 03/19] Particle scripts in particle command --- .../scripts/commands/ParticleCommand.java | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/denizenscript/clientizen/scripts/commands/ParticleCommand.java b/src/main/java/com/denizenscript/clientizen/scripts/commands/ParticleCommand.java index 074a28e..97e74dc 100644 --- a/src/main/java/com/denizenscript/clientizen/scripts/commands/ParticleCommand.java +++ b/src/main/java/com/denizenscript/clientizen/scripts/commands/ParticleCommand.java @@ -1,12 +1,13 @@ package com.denizenscript.clientizen.scripts.commands; -import com.denizenscript.clientizen.mixin.particle.ParticleAccessor; +import com.denizenscript.clientizen.Clientizen; import com.denizenscript.clientizen.mixin.WorldRendererAccessor; +import com.denizenscript.clientizen.mixin.particle.ParticleAccessor; import com.denizenscript.clientizen.objects.EntityTag; import com.denizenscript.clientizen.objects.ItemTag; import com.denizenscript.clientizen.objects.LocationTag; import com.denizenscript.clientizen.objects.MaterialTag; -import com.denizenscript.clientizen.util.Utilities; +import com.denizenscript.clientizen.scripts.containers.ParticleScriptContainer; import com.denizenscript.denizencore.exceptions.InvalidArgumentsRuntimeException; import com.denizenscript.denizencore.objects.ObjectTag; import com.denizenscript.denizencore.objects.core.ColorTag; @@ -14,6 +15,7 @@ import com.denizenscript.denizencore.objects.core.ElementTag; import com.denizenscript.denizencore.objects.core.MapTag; import com.denizenscript.denizencore.scripts.ScriptEntry; +import com.denizenscript.denizencore.scripts.ScriptRegistry; import com.denizenscript.denizencore.scripts.commands.AbstractCommand; import com.denizenscript.denizencore.scripts.commands.generator.ArgDefaultNull; import com.denizenscript.denizencore.scripts.commands.generator.ArgName; @@ -46,7 +48,7 @@ public class ParticleCommand extends AbstractCommand { // // @Description // Spawns a particle of the specified type in the world. - // The type can be any particle type, including ones added by other mods - see <@link url https://minecraft.wiki/w/Particles_(Java_Edition)#Types_of_particles> for all vanilla particle types. + // The type can be any particle type/script, including ones added by other mods - see <@link url https://minecraft.wiki/w/Particles_(Java_Edition)#Types_of_particles> for all vanilla particle types. // The location can be any location to play the particle at. // The velocity is a vector location for the particle's movement, which overrides its default movement (if any). // The color will override the particle's color or color its texture (depending on the particle), and can be any color. @@ -104,7 +106,8 @@ public ParticleCommand() { @Override public void addCustomTabCompletions(TabCompletionsBuilder tab) { - tab.addWithPrefix("type:", Utilities.listRegistryKeys(Registries.PARTICLE_TYPE)); + tab.addWithPrefix("type:", Registries.PARTICLE_TYPE.getIds().stream() + .map(id -> id.getNamespace().equals(Identifier.DEFAULT_NAMESPACE) || id.getNamespace().equals(Clientizen.ID) ? id.getPath() : id.toString()).toList()); } public static void autoExecute(ScriptEntry scriptEntry, @@ -118,8 +121,12 @@ public static void autoExecute(ScriptEntry scriptEntry, @ArgName("raw_data") @ArgPrefixed @ArgDefaultNull String rawData) { ParticleType type = Registries.PARTICLE_TYPE.get(Identifier.tryParse(particleName)); if (type == null) { - Debug.echoError("Invalid particle type specified: " + particleName + '.'); - return; + ParticleScriptContainer particleScript = ScriptRegistry.getScriptContainerAs(particleName, ParticleScriptContainer.class); + if (particleScript == null) { + Debug.echoError("Invalid particle type specified: " + particleName + '.'); + return; + } + type = Registries.PARTICLE_TYPE.get(particleScript.getId()); } ParticleEffect particle; if (rawData != null) { From e251409f4adfa4b31492452e3cd76e53ff8dd69e Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Fri, 12 Apr 2024 11:21:37 +0100 Subject: [PATCH 04/19] More tags/mechanisms --- .../mixin/particle/ParticleAccessor.java | 33 ++++++++++-- .../clientizen/objects/ParticleTag.java | 52 +++++++++++++++++++ 2 files changed, 82 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/denizenscript/clientizen/mixin/particle/ParticleAccessor.java b/src/main/java/com/denizenscript/clientizen/mixin/particle/ParticleAccessor.java index 52f168b..eb514e3 100644 --- a/src/main/java/com/denizenscript/clientizen/mixin/particle/ParticleAccessor.java +++ b/src/main/java/com/denizenscript/clientizen/mixin/particle/ParticleAccessor.java @@ -8,9 +8,6 @@ @Mixin(Particle.class) public interface ParticleAccessor { - @Invoker - void invokeSetAlpha(float alpha); - // MCDev plugin bug, need to specify the name in the annotation to avoid IDE errors @Accessor("x") double getX(); @@ -29,4 +26,34 @@ public interface ParticleAccessor { @Accessor double getVelocityZ(); + + @Accessor + float getRed(); + + @Accessor + float getGreen(); + + @Accessor + float getBlue(); + + @Accessor + float getAlpha(); + + @Invoker + void invokeSetAlpha(float alpha); + + @Accessor + boolean isOnGround(); + + @Accessor("collidesWithWorld") + boolean collidesWithWorld(); + + @Accessor + void setCollidesWithWorld(boolean collidesWithWorld); + + @Accessor + int getAge(); + + @Accessor + void setAge(int age); } diff --git a/src/main/java/com/denizenscript/clientizen/objects/ParticleTag.java b/src/main/java/com/denizenscript/clientizen/objects/ParticleTag.java index 37d9c0e..fc294e5 100644 --- a/src/main/java/com/denizenscript/clientizen/objects/ParticleTag.java +++ b/src/main/java/com/denizenscript/clientizen/objects/ParticleTag.java @@ -9,6 +9,8 @@ import com.denizenscript.denizencore.objects.Fetchable; import com.denizenscript.denizencore.objects.Mechanism; import com.denizenscript.denizencore.objects.ObjectTag; +import com.denizenscript.denizencore.objects.core.ColorTag; +import com.denizenscript.denizencore.objects.core.DurationTag; import com.denizenscript.denizencore.objects.core.ElementTag; import com.denizenscript.denizencore.tags.Attribute; import com.denizenscript.denizencore.tags.ObjectTagProcessor; @@ -134,6 +136,46 @@ public static void register() { spriteParticle.invokeSetSprite(sprite); }); + tagProcessor.registerTag(ColorTag.class, "color", (attribute, object) -> { + ParticleAccessor particle = object.getAccessor(); + return new ColorTag((int) (particle.getRed() * 255f), (int) (particle.getGreen() * 255f), (int) (particle.getBlue() * 255f), (int) (particle.getAlpha() * 255f)); + }); + + tagProcessor.registerMechanism("color", false, ColorTag.class, (object, mechanism, input) -> { + object.particle.setColor(input.red / 255f, input.green / 255f, input.blue / 255f); + object.getAccessor().invokeSetAlpha(input.alpha / 255f); + }); + + tagProcessor.registerTag(ElementTag.class, "world_collision", (attribute, object) -> { + return new ElementTag(object.getAccessor().collidesWithWorld()); + }); + + tagProcessor.registerMechanism("world_collision", false, ElementTag.class, (object, mechanism, input) -> { + if (mechanism.requireBoolean()) { + object.getAccessor().setCollidesWithWorld(input.asBoolean()); + } + }); + + tagProcessor.registerTag(DurationTag.class, "time_lived", (attribute, object) -> { + return new DurationTag((long) object.getAccessor().getAge()); + }); + + tagProcessor.registerMechanism("time_lived", false, DurationTag.class, (object, mechanism, input) -> { + object.getAccessor().setAge(input.getTicksAsInt()); + }); + + tagProcessor.registerTag(DurationTag.class, "time_to_live", (attribute, object) -> { + return new DurationTag((long) object.particle.getMaxAge()); + }); + + tagProcessor.registerMechanism("time_to_live", false, DurationTag.class, (object, mechanism, input) -> { + object.particle.setMaxAge(input.getTicksAsInt()); + }); + + tagProcessor.registerTag(ElementTag.class, "on_ground", (attribute, object) -> { + return new ElementTag(object.getAccessor().isOnGround()); + }); + tagProcessor.registerMechanism("randomize_texture", false, (object, mechanism) -> { if (!(object.particle instanceof SpriteBillboardParticle spriteParticle)) { mechanism.echoError("Cannot randomize texture: particles of type '" + object.getTypeString() + "' don't have textures."); @@ -151,6 +193,16 @@ public static void register() { ParticleManager.SimpleSpriteProvider spriteProvider = getSpriteProviders().get(object.getTypeId()); spriteParticle.setSpriteForAge(spriteProvider); }); + + tagProcessor.registerMechanism("multiply_scale", false, ElementTag.class, (object, mechanism, input) -> { + if (mechanism.requireFloat()) { + object.particle.scale(input.asFloat()); + } + }); + + tagProcessor.registerMechanism("remove", false, (object, mechanism) -> { + object.particle.markDead(); + }); } public static final ObjectTagProcessor tagProcessor = new ObjectTagProcessor<>(); From da781d5e196dfe6e98eac7d43420dd3d93de269f Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Fri, 12 Apr 2024 12:45:37 +0100 Subject: [PATCH 05/19] `tick` -> `update`, `update_rate`, error context --- .../containers/ParticleScriptContainer.java | 33 ++++++++++++++----- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/denizenscript/clientizen/scripts/containers/ParticleScriptContainer.java b/src/main/java/com/denizenscript/clientizen/scripts/containers/ParticleScriptContainer.java index 0d37ba4..a96c379 100644 --- a/src/main/java/com/denizenscript/clientizen/scripts/containers/ParticleScriptContainer.java +++ b/src/main/java/com/denizenscript/clientizen/scripts/containers/ParticleScriptContainer.java @@ -2,9 +2,10 @@ import com.denizenscript.clientizen.Clientizen; import com.denizenscript.clientizen.access.RegistryMixinAccess; -import com.denizenscript.clientizen.mixin.particle.ParticleManagerAccessor; import com.denizenscript.clientizen.objects.ParticleTag; +import com.denizenscript.clientizen.scripts.containers.gui.GuiScriptContainer; import com.denizenscript.denizencore.DenizenCore; +import com.denizenscript.denizencore.objects.core.DurationTag; import com.denizenscript.denizencore.scripts.ScriptEntry; import com.denizenscript.denizencore.scripts.containers.ScriptContainer; import com.denizenscript.denizencore.scripts.queues.ContextSource; @@ -57,11 +58,13 @@ public static void registerCustomParticles() { Registries.PARTICLE_TYPE.freeze(); } - public List textures; - public List tick; + public final List textures; + public final List updateScript; + public long updateRate; public ParticleScriptContainer(YamlConfiguration configurationSection, String scriptContainerName) { super(configurationSection, scriptContainerName); + Debug.pushErrorContext(this); SpriteAtlasTexture particlesAtlas = ParticleTag.getParticleAtlas(); List textureInput = getStringList("textures", true); textures = new ArrayList<>(textureInput.size()); @@ -78,8 +81,13 @@ public ParticleScriptContainer(YamlConfiguration configurationSection, String sc } textures.add(sprite); } - tick = getEntries(DenizenCore.implementation.getEmptyScriptEntryData(), "tick"); + updateScript = getEntries(DenizenCore.implementation.getEmptyScriptEntryData(), "update"); + DurationTag rateDuration = GuiScriptContainer.getTaggedObject(DurationTag.class, configurationSection, "update_rate", DenizenCore.implementation.getTagContext(this)); + if (rateDuration != null) { + updateRate = rateDuration.getMillis(); + } customParticles.add(this); + Debug.popErrorContext(); } public Identifier getId() { @@ -91,6 +99,7 @@ public static class ClientizenParticle extends SpriteBillboardParticle { SpriteProvider spriteProvider; ParticleScriptContainer particleScript; ContextSource.SimpleMap scriptContext; + long lastUpdateTime; protected ClientizenParticle(ClientWorld world, double x, double y, double z, double velocityX, double velocityY, double velocityZ, SpriteProvider spriteProvider, ParticleScriptContainer particleScript) { super(world, x, y, z, velocityX, velocityY, velocityZ); @@ -103,16 +112,24 @@ protected ClientizenParticle(ClientWorld world, double x, double y, double z, do @Override public void tick() { + if (age++ >= maxAge) { + markDead(); + return; + } prevPosX = x; prevPosY = y; prevPosZ = z; prevAngle = angle; - if (age++ >= maxAge) { - markDead(); + move(this.velocityX, this.velocityY, this.velocityZ); + if (particleScript.updateScript == null) { return; } - move(this.velocityX, this.velocityY, this.velocityZ); - ScriptUtilities.createAndStartQueueArbitrary(particleScript.getName() + "_TICK", particleScript.tick, DenizenCore.implementation.getEmptyScriptEntryData(), scriptContext, null); + long currentTime = DenizenCore.currentTimeMillis; + if (currentTime - lastUpdateTime < particleScript.updateRate) { + return; + } + lastUpdateTime = currentTime; + ScriptUtilities.createAndStartQueueArbitrary(particleScript.getName() + "_UPDATE", particleScript.updateScript, null, scriptContext, null); } @Override From 1249ee7c0e16951162f5eab1adbd155957763444 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Fri, 12 Apr 2024 15:57:00 +0100 Subject: [PATCH 06/19] `mechanisms` section --- .../containers/ParticleScriptContainer.java | 30 ++++++++++++++++--- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/denizenscript/clientizen/scripts/containers/ParticleScriptContainer.java b/src/main/java/com/denizenscript/clientizen/scripts/containers/ParticleScriptContainer.java index a96c379..55a40a2 100644 --- a/src/main/java/com/denizenscript/clientizen/scripts/containers/ParticleScriptContainer.java +++ b/src/main/java/com/denizenscript/clientizen/scripts/containers/ParticleScriptContainer.java @@ -5,14 +5,18 @@ import com.denizenscript.clientizen.objects.ParticleTag; import com.denizenscript.clientizen.scripts.containers.gui.GuiScriptContainer; import com.denizenscript.denizencore.DenizenCore; +import com.denizenscript.denizencore.objects.Mechanism; +import com.denizenscript.denizencore.objects.ObjectTag; import com.denizenscript.denizencore.objects.core.DurationTag; import com.denizenscript.denizencore.scripts.ScriptEntry; import com.denizenscript.denizencore.scripts.containers.ScriptContainer; import com.denizenscript.denizencore.scripts.queues.ContextSource; +import com.denizenscript.denizencore.tags.TagContext; import com.denizenscript.denizencore.utilities.CoreUtilities; import com.denizenscript.denizencore.utilities.ScriptUtilities; import com.denizenscript.denizencore.utilities.YamlConfiguration; import com.denizenscript.denizencore.utilities.debugging.Debug; +import com.denizenscript.denizencore.utilities.text.StringHolder; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; import net.fabricmc.fabric.api.client.particle.v1.ParticleFactoryRegistry; import net.fabricmc.fabric.api.particle.v1.FabricParticleTypes; @@ -22,6 +26,7 @@ import net.minecraft.client.texture.SpriteAtlasTexture; import net.minecraft.client.world.ClientWorld; import net.minecraft.particle.DefaultParticleType; +import net.minecraft.particle.ParticleType; import net.minecraft.registry.Registries; import net.minecraft.registry.Registry; import net.minecraft.util.Identifier; @@ -60,6 +65,7 @@ public static void registerCustomParticles() { public final List textures; public final List updateScript; + public List mechanisms; public long updateRate; public ParticleScriptContainer(YamlConfiguration configurationSection, String scriptContainerName) { @@ -82,10 +88,19 @@ public ParticleScriptContainer(YamlConfiguration configurationSection, String sc textures.add(sprite); } updateScript = getEntries(DenizenCore.implementation.getEmptyScriptEntryData(), "update"); - DurationTag rateDuration = GuiScriptContainer.getTaggedObject(DurationTag.class, configurationSection, "update_rate", DenizenCore.implementation.getTagContext(this)); + TagContext scriptContext = DenizenCore.implementation.getTagContext(this); + DurationTag rateDuration = GuiScriptContainer.getTaggedObject(DurationTag.class, configurationSection, "update_rate", scriptContext); if (rateDuration != null) { updateRate = rateDuration.getMillis(); } + YamlConfiguration mechanismsSection = getConfigurationSection("mechanisms"); + if (mechanismsSection != null) { + mechanisms = new ArrayList<>(mechanismsSection.contents.size()); + for (Map.Entry entry : mechanismsSection.contents.entrySet()) { + ObjectTag value = CoreUtilities.objectToTagForm(entry.getValue(), scriptContext, true, true, true); + mechanisms.add(new Mechanism(entry.getKey().low, value, scriptContext)); + } + } customParticles.add(this); Debug.popErrorContext(); } @@ -101,13 +116,20 @@ public static class ClientizenParticle extends SpriteBillboardParticle { ContextSource.SimpleMap scriptContext; long lastUpdateTime; - protected ClientizenParticle(ClientWorld world, double x, double y, double z, double velocityX, double velocityY, double velocityZ, SpriteProvider spriteProvider, ParticleScriptContainer particleScript) { + protected ClientizenParticle(ClientWorld world, double x, double y, double z, double velocityX, double velocityY, double velocityZ, + SpriteProvider spriteProvider, ParticleScriptContainer particleScript, ParticleType particleType) { super(world, x, y, z, velocityX, velocityY, velocityZ); this.spriteProvider = spriteProvider; this.particleScript = particleScript; this.scriptContext = new ContextSource.SimpleMap(); - scriptContext.contexts = Map.of("particle", new ParticleTag(this)); setSprite(spriteProvider); + ParticleTag particleTag = new ParticleTag(this); + // Specifically set the type early, as we apply mechanisms + particleTag.getMixinAccess().clientizen$setType(particleType); + scriptContext.contexts = Map.of("particle", particleTag); + if (particleScript.mechanisms != null) { + particleScript.mechanisms.forEach(particleTag::safeAdjust); + } } @Override @@ -141,7 +163,7 @@ public record Factory(SpriteProvider spriteProvider, ParticleScriptContainer par @Override public Particle createParticle(DefaultParticleType parameters, ClientWorld world, double x, double y, double z, double velocityX, double velocityY, double velocityZ) { - return new ClientizenParticle(world, x, y, z, velocityX, velocityY, velocityZ, spriteProvider, particleScript); + return new ClientizenParticle(world, x, y, z, velocityX, velocityY, velocityZ, spriteProvider, particleScript, parameters); } } } From e95de278a4e07a1d46e88a348a7cfaeac5e33bbe Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Fri, 12 Apr 2024 17:08:46 +0100 Subject: [PATCH 07/19] Require `textures` key --- .../scripts/containers/ParticleScriptContainer.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/denizenscript/clientizen/scripts/containers/ParticleScriptContainer.java b/src/main/java/com/denizenscript/clientizen/scripts/containers/ParticleScriptContainer.java index 55a40a2..d2641e6 100644 --- a/src/main/java/com/denizenscript/clientizen/scripts/containers/ParticleScriptContainer.java +++ b/src/main/java/com/denizenscript/clientizen/scripts/containers/ParticleScriptContainer.java @@ -63,7 +63,7 @@ public static void registerCustomParticles() { Registries.PARTICLE_TYPE.freeze(); } - public final List textures; + public List textures; public final List updateScript; public List mechanisms; public long updateRate; @@ -73,6 +73,12 @@ public ParticleScriptContainer(YamlConfiguration configurationSection, String sc Debug.pushErrorContext(this); SpriteAtlasTexture particlesAtlas = ParticleTag.getParticleAtlas(); List textureInput = getStringList("textures", true); + if (textureInput == null) { + Debug.echoError("Missing required 'textures' key."); + Debug.popErrorContext(); + updateScript = null; + return; + } textures = new ArrayList<>(textureInput.size()); for (String texture : textureInput) { Identifier textureId = Identifier.tryParse(texture); From 77827dd158a0504f16f6e668d20a9e4b64ea8684 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Fri, 12 Apr 2024 18:06:03 +0100 Subject: [PATCH 08/19] `particle` command: `created_particle` save --- .../clientizen/scripts/commands/ParticleCommand.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/denizenscript/clientizen/scripts/commands/ParticleCommand.java b/src/main/java/com/denizenscript/clientizen/scripts/commands/ParticleCommand.java index 97e74dc..f5e4a2b 100644 --- a/src/main/java/com/denizenscript/clientizen/scripts/commands/ParticleCommand.java +++ b/src/main/java/com/denizenscript/clientizen/scripts/commands/ParticleCommand.java @@ -3,10 +3,7 @@ import com.denizenscript.clientizen.Clientizen; import com.denizenscript.clientizen.mixin.WorldRendererAccessor; import com.denizenscript.clientizen.mixin.particle.ParticleAccessor; -import com.denizenscript.clientizen.objects.EntityTag; -import com.denizenscript.clientizen.objects.ItemTag; -import com.denizenscript.clientizen.objects.LocationTag; -import com.denizenscript.clientizen.objects.MaterialTag; +import com.denizenscript.clientizen.objects.*; import com.denizenscript.clientizen.scripts.containers.ParticleScriptContainer; import com.denizenscript.denizencore.exceptions.InvalidArgumentsRuntimeException; import com.denizenscript.denizencore.objects.ObjectTag; @@ -213,6 +210,7 @@ else if (type == ParticleTypes.SHRIEK) { } createdParticle.scale(scaleMultiplier.asFloat()); } + scriptEntry.saveObject("created_particle", new ParticleTag(createdParticle)); } private static Vector3f colorToVector(ColorTag color) { From 91261a729643fc40935b078f16a6a33e49e83b92 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Fri, 12 Apr 2024 18:17:18 +0100 Subject: [PATCH 09/19] `ParticleTag.script`, fix `debuggable` format --- .../denizenscript/clientizen/objects/ParticleTag.java | 11 ++++++++++- .../scripts/containers/ParticleScriptContainer.java | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/denizenscript/clientizen/objects/ParticleTag.java b/src/main/java/com/denizenscript/clientizen/objects/ParticleTag.java index fc294e5..123a86a 100644 --- a/src/main/java/com/denizenscript/clientizen/objects/ParticleTag.java +++ b/src/main/java/com/denizenscript/clientizen/objects/ParticleTag.java @@ -4,6 +4,7 @@ import com.denizenscript.clientizen.mixin.particle.ParticleAccessor; import com.denizenscript.clientizen.mixin.particle.ParticleManagerAccessor; import com.denizenscript.clientizen.mixin.particle.SpriteBillboardParticleAccessor; +import com.denizenscript.clientizen.scripts.containers.ParticleScriptContainer; import com.denizenscript.clientizen.util.Utilities; import com.denizenscript.denizencore.objects.Adjustable; import com.denizenscript.denizencore.objects.Fetchable; @@ -12,6 +13,7 @@ import com.denizenscript.denizencore.objects.core.ColorTag; import com.denizenscript.denizencore.objects.core.DurationTag; import com.denizenscript.denizencore.objects.core.ElementTag; +import com.denizenscript.denizencore.objects.core.ScriptTag; import com.denizenscript.denizencore.tags.Attribute; import com.denizenscript.denizencore.tags.ObjectTagProcessor; import com.denizenscript.denizencore.tags.TagContext; @@ -93,6 +95,13 @@ public static void register() { return new ElementTag(object.getTypeString(), true); }); + tagProcessor.registerTag(ScriptTag.class, "script", (attribute, object) -> { + if (object.particle instanceof ParticleScriptContainer.ClientizenParticle clientizenParticle) { + return new ScriptTag(clientizenParticle.particleScript); + } + return null; + }); + tagProcessor.registerTag(LocationTag.class, "location", (attribute, object) -> { ParticleAccessor particle = object.getAccessor(); return new LocationTag(particle.getX(), particle.getY(), particle.getZ()); @@ -239,7 +248,7 @@ public String identifySimple() { @Override public String debuggable() { - return "particle@" + getMixinAccess().clientizen$getUUID() + " (" + getTypeString() + ")"; + return "particle@" + getMixinAccess().clientizen$getUUID() + " (" + getTypeString() + ")"; } @Override diff --git a/src/main/java/com/denizenscript/clientizen/scripts/containers/ParticleScriptContainer.java b/src/main/java/com/denizenscript/clientizen/scripts/containers/ParticleScriptContainer.java index d2641e6..2d6008a 100644 --- a/src/main/java/com/denizenscript/clientizen/scripts/containers/ParticleScriptContainer.java +++ b/src/main/java/com/denizenscript/clientizen/scripts/containers/ParticleScriptContainer.java @@ -118,7 +118,7 @@ public Identifier getId() { public static class ClientizenParticle extends SpriteBillboardParticle { SpriteProvider spriteProvider; - ParticleScriptContainer particleScript; + public ParticleScriptContainer particleScript; ContextSource.SimpleMap scriptContext; long lastUpdateTime; From ffe3ba108378f988ac2f64e2c58c80d9558a9bb3 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Sat, 13 Apr 2024 18:05:07 +0100 Subject: [PATCH 10/19] Scale controls, avoid randomizing velocity --- .../access/BillboardParticleMixinAccess.java | 8 ++++ .../particle/BillboardParticleMixin.java | 37 +++++++++++++++++++ .../clientizen/objects/ParticleTag.java | 26 +++++++++++++ .../containers/ParticleScriptContainer.java | 5 +++ src/main/resources/clientizen.mixins.json | 1 + 5 files changed, 77 insertions(+) create mode 100644 src/main/java/com/denizenscript/clientizen/access/BillboardParticleMixinAccess.java create mode 100644 src/main/java/com/denizenscript/clientizen/mixin/particle/BillboardParticleMixin.java diff --git a/src/main/java/com/denizenscript/clientizen/access/BillboardParticleMixinAccess.java b/src/main/java/com/denizenscript/clientizen/access/BillboardParticleMixinAccess.java new file mode 100644 index 0000000..4e861ce --- /dev/null +++ b/src/main/java/com/denizenscript/clientizen/access/BillboardParticleMixinAccess.java @@ -0,0 +1,8 @@ +package com.denizenscript.clientizen.access; + +public interface BillboardParticleMixinAccess { + + float clientizen$getScale(); + + void clientizen$setScale(Float scale); +} diff --git a/src/main/java/com/denizenscript/clientizen/mixin/particle/BillboardParticleMixin.java b/src/main/java/com/denizenscript/clientizen/mixin/particle/BillboardParticleMixin.java new file mode 100644 index 0000000..f857fc4 --- /dev/null +++ b/src/main/java/com/denizenscript/clientizen/mixin/particle/BillboardParticleMixin.java @@ -0,0 +1,37 @@ +package com.denizenscript.clientizen.mixin.particle; + +import com.denizenscript.clientizen.access.BillboardParticleMixinAccess; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import net.minecraft.client.particle.BillboardParticle; +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; + +@Mixin(BillboardParticle.class) +public abstract class BillboardParticleMixin implements BillboardParticleMixinAccess { + + @Shadow + protected float scale; + @Unique + Float clientizen$scale; + + @Override + public float clientizen$getScale() { + return clientizen$scale != null ? clientizen$scale : scale; + } + + @Override + public void clientizen$setScale(Float scale) { + clientizen$scale = scale; + } + + @WrapOperation( + method = "buildGeometry", + at = @At(value = "INVOKE", target = "Lnet/minecraft/client/particle/BillboardParticle;getSize(F)F") + ) + private float clientizen$overrideSize(BillboardParticle particle, float tickDelta, Operation original) { + return clientizen$scale != null ? clientizen$scale : original.call(particle, tickDelta); + } +} diff --git a/src/main/java/com/denizenscript/clientizen/objects/ParticleTag.java b/src/main/java/com/denizenscript/clientizen/objects/ParticleTag.java index 123a86a..34d4288 100644 --- a/src/main/java/com/denizenscript/clientizen/objects/ParticleTag.java +++ b/src/main/java/com/denizenscript/clientizen/objects/ParticleTag.java @@ -1,5 +1,6 @@ package com.denizenscript.clientizen.objects; +import com.denizenscript.clientizen.access.BillboardParticleMixinAccess; import com.denizenscript.clientizen.access.ParticleMixinAccess; import com.denizenscript.clientizen.mixin.particle.ParticleAccessor; import com.denizenscript.clientizen.mixin.particle.ParticleManagerAccessor; @@ -181,6 +182,31 @@ public static void register() { object.particle.setMaxAge(input.getTicksAsInt()); }); + tagProcessor.registerTag(ElementTag.class, "scale", (attribute, object) -> { + if (object.particle instanceof BillboardParticleMixinAccess billboardParticle) { + return new ElementTag(billboardParticle.clientizen$getScale()); + } + return null; + }); + + tagProcessor.registerMechanism("scale", false, ElementTag.class, (object, mechanism, input) -> { + if (!(object.particle instanceof BillboardParticleMixinAccess billboardParticle)) { + mechanism.echoError("Cannot set scale: particles of type '" + object.getTypeString() + "' don't support scaling."); + return; + } + if (mechanism.requireFloat()) { + billboardParticle.clientizen$setScale(mechanism.getValue().asFloat()); + } + }); + + tagProcessor.registerMechanism("reset_scale", false, (object, mechanism) -> { + if (!(object.particle instanceof BillboardParticleMixinAccess billboardParticle)) { + mechanism.echoError("Cannot reset scale: particles of type '" + object.getTypeString() + "' don't support scaling."); + return; + } + billboardParticle.clientizen$setScale(null); + }); + tagProcessor.registerTag(ElementTag.class, "on_ground", (attribute, object) -> { return new ElementTag(object.getAccessor().isOnGround()); }); diff --git a/src/main/java/com/denizenscript/clientizen/scripts/containers/ParticleScriptContainer.java b/src/main/java/com/denizenscript/clientizen/scripts/containers/ParticleScriptContainer.java index 2d6008a..cd149c2 100644 --- a/src/main/java/com/denizenscript/clientizen/scripts/containers/ParticleScriptContainer.java +++ b/src/main/java/com/denizenscript/clientizen/scripts/containers/ParticleScriptContainer.java @@ -125,6 +125,11 @@ public static class ClientizenParticle extends SpriteBillboardParticle { protected ClientizenParticle(ClientWorld world, double x, double y, double z, double velocityX, double velocityY, double velocityZ, SpriteProvider spriteProvider, ParticleScriptContainer particleScript, ParticleType particleType) { super(world, x, y, z, velocityX, velocityY, velocityZ); + // Minecraft randomizes some values, don't want that for Clientizen particles + this.velocityX = velocityX; + this.velocityY = velocityY; + this.velocityZ = velocityZ; + this.scale = 1; this.spriteProvider = spriteProvider; this.particleScript = particleScript; this.scriptContext = new ContextSource.SimpleMap(); diff --git a/src/main/resources/clientizen.mixins.json b/src/main/resources/clientizen.mixins.json index cdee21d..307d732 100644 --- a/src/main/resources/clientizen.mixins.json +++ b/src/main/resources/clientizen.mixins.json @@ -20,6 +20,7 @@ "WorldRendererMixin", "gui.WScrollPanelAccessor", "gui.WTextAccessor", + "particle.BillboardParticleMixin", "particle.ParticleAccessor", "particle.ParticleManagerAccessor", "particle.ParticleManagerMixin", From 7da5a890f41e3dcc4701b3eb6c052edf56a7c993 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Sun, 14 Apr 2024 13:18:04 +0100 Subject: [PATCH 11/19] Cleanup registry mixin --- .../clientizen/mixin/RegistryMixin.java | 24 +++++-------------- 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/denizenscript/clientizen/mixin/RegistryMixin.java b/src/main/java/com/denizenscript/clientizen/mixin/RegistryMixin.java index b6f58d6..7b7de2a 100644 --- a/src/main/java/com/denizenscript/clientizen/mixin/RegistryMixin.java +++ b/src/main/java/com/denizenscript/clientizen/mixin/RegistryMixin.java @@ -31,48 +31,31 @@ public abstract class RegistryMixin implements RegistryMixinAccess { @Shadow private boolean frozen; - - @Shadow - private @Nullable Map> intrusiveValueToEntry; - @Shadow public abstract RegistryKey> getKey(); - @Shadow - public abstract @Nullable T get(@Nullable Identifier id); - + private @Nullable Map> intrusiveValueToEntry; @Shadow @Final private ObjectList> rawIdToEntry; - @Shadow @Final private Map> idToEntry; - @Shadow @Final private Reference2IntMap entryToRawId; - @Shadow @Final private Map, RegistryEntry.Reference> keyToEntry; - @Shadow @Final private Map> valueToEntry; - @Shadow @Final private Map entryToLifecycle; - @Shadow private @Nullable List> cachedEntries; - @Inject(method = "(Lnet/minecraft/registry/RegistryKey;Lcom/mojang/serialization/Lifecycle;Z)V", at = @At("TAIL")) - private void clientizen$saveIsIntrusive(RegistryKey key, Lifecycle lifecycle, boolean intrusive, CallbackInfo ci) { - clientizen$isIntrusive = intrusive; - } - @Override public void clientizen$unfreeze() { if (!frozen) { @@ -99,4 +82,9 @@ public abstract class RegistryMixin implements RegistryMixinAccess { entryToLifecycle.remove(value.value()); cachedEntries = null; } + + @Inject(method = "(Lnet/minecraft/registry/RegistryKey;Lcom/mojang/serialization/Lifecycle;Z)V", at = @At("TAIL")) + private void clientizen$saveIsIntrusive(RegistryKey key, Lifecycle lifecycle, boolean intrusive, CallbackInfo ci) { + clientizen$isIntrusive = intrusive; + } } From e77e4b2024d2878db7b9331547f8a0068c36841f Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Wed, 17 Apr 2024 11:02:54 +0100 Subject: [PATCH 12/19] Document `ParticleTag` --- .../clientizen/objects/ParticleTag.java | 265 ++++++++++++++++++ 1 file changed, 265 insertions(+) diff --git a/src/main/java/com/denizenscript/clientizen/objects/ParticleTag.java b/src/main/java/com/denizenscript/clientizen/objects/ParticleTag.java index 34d4288..026d580 100644 --- a/src/main/java/com/denizenscript/clientizen/objects/ParticleTag.java +++ b/src/main/java/com/denizenscript/clientizen/objects/ParticleTag.java @@ -34,6 +34,21 @@ public class ParticleTag implements Adjustable { + // <--[ObjectType] + // @name ParticleTag + // @prefix particle + // @ExampleTagBase [particle] + // @base ElementTag + // @format + // The identity format for particles is the particle's UUID. + // For example, 'particle@14ade8b1-746c-4952-881f-2844432aa277'. + // + // @description + // A ParticleTag represents a particle that currently exists in the world. + // Either a normal vanilla particle, one from a <@link language Particle Script Container>, or one from another mod. + // + // --> + public static final Map particles = new HashMap<>(); public static SpriteAtlasTexture getParticleAtlas() { @@ -92,10 +107,30 @@ public String getTypeString() { } public static void register() { + + // <--[tag] + // @attribute + // @returns ElementTag + // @description + // Returns the particle's particle type. + // For vanilla particles, this is their base vanilla type - see <@link url https://minecraft.wiki/w/Particles_(Java_Edition)#Types_of_particles>. + // For clientizen particles, this is their custom particle type ("clientizen:") - should generally prefer <@link tag ParticleTag.script>. + // For particles added by other mods, this is a custom particle type in namespaced key format (":"). + // @example + // # Use to check if a particle is a flame particle. + // - if <[particle].type> == flame: + // - narrate "It's a flame particle!" + // --> tagProcessor.registerTag(ElementTag.class, "type", (attribute, object) -> { return new ElementTag(object.getTypeString(), true); }); + // <--[tag] + // @attribute + // @returns ScriptTag + // @description + // Returns the particle script a particle was created from, if any. + // --> tagProcessor.registerTag(ScriptTag.class, "script", (attribute, object) -> { if (object.particle instanceof ParticleScriptContainer.ClientizenParticle clientizenParticle) { return new ScriptTag(clientizenParticle.particleScript); @@ -103,24 +138,78 @@ public static void register() { return null; }); + // <--[tag] + // @attribute + // @returns LocationTag + // @mechanism ParticleTag.location + // @description + // Returns the particle's location. + // @example + // # Use to move the particle 5 blocks up. + // - adjust <[particle]> location:<[particle].location.above[5]> + // --> tagProcessor.registerTag(LocationTag.class, "location", (attribute, object) -> { ParticleAccessor particle = object.getAccessor(); return new LocationTag(particle.getX(), particle.getY(), particle.getZ()); }); + // <--[mechanism] + // @object ParticleTag + // @name location + // @input LocationTag + // @description + // Sets the particle's location. + // @tags + // + // @example + // # Use to move the particle 5 blocks up. + // - adjust <[particle]> location:<[particle].location.above[5]> + // --> tagProcessor.registerMechanism("location", false, LocationTag.class, (object, mechanism, input) -> { object.particle.setPos(input.getX(), input.getY(), input.getZ()); }); + // <--[tag] + // @attribute + // @returns LocationTag + // @mechanism ParticleTag.velocity + // @description + // Returns the particle's velocity as a LocationTag vector. + // @example + // # Use to check whether the particle is going upwards. + // - if <[particle].velocity.y> > 0: + // - narrate "The particle is heading upwards." + // --> tagProcessor.registerTag(LocationTag.class, "velocity", (attribute, object) -> { ParticleAccessor particle = object.getAccessor(); return new LocationTag(particle.getVelocityX(), particle.getVelocityY(), particle.getVelocityZ()); }); + // <--[mechanism] + // @object ParticleTag + // @name velocity + // @input LocationTag + // @description + // Sets the particle's velocity to the given LocationTag vector. + // @tags + // + // @example + // # Use to make the particle move upwards. + // - adjust <[particle]> velocity:0,1,0 + // --> tagProcessor.registerMechanism("velocity", false, LocationTag.class, (object, mechanism, input) -> { object.particle.setVelocity(input.getX(), input.getY(), input.getZ()); }); + // <--[tag] + // @attribute + // @returns ElementTag + // @mechanism ParticleTag.texture + // @description + // Returns the particle's current texture as a namespaced key, if it's of a type that has textures. + // Note that the texture id is within the particle texture atlas, + // "assets//textures/particle/.png" within the resource pack, and referenced as ":". + // --> tagProcessor.registerTag(ElementTag.class, "texture", (attribute, object) -> { if (object.particle instanceof SpriteBillboardParticleAccessor spriteParticle) { return new ElementTag(Utilities.idToString(spriteParticle.getSprite().getContents().getId()), true); @@ -128,6 +217,17 @@ public static void register() { return null; }); + // <--[mechanism] + // @object ParticleTag + // @name texture + // @input ElementTag + // @description + // Sets the particle's texture, if it's of a type that allows them. + // The input is a namespaced key of the texture, within the particle texture atlas - + // "assets//textures/particle/.png" within the resource pack, and referenced as ":". + // @tags + // + // --> tagProcessor.registerMechanism("texture", false, ElementTag.class, (object, mechanism, input) -> { if (!(object.particle instanceof SpriteBillboardParticleAccessor spriteParticle)) { mechanism.echoError("Cannot set texture: particles of type '" + object.getTypeString() + "' don't support textures."); @@ -146,42 +246,139 @@ public static void register() { spriteParticle.invokeSetSprite(sprite); }); + // <--[tag] + // @attribute + // @returns ColorTag + // @mechanism ParticleTag.color + // @description + // Returns the particle's color. + // Usually applied on top of a particle's existing texture, either coloring it or overriding it (while keeping the shape). + // --> tagProcessor.registerTag(ColorTag.class, "color", (attribute, object) -> { ParticleAccessor particle = object.getAccessor(); return new ColorTag((int) (particle.getRed() * 255f), (int) (particle.getGreen() * 255f), (int) (particle.getBlue() * 255f), (int) (particle.getAlpha() * 255f)); }); + // <--[mechanism] + // @object ParticleTag + // @name color + // @input ColorTag + // @description + // Sets the particle's color. + // Usually applied on top of a particle's existing texture, either coloring it or overriding it (while keeping the shape). + // Note that alpha values can be set, but only visually apply to some particles. + // @tags + // + // @example + // # Use to set a particle's color to a random color. + // - adjust <[particle]> color:random + // --> tagProcessor.registerMechanism("color", false, ColorTag.class, (object, mechanism, input) -> { object.particle.setColor(input.red / 255f, input.green / 255f, input.blue / 255f); object.getAccessor().invokeSetAlpha(input.alpha / 255f); }); + // <--[tag] + // @attribute + // @returns ElementTag(Boolean) + // @mechanism ParticleTag.world_collision + // @description + // Returns whether the particle will collide with the world. + // --> tagProcessor.registerTag(ElementTag.class, "world_collision", (attribute, object) -> { return new ElementTag(object.getAccessor().collidesWithWorld()); }); + // <--[mechanism] + // @object ParticleTag + // @name world_collision + // @input ElementTag(Boolean) + // @description + // Sets whether the particle will collide the with the world. + // @tags + // + // --> tagProcessor.registerMechanism("world_collision", false, ElementTag.class, (object, mechanism, input) -> { if (mechanism.requireBoolean()) { object.getAccessor().setCollidesWithWorld(input.asBoolean()); } }); + // <--[tag] + // @attribute + // @returns DurationTag + // @mechanism ParticleTag.time_lived + // @description + // Returns how long the particle's existed for. + // @example + // # Use to check if the particle's existed for at least 10 seconds. + // - if <[particle].time_lived.is_more_than[10s]>: + // - narrate "The particle's existed for more than 10 seconds." + // --> tagProcessor.registerTag(DurationTag.class, "time_lived", (attribute, object) -> { return new DurationTag((long) object.getAccessor().getAge()); }); + // <--[mechanism] + // @object ParticleTag + // @name time_lived + // @input DurationTag + // @description + // Sets the amount of time the particle's existed for. + // Generally shouldn't be needed, but may be useful in some specific cases. + // See <@link mechanism ParticleTag.time_to_live> for setting the amount of time the particle should exist for. + // @tags + // + // @example + // # Use to make it as if the particle just spawned in. + // - adjust <[particle]> time_lived:0 + // --> tagProcessor.registerMechanism("time_lived", false, DurationTag.class, (object, mechanism, input) -> { object.getAccessor().setAge(input.getTicksAsInt()); }); + // <--[tag] + // @attribute + // @returns DurationTag + // @mechanism ParticleTag.time_to_live + // @description + // Returns the amount of time the particle should exist for. + // See <@link tag ParticleTag.time_lived> for the amount of time the particle's existed. + // @example + // # Use to check how much time is left before the particle despawns. + // - narrate "The particle will despawn in <[particle].time_to_live.sub[<[particle].time_lived>].formatted>." + // --> tagProcessor.registerTag(DurationTag.class, "time_to_live", (attribute, object) -> { return new DurationTag((long) object.particle.getMaxAge()); }); + // <--[mechanism] + // @object ParticleTag + // @name time_to_live + // @input DurationTag + // @description + // Sets the amount of time the particle should exist for. + // @tags + // + // @example + // # Use to make it so the particle will exist for 10 seconds (assuming it just spawned). + // - adjust <[particle]> time_to_live:10s + // --> tagProcessor.registerMechanism("time_to_live", false, DurationTag.class, (object, mechanism, input) -> { object.particle.setMaxAge(input.getTicksAsInt()); }); + // <--[tag] + // @attribute + // @returns ElementTag(Decimal) + // @mechanism ParticleTag.scale + // @description + // Returns the particle's scale, if it's of a type that supports scaling. + // Note that some particles may do additional processing on their base scale, which can be overriden using the mechanism. + // @example + // # Use to make a particle twice as large. + // - adjust <[particle]> scale:<[particle].scale.mul[2]> + // --> tagProcessor.registerTag(ElementTag.class, "scale", (attribute, object) -> { if (object.particle instanceof BillboardParticleMixinAccess billboardParticle) { return new ElementTag(billboardParticle.clientizen$getScale()); @@ -189,6 +386,21 @@ public static void register() { return null; }); + // <--[mechanism] + // @object ParticleTag + // @name scale + // @input ElementTag(Decimal) + // @description + // Sets the particle's scale, if it's of a type that supports scaling. + // Note that this overrides the particle's normal scale calculations (some particles rescale based on their time lived, for example) with a hard-coded scale, + // see <@link mechanism ParticleTag.multiply_scale> to modify the vanilla scaling instead of overriding it. + // And see <@link mechanism ParticleTag.reset_scale> to go back to the default vanilla scaling. + // @tags + // + // @example + // # Use to make a particle twice as large. + // - adjust <[particle]> scale:<[particle].scale.mul[2]> + // --> tagProcessor.registerMechanism("scale", false, ElementTag.class, (object, mechanism, input) -> { if (!(object.particle instanceof BillboardParticleMixinAccess billboardParticle)) { mechanism.echoError("Cannot set scale: particles of type '" + object.getTypeString() + "' don't support scaling."); @@ -199,6 +411,13 @@ public static void register() { } }); + // <--[mechanism] + // @object ParticleTag + // @name reset_scale + // @input None + // @description + // Resets a scale override from <@link mechanism ParticleTag.scale> back to the particle's original vanilla scaling. + // --> tagProcessor.registerMechanism("reset_scale", false, (object, mechanism) -> { if (!(object.particle instanceof BillboardParticleMixinAccess billboardParticle)) { mechanism.echoError("Cannot reset scale: particles of type '" + object.getTypeString() + "' don't support scaling."); @@ -207,10 +426,29 @@ public static void register() { billboardParticle.clientizen$setScale(null); }); + // <--[tag] + // @attribute + // @returns ElementTag(Boolean) + // @description + // Returns whether the particle's on the ground or in the air. + // See <@link tag ParticleTag.world_collision> for whether the particle collides with the ground. + // @example + // # Use to make the particle blue if it's on the ground. + // - if <[particle].on_ground>: + // - adjust <[particle]> color:blue + // --> tagProcessor.registerTag(ElementTag.class, "on_ground", (attribute, object) -> { return new ElementTag(object.getAccessor().isOnGround()); }); + // <--[mechanism] + // @object ParticleTag + // @name randomize_texture + // @input None + // @description + // Applies a random texture from the particle's texture list, if it's of a type that supports textures. + // See <@link mechanism ParticleTag.texture> for setting a specific texture. + // --> tagProcessor.registerMechanism("randomize_texture", false, (object, mechanism) -> { if (!(object.particle instanceof SpriteBillboardParticle spriteParticle)) { mechanism.echoError("Cannot randomize texture: particles of type '" + object.getTypeString() + "' don't have textures."); @@ -220,6 +458,15 @@ public static void register() { spriteParticle.setSprite(spriteProvider); }); + // <--[mechanism] + // @object ParticleTag + // @name update_age_texture + // @input None + // @description + // Applies a texture from the particle's texture list based on the time it's lived. + // For example: a particle with 4 textures that exists for 20 seconds will apply a different texture every 5 seconds, when this mechanism is used. + // See <@link mechanism ParticleTag.texture> for setting a specific texture. + // --> tagProcessor.registerMechanism("update_age_texture", false, (object, mechanism) -> { if (!(object.particle instanceof SpriteBillboardParticle spriteParticle)) { mechanism.echoError("Cannot update texture for age: particles of type '" + object.getTypeString() + "' don't have textures."); @@ -229,12 +476,30 @@ public static void register() { spriteParticle.setSpriteForAge(spriteProvider); }); + // <--[mechanism] + // @object ParticleTag + // @name multiply_scale + // @input ElementTag(Decimal) + // @description + // Multiplies the particle's current vanilla scale by the input amount, without overriding it. + // See <@link mechanism ParticleTag.scale> for overriding the vanilla scaling with a specific scale. + // @example + // # Use to make a particle twice as big without overriding its built-in scaling logic. + // - adjust <[particle]> multiply_scale:2 + // --> tagProcessor.registerMechanism("multiply_scale", false, ElementTag.class, (object, mechanism, input) -> { if (mechanism.requireFloat()) { object.particle.scale(input.asFloat()); } }); + // <--[mechanism] + // @object ParticleTag + // @name remove + // @input None + // @description + // Removes a particle from the world. + // --> tagProcessor.registerMechanism("remove", false, (object, mechanism) -> { object.particle.markDead(); }); From b36325a25cc0caaee11c991f74f9158b7bd93a5b Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Wed, 17 Apr 2024 17:42:38 +0100 Subject: [PATCH 13/19] Advanced matchers --- .../clientizen/objects/ParticleTag.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/main/java/com/denizenscript/clientizen/objects/ParticleTag.java b/src/main/java/com/denizenscript/clientizen/objects/ParticleTag.java index 026d580..1dcac9e 100644 --- a/src/main/java/com/denizenscript/clientizen/objects/ParticleTag.java +++ b/src/main/java/com/denizenscript/clientizen/objects/ParticleTag.java @@ -7,6 +7,7 @@ import com.denizenscript.clientizen.mixin.particle.SpriteBillboardParticleAccessor; import com.denizenscript.clientizen.scripts.containers.ParticleScriptContainer; import com.denizenscript.clientizen.util.Utilities; +import com.denizenscript.denizencore.events.ScriptEvent; import com.denizenscript.denizencore.objects.Adjustable; import com.denizenscript.denizencore.objects.Fetchable; import com.denizenscript.denizencore.objects.Mechanism; @@ -47,6 +48,13 @@ public class ParticleTag implements Adjustable { // A ParticleTag represents a particle that currently exists in the world. // Either a normal vanilla particle, one from a <@link language Particle Script Container>, or one from another mod. // + // @Matchable + // ParticleTag matchers, sometimes identified as : + // "particle" plaintext: always matches. + // "script" plaintext: matches if the particle is from a <@link language Particle Script Container>. + // Any particle type (see <@link tag ParticleTag.type> for formats): matches if the particle is of the given type, using advanced matchers. + // Any particle script name: matches if the particle is from the given script, using advanced matchers. + // // --> public static final Map particles = new HashMap<>(); @@ -547,6 +555,19 @@ public String toString() { return identify(); } + @Override + public boolean advancedMatches(String matcher) { + return ScriptEvent.createMatcher(matcher).doesMatch( + particle instanceof ParticleScriptContainer.ClientizenParticle clientizenParticle ? clientizenParticle.particleScript.getName() : getTypeString(), text -> { + return switch (text) { + case "particle" -> true; + case "script" -> particle instanceof ParticleScriptContainer.ClientizenParticle; + default -> false; + }; + } + ); + } + String prefix; @Override From 46e884d668c6a2e506328c809090e38112637876 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Wed, 17 Apr 2024 20:01:46 +0100 Subject: [PATCH 14/19] Flaggable `ParticleTag`s --- .../clientizen/access/ParticleMixinAccess.java | 3 +++ .../mixin/particle/ParticleMixin.java | 12 +++++++++++- .../clientizen/objects/ParticleTag.java | 17 ++++++++++++++++- 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/denizenscript/clientizen/access/ParticleMixinAccess.java b/src/main/java/com/denizenscript/clientizen/access/ParticleMixinAccess.java index ef399c0..f8ba338 100644 --- a/src/main/java/com/denizenscript/clientizen/access/ParticleMixinAccess.java +++ b/src/main/java/com/denizenscript/clientizen/access/ParticleMixinAccess.java @@ -1,5 +1,6 @@ package com.denizenscript.clientizen.access; +import com.denizenscript.denizencore.flags.MapTagFlagTracker; import net.minecraft.particle.ParticleType; import java.util.UUID; @@ -11,4 +12,6 @@ public interface ParticleMixinAccess { ParticleType clientizen$getType(); void clientizen$setType(ParticleType type); + + MapTagFlagTracker clientizen$getFlagTracker(); } diff --git a/src/main/java/com/denizenscript/clientizen/mixin/particle/ParticleMixin.java b/src/main/java/com/denizenscript/clientizen/mixin/particle/ParticleMixin.java index c8cc5fb..95e7190 100644 --- a/src/main/java/com/denizenscript/clientizen/mixin/particle/ParticleMixin.java +++ b/src/main/java/com/denizenscript/clientizen/mixin/particle/ParticleMixin.java @@ -2,6 +2,7 @@ import com.denizenscript.clientizen.access.ParticleMixinAccess; import com.denizenscript.clientizen.objects.ParticleTag; +import com.denizenscript.denizencore.flags.MapTagFlagTracker; import net.minecraft.client.particle.Particle; import net.minecraft.particle.ParticleType; import org.spongepowered.asm.mixin.Mixin; @@ -17,9 +18,10 @@ public abstract class ParticleMixin implements ParticleMixinAccess { @Unique final UUID clientizen$id = UUID.randomUUID(); - @Unique ParticleType clientizen$particleType; + @Unique + MapTagFlagTracker clientizen$flagMap; @Inject(method = "(Lnet/minecraft/client/world/ClientWorld;DDD)V", at = @At("TAIL")) private void clientizen$onParticleCreated(CallbackInfo ci) { @@ -45,4 +47,12 @@ public abstract class ParticleMixin implements ParticleMixinAccess { public void clientizen$setType(ParticleType type) { clientizen$particleType = type; } + + @Override + public MapTagFlagTracker clientizen$getFlagTracker() { + if (clientizen$flagMap == null) { + clientizen$flagMap = new MapTagFlagTracker(); + } + return clientizen$flagMap; + } } diff --git a/src/main/java/com/denizenscript/clientizen/objects/ParticleTag.java b/src/main/java/com/denizenscript/clientizen/objects/ParticleTag.java index 1dcac9e..7fbec60 100644 --- a/src/main/java/com/denizenscript/clientizen/objects/ParticleTag.java +++ b/src/main/java/com/denizenscript/clientizen/objects/ParticleTag.java @@ -8,6 +8,8 @@ import com.denizenscript.clientizen.scripts.containers.ParticleScriptContainer; import com.denizenscript.clientizen.util.Utilities; import com.denizenscript.denizencore.events.ScriptEvent; +import com.denizenscript.denizencore.flags.AbstractFlagTracker; +import com.denizenscript.denizencore.flags.FlaggableObject; import com.denizenscript.denizencore.objects.Adjustable; import com.denizenscript.denizencore.objects.Fetchable; import com.denizenscript.denizencore.objects.Mechanism; @@ -33,12 +35,13 @@ import java.util.Map; import java.util.UUID; -public class ParticleTag implements Adjustable { +public class ParticleTag implements Adjustable, FlaggableObject { // <--[ObjectType] // @name ParticleTag // @prefix particle // @ExampleTagBase [particle] + // @implements FlaggableObject // @base ElementTag // @format // The identity format for particles is the particle's UUID. @@ -48,6 +51,9 @@ public class ParticleTag implements Adjustable { // A ParticleTag represents a particle that currently exists in the world. // Either a normal vanilla particle, one from a <@link language Particle Script Container>, or one from another mod. // + // This object type is flaggable. + // Flags on this object type will be stored on the particle. + // // @Matchable // ParticleTag matchers, sometimes identified as : // "particle" plaintext: always matches. @@ -115,6 +121,7 @@ public String getTypeString() { } public static void register() { + AbstractFlagTracker.registerFlagHandlers(tagProcessor); // <--[tag] // @attribute @@ -530,6 +537,14 @@ public void applyProperty(Mechanism mechanism) { mechanism.echoError("Cannot apply properties to a ParticleTag."); } + @Override + public AbstractFlagTracker getFlagTracker() { + return getMixinAccess().clientizen$getFlagTracker(); + } + + @Override + public void reapplyTracker(AbstractFlagTracker tracker) {} + @Override public boolean isUnique() { return true; From b0931687c3deed757a31539176e88f43554440be Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Thu, 18 Apr 2024 15:10:02 +0100 Subject: [PATCH 15/19] Document particle script containers --- .../clientizen/objects/ParticleTag.java | 10 ++-- .../containers/ParticleScriptContainer.java | 55 +++++++++++++++++++ 2 files changed, 59 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/denizenscript/clientizen/objects/ParticleTag.java b/src/main/java/com/denizenscript/clientizen/objects/ParticleTag.java index 7fbec60..49d3703 100644 --- a/src/main/java/com/denizenscript/clientizen/objects/ParticleTag.java +++ b/src/main/java/com/denizenscript/clientizen/objects/ParticleTag.java @@ -49,7 +49,7 @@ public class ParticleTag implements Adjustable, FlaggableObject { // // @description // A ParticleTag represents a particle that currently exists in the world. - // Either a normal vanilla particle, one from a <@link language Particle Script Container>, or one from another mod. + // Either a normal vanilla particle, one from a <@link language Particle Script Containers>, or one from another mod. // // This object type is flaggable. // Flags on this object type will be stored on the particle. @@ -57,7 +57,7 @@ public class ParticleTag implements Adjustable, FlaggableObject { // @Matchable // ParticleTag matchers, sometimes identified as : // "particle" plaintext: always matches. - // "script" plaintext: matches if the particle is from a <@link language Particle Script Container>. + // "script" plaintext: matches if the particle is from a <@link language Particle Script Containers>. // Any particle type (see <@link tag ParticleTag.type> for formats): matches if the particle is of the given type, using advanced matchers. // Any particle script name: matches if the particle is from the given script, using advanced matchers. // @@ -222,8 +222,7 @@ public static void register() { // @mechanism ParticleTag.texture // @description // Returns the particle's current texture as a namespaced key, if it's of a type that has textures. - // Note that the texture id is within the particle texture atlas, - // "assets//textures/particle/.png" within the resource pack, and referenced as ":". + // Note that the texture id is within the particle texture atlas, see <@link Texture Atlases> for more information. // --> tagProcessor.registerTag(ElementTag.class, "texture", (attribute, object) -> { if (object.particle instanceof SpriteBillboardParticleAccessor spriteParticle) { @@ -238,8 +237,7 @@ public static void register() { // @input ElementTag // @description // Sets the particle's texture, if it's of a type that allows them. - // The input is a namespaced key of the texture, within the particle texture atlas - - // "assets//textures/particle/.png" within the resource pack, and referenced as ":". + // The input is a namespaced key of the texture within the particle texture atlas, see <@link Texture Atlases> for more information. // @tags // // --> diff --git a/src/main/java/com/denizenscript/clientizen/scripts/containers/ParticleScriptContainer.java b/src/main/java/com/denizenscript/clientizen/scripts/containers/ParticleScriptContainer.java index cd149c2..ce0ba45 100644 --- a/src/main/java/com/denizenscript/clientizen/scripts/containers/ParticleScriptContainer.java +++ b/src/main/java/com/denizenscript/clientizen/scripts/containers/ParticleScriptContainer.java @@ -37,6 +37,61 @@ public class ParticleScriptContainer extends ScriptContainer { + // <--[language] + // @name Texture Atlases + // @group Client Information + // @description + // A texture atlas is a group of textures for a specific use case. + // They are usually a folder under "assets//textures/" (see <@link url https://minecraft.wiki/w/Resource_pack#Folder_structure>), and contain textures. + // As each atlas is for a specific purpose and the client knows what a texture is for (E.g. when setting a texture on a particle it knows to look within the particle atlas), + // they can be referenced in code using just the namespace and texture name. + // So for example, "assets/my_server_pack/textures/particle/water_drop.png" can be referenced in a particle script as "my_server_pack:water_drop". + // --> + + // <--[language] + // @name Particle Script Containers + // @group Script Container System + // @description + // Particle script containers allow you to add your own custom particles, optionally setting their behaviour. + // They can be played using the <@link command particle> command by specifying the script name, see it's usage examples. + // + // + // Particle_Script_Name: + // type: particle + + // # The particle's texture list. + // # Can be a single texture to use, or a list of textures which will be picked from randomly when the particle is spawned in. + // # This is the texture list used for features like <@link mechanism ParticleTag.randomize_texture> and <@link mechanism ParticleTag.update_age_texture>. + // # Note that the textures must be within the particle texture atlas, see <@link language Texture Atlases> for more information. + // # | All particle scripts MUST have this key! + // textures: + // - : + // + // # Mechanisms to apply to the particle when it's spawned in. + // # | Some particle scripts should have this key. + // mechanisms: + // # Examples of mechanisms being used, any valid ParticleTag mechanism can be specified. + // + // # | Do not copy this line, it is only an example. + // color: red/blue/green/... + // + // # | Do not copy this line, it is only an example. + // velocity: 1,0.5,1 + // + // # The rate at which the particle's update code should run, as a <@link ObjectType DurationTag> - defaults to running every tick. + // # | Some particle scripts should have this key. + // update_rate: 1s + // + // # The particle's update code; runs every tick by default, or based on the update rate if specified. + // # Provides : a <@link ObjectType ParticleTag> of the particle from this particle script that's being updated. + // # | Some particle scripts should have this key. + // update: + // # Use to make a particle red once it hits the ground + // - if : + // - adjust color:red + // + // --> + public static final List customParticles = new ArrayList<>(); public static void clearCustomParticles() { From f1b8b2e9e17c59197ae069203d3d9142c7d4b1f5 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Thu, 18 Apr 2024 15:35:22 +0100 Subject: [PATCH 16/19] Update particle command meta --- .../clientizen/scripts/commands/ParticleCommand.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/denizenscript/clientizen/scripts/commands/ParticleCommand.java b/src/main/java/com/denizenscript/clientizen/scripts/commands/ParticleCommand.java index f5e4a2b..72b3169 100644 --- a/src/main/java/com/denizenscript/clientizen/scripts/commands/ParticleCommand.java +++ b/src/main/java/com/denizenscript/clientizen/scripts/commands/ParticleCommand.java @@ -45,7 +45,7 @@ public class ParticleCommand extends AbstractCommand { // // @Description // Spawns a particle of the specified type in the world. - // The type can be any particle type/script, including ones added by other mods - see <@link url https://minecraft.wiki/w/Particles_(Java_Edition)#Types_of_particles> for all vanilla particle types. + // The type can be any particle type/particle script, including ones added by other mods - see <@link url https://minecraft.wiki/w/Particles_(Java_Edition)#Types_of_particles> for all vanilla particle types. // The location can be any location to play the particle at. // The velocity is a vector location for the particle's movement, which overrides its default movement (if any). // The color will override the particle's color or color its texture (depending on the particle), and can be any color. @@ -78,7 +78,7 @@ public class ParticleCommand extends AbstractCommand { // - <@link ObjectType DurationTag> "delay" key, for the amount of time the particle should wait before spawning. // // @Tags - // None + // returns a <@link ObjectType ParticleTag> of the particle that was spawned in. // // @Usage // Use to spawn a large flame particle above the player. @@ -92,6 +92,10 @@ public class ParticleCommand extends AbstractCommand { // Use to spawn a block marker particle of a stone block that slowly moves upwards. // - particle type:block_marker at:<[location]> data:[material=stone] velocity:0,0.1,0 // + // @Usage + // Use to spawn a particle from a particle script at the player's location. + // - particle type:my_particle_script at: + // // --> public ParticleCommand() { From cf9f0a0f184ca042843b65f475dfa76730beb228 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Thu, 18 Apr 2024 16:38:53 +0100 Subject: [PATCH 17/19] Particle constructor meta (and friends) --- .../objects/ClientizenObjectRegistry.java | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/main/java/com/denizenscript/clientizen/objects/ClientizenObjectRegistry.java b/src/main/java/com/denizenscript/clientizen/objects/ClientizenObjectRegistry.java index 5aa164e..47e6e0d 100644 --- a/src/main/java/com/denizenscript/clientizen/objects/ClientizenObjectRegistry.java +++ b/src/main/java/com/denizenscript/clientizen/objects/ClientizenObjectRegistry.java @@ -13,11 +13,59 @@ public class ClientizenObjectRegistry { public static ObjectType TYPE_PARTICLE; public static void registerObjects() { + + // <--[tag] + // @attribute ]> + // @returns EntityTag + // @description + // Returns an entity object constructed from the input value. + // Refer to <@link ObjectType EntityTag>. + // --> TYPE_ENTITY = ObjectFetcher.registerWithObjectFetcher(EntityTag.class, EntityTag.tagProcessor).setAsNOtherCode().generateBaseTag(); + + // <--[tag] + // @attribute ]> + // @returns LocationTag + // @description + // Returns a location object constructed from the input value. + // Refer to <@link ObjectType LocationTag>. + // --> TYPE_LOCATION = ObjectFetcher.registerWithObjectFetcher(LocationTag.class, LocationTag.tagProcessor).setAsNOtherCode().setCanConvertStatic().generateBaseTag(); + + // <--[tag] + // @attribute ]> + // @returns MaterialTag + // @description + // Returns a material object constructed from the input value. + // Refer to <@link ObjectType MaterialTag>. + // --> TYPE_MATERIAL = ObjectFetcher.registerWithObjectFetcher(MaterialTag.class, MaterialTag.tagProcessor).generateBaseTag(); + + // <--[tag] + // @attribute ]> + // @returns ItemTag + // @description + // Returns an item object constructed from the input value. + // Refer to <@link ObjectType ItemTag>. + // --> TYPE_ITEM = ObjectFetcher.registerWithObjectFetcher(ItemTag.class, ItemTag.tagProcessor).setAsNOtherCode().generateBaseTag(); + + // <--[tag] + // @attribute ]> + // @returns ModTag + // @description + // Returns a mod object constructed from the input value. + // Refer to <@link ObjectType ModTag>. + // --> TYPE_MOD = ObjectFetcher.registerWithObjectFetcher(ModTag.class, ModTag.tagProcessor).setAsNOtherCode().setCanConvertStatic().generateBaseTag(); + + // <--[tag] + // @attribute ]> + // @returns ParticleTag + // @description + // Returns a particle object constructed from the input value. + // Refer to <@link ObjectType ParticleTag>. + // --> TYPE_PARTICLE = ObjectFetcher.registerWithObjectFetcher(ParticleTag.class, ParticleTag.tagProcessor).setAsNOtherCode().generateBaseTag(); } } From a1d6c8eb051960310c043d1a664839f03b65dc29 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Thu, 18 Apr 2024 18:56:25 +0100 Subject: [PATCH 18/19] Minor fixups --- .../clientizen/mixin/particle/BillboardParticleMixin.java | 3 ++- .../com/denizenscript/clientizen/objects/ParticleTag.java | 7 +++---- .../scripts/containers/ParticleScriptContainer.java | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/denizenscript/clientizen/mixin/particle/BillboardParticleMixin.java b/src/main/java/com/denizenscript/clientizen/mixin/particle/BillboardParticleMixin.java index f857fc4..7b115ee 100644 --- a/src/main/java/com/denizenscript/clientizen/mixin/particle/BillboardParticleMixin.java +++ b/src/main/java/com/denizenscript/clientizen/mixin/particle/BillboardParticleMixin.java @@ -14,6 +14,7 @@ public abstract class BillboardParticleMixin implements BillboardParticleMixinAc @Shadow protected float scale; + @Unique Float clientizen$scale; @@ -31,7 +32,7 @@ public abstract class BillboardParticleMixin implements BillboardParticleMixinAc method = "buildGeometry", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/particle/BillboardParticle;getSize(F)F") ) - private float clientizen$overrideSize(BillboardParticle particle, float tickDelta, Operation original) { + private float clientizen$overrideScale(BillboardParticle particle, float tickDelta, Operation original) { return clientizen$scale != null ? clientizen$scale : original.call(particle, tickDelta); } } diff --git a/src/main/java/com/denizenscript/clientizen/objects/ParticleTag.java b/src/main/java/com/denizenscript/clientizen/objects/ParticleTag.java index 49d3703..c7f9306 100644 --- a/src/main/java/com/denizenscript/clientizen/objects/ParticleTag.java +++ b/src/main/java/com/denizenscript/clientizen/objects/ParticleTag.java @@ -49,7 +49,7 @@ public class ParticleTag implements Adjustable, FlaggableObject { // // @description // A ParticleTag represents a particle that currently exists in the world. - // Either a normal vanilla particle, one from a <@link language Particle Script Containers>, or one from another mod. + // Can be either a normal vanilla particle, one from a <@link language Particle Script Containers>, or one from another mod. // // This object type is flaggable. // Flags on this object type will be stored on the particle. @@ -282,9 +282,6 @@ public static void register() { // Note that alpha values can be set, but only visually apply to some particles. // @tags // - // @example - // # Use to set a particle's color to a random color. - // - adjust <[particle]> color:random // --> tagProcessor.registerMechanism("color", false, ColorTag.class, (object, mechanism, input) -> { object.particle.setColor(input.red / 255f, input.green / 255f, input.blue / 255f); @@ -356,6 +353,7 @@ public static void register() { // @mechanism ParticleTag.time_to_live // @description // Returns the amount of time the particle should exist for. + // Note that this is the total amount of time it should exist for after spawning, the return value doesn't change with time passing. // See <@link tag ParticleTag.time_lived> for the amount of time the particle's existed. // @example // # Use to check how much time is left before the particle despawns. @@ -371,6 +369,7 @@ public static void register() { // @input DurationTag // @description // Sets the amount of time the particle should exist for. + // Note that this is the total amount of time it should exist for after spawning, not relative to the amount of time it's already existed for. // @tags // // @example diff --git a/src/main/java/com/denizenscript/clientizen/scripts/containers/ParticleScriptContainer.java b/src/main/java/com/denizenscript/clientizen/scripts/containers/ParticleScriptContainer.java index ce0ba45..df9f3de 100644 --- a/src/main/java/com/denizenscript/clientizen/scripts/containers/ParticleScriptContainer.java +++ b/src/main/java/com/denizenscript/clientizen/scripts/containers/ParticleScriptContainer.java @@ -53,7 +53,7 @@ public class ParticleScriptContainer extends ScriptContainer { // @group Script Container System // @description // Particle script containers allow you to add your own custom particles, optionally setting their behaviour. - // They can be played using the <@link command particle> command by specifying the script name, see it's usage examples. + // They can be played using the <@link command particle> command by specifying the script name, see it's usage examples/meta. // // // Particle_Script_Name: @@ -126,7 +126,6 @@ public static void registerCustomParticles() { public ParticleScriptContainer(YamlConfiguration configurationSection, String scriptContainerName) { super(configurationSection, scriptContainerName); Debug.pushErrorContext(this); - SpriteAtlasTexture particlesAtlas = ParticleTag.getParticleAtlas(); List textureInput = getStringList("textures", true); if (textureInput == null) { Debug.echoError("Missing required 'textures' key."); @@ -134,6 +133,7 @@ public ParticleScriptContainer(YamlConfiguration configurationSection, String sc updateScript = null; return; } + SpriteAtlasTexture particlesAtlas = ParticleTag.getParticleAtlas(); textures = new ArrayList<>(textureInput.size()); for (String texture : textureInput) { Identifier textureId = Identifier.tryParse(texture); @@ -184,7 +184,7 @@ protected ClientizenParticle(ClientWorld world, double x, double y, double z, do this.velocityX = velocityX; this.velocityY = velocityY; this.velocityZ = velocityZ; - this.scale = 1; + this.scale = 0.5f; this.spriteProvider = spriteProvider; this.particleScript = particleScript; this.scriptContext = new ContextSource.SimpleMap(); From 4ad8d29fca4b124b67635c64041c3ad1bde0e7b1 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Mon, 13 May 2024 15:51:23 +0100 Subject: [PATCH 19/19] 1.20.6 fixes --- .../denizenscript/clientizen/mixin/RegistryMixin.java | 9 +++------ .../scripts/containers/ParticleScriptContainer.java | 8 ++++---- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/denizenscript/clientizen/mixin/RegistryMixin.java b/src/main/java/com/denizenscript/clientizen/mixin/RegistryMixin.java index 7b7de2a..50c066d 100644 --- a/src/main/java/com/denizenscript/clientizen/mixin/RegistryMixin.java +++ b/src/main/java/com/denizenscript/clientizen/mixin/RegistryMixin.java @@ -9,6 +9,7 @@ import net.minecraft.registry.RegistryKey; import net.minecraft.registry.SimpleRegistry; import net.minecraft.registry.entry.RegistryEntry; +import net.minecraft.registry.entry.RegistryEntryInfo; import net.minecraft.util.Identifier; import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Final; @@ -20,7 +21,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import java.util.IdentityHashMap; -import java.util.List; import java.util.Map; @Mixin(SimpleRegistry.class) @@ -52,9 +52,7 @@ public abstract class RegistryMixin implements RegistryMixinAccess { private Map> valueToEntry; @Shadow @Final - private Map entryToLifecycle; - @Shadow - private @Nullable List> cachedEntries; + private Map, RegistryEntryInfo> keyToEntryInfo; @Override public void clientizen$unfreeze() { @@ -79,8 +77,7 @@ public abstract class RegistryMixin implements RegistryMixinAccess { valueToEntry.remove(value.value()); rawIdToEntry.remove(value); entryToRawId.removeInt(value.value()); - entryToLifecycle.remove(value.value()); - cachedEntries = null; + keyToEntryInfo.remove(key); } @Inject(method = "(Lnet/minecraft/registry/RegistryKey;Lcom/mojang/serialization/Lifecycle;Z)V", at = @At("TAIL")) diff --git a/src/main/java/com/denizenscript/clientizen/scripts/containers/ParticleScriptContainer.java b/src/main/java/com/denizenscript/clientizen/scripts/containers/ParticleScriptContainer.java index df9f3de..c85a6b8 100644 --- a/src/main/java/com/denizenscript/clientizen/scripts/containers/ParticleScriptContainer.java +++ b/src/main/java/com/denizenscript/clientizen/scripts/containers/ParticleScriptContainer.java @@ -25,8 +25,8 @@ import net.minecraft.client.texture.Sprite; import net.minecraft.client.texture.SpriteAtlasTexture; import net.minecraft.client.world.ClientWorld; -import net.minecraft.particle.DefaultParticleType; import net.minecraft.particle.ParticleType; +import net.minecraft.particle.SimpleParticleType; import net.minecraft.registry.Registries; import net.minecraft.registry.Registry; import net.minecraft.util.Identifier; @@ -109,7 +109,7 @@ public static void registerCustomParticles() { } Map spritesMap = ParticleTag.getSpriteProviders(); for (ParticleScriptContainer particleScript : customParticles) { - DefaultParticleType type = FabricParticleTypes.simple(); + SimpleParticleType type = FabricParticleTypes.simple(); Identifier particleId = particleScript.getId(); Registry.register(Registries.PARTICLE_TYPE, particleId, type); ParticleFactoryRegistry.getInstance().register(type, spriteProvider -> new ClientizenParticle.Factory(spriteProvider, particleScript)); @@ -225,10 +225,10 @@ public ParticleTextureSheet getType() { return ParticleTextureSheet.PARTICLE_SHEET_TRANSLUCENT; } - public record Factory(SpriteProvider spriteProvider, ParticleScriptContainer particleScript) implements ParticleFactory { + public record Factory(SpriteProvider spriteProvider, ParticleScriptContainer particleScript) implements ParticleFactory { @Override - public Particle createParticle(DefaultParticleType parameters, ClientWorld world, double x, double y, double z, double velocityX, double velocityY, double velocityZ) { + public Particle createParticle(SimpleParticleType parameters, ClientWorld world, double x, double y, double z, double velocityX, double velocityY, double velocityZ) { return new ClientizenParticle(world, x, y, z, velocityX, velocityY, velocityZ, spriteProvider, particleScript, parameters); } }