From 593d918ce95f9543fc92c1209c87ff8e29cc4ead Mon Sep 17 00:00:00 2001 From: ev chang Date: Wed, 19 Jun 2024 22:51:17 +0700 Subject: [PATCH] - fix compat in singleplayer - "Cleaner Particles" feature --- build.gradle.kts | 6 +- .../mixin/EffectRendererMixin.java | 37 +++++++----- .../mixin/EntityLivingBaseMixin.java | 14 ++++- .../overflowparticles/mixin/EntityMixin.java | 5 ++ .../overflowparticles/mixin/WorldMixin.java | 4 ++ .../overflowparticles/config/MainConfig.kt | 1 + .../overflowparticles/config/ParticleEntry.kt | 4 +- .../overflowparticles/config/Settings.kt | 7 +++ .../polyfrost/overflowparticles/utils/Util.kt | 57 +++++++++++++++---- 9 files changed, 106 insertions(+), 29 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 417171b..cb97810 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -53,6 +53,7 @@ loom { runConfigs { "client" { programArgs("--tweakClass", "cc.polyfrost.oneconfig.loader.stage0.LaunchWrapperTweaker") + property("fml.coreMods.load", "org.polyfrost.craftycrashes.plugin.LegacyCraftyCrashesLoadingPlugin") property("mixin.debug.export", "true") } } @@ -87,16 +88,19 @@ sourceSets { // Adds the Polyfrost maven repository so that we can get the libraries necessary to develop the mod. repositories { + mavenLocal() maven("https://repo.polyfrost.org/releases") } // Configures the libraries/dependencies for your mod. dependencies { // Adds the OneConfig library, so we can develop with it. - modCompileOnly("cc.polyfrost:oneconfig-$platform:0.2.2-alpha199") + modCompileOnly("cc.polyfrost:oneconfig-$platform:0.2.2-alpha+") modRuntimeOnly("me.djtheredstoner:DevAuth-${if (platform.isFabric) "fabric" else if (platform.isLegacyForge) "forge-legacy" else "forge-latest"}:1.2.0") + modRuntimeOnly("org.polyfrost:legacycraftycrashes:1.0.0") + // If we are building for legacy forge, includes the launch wrapper with `shade` as we configured earlier. if (platform.isLegacyForge) { compileOnly("org.spongepowered:mixin:0.7.11-SNAPSHOT") diff --git a/src/main/java/org/polyfrost/overflowparticles/mixin/EffectRendererMixin.java b/src/main/java/org/polyfrost/overflowparticles/mixin/EffectRendererMixin.java index dbfd35d..0e36ad0 100644 --- a/src/main/java/org/polyfrost/overflowparticles/mixin/EffectRendererMixin.java +++ b/src/main/java/org/polyfrost/overflowparticles/mixin/EffectRendererMixin.java @@ -1,17 +1,24 @@ package org.polyfrost.overflowparticles.mixin; -import net.minecraft.client.particle.*; +import net.minecraft.client.particle.EffectRenderer; +import net.minecraft.client.particle.EntityDiggingFX; +import net.minecraft.client.particle.EntityFX; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.WorldRenderer; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.entity.Entity; import org.polyfrost.overflowparticles.OverflowParticles; -import org.polyfrost.overflowparticles.config.*; -import org.spongepowered.asm.mixin.*; +import org.polyfrost.overflowparticles.config.MainConfig; +import org.polyfrost.overflowparticles.config.ModConfig; +import org.polyfrost.overflowparticles.config.ParticleConfig; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.*; -import org.spongepowered.asm.mixin.injection.callback.*; -import org.spongepowered.asm.mixin.injection.invoke.arg.Args; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import java.util.Collection; import java.util.List; @Mixin(EffectRenderer.class) @@ -21,7 +28,7 @@ public abstract class EffectRendererMixin { private List[][] fxLayers; @Unique - private int ID; + private int overflowParticles$ID; @Redirect(method = "renderLitParticles", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/particle/EntityFX;renderParticle(Lnet/minecraft/client/renderer/WorldRenderer;Lnet/minecraft/entity/Entity;FFFFFF)V")) private void a(EntityFX instance, WorldRenderer worldRendererIn, Entity entityIn, float partialTicks, float rotationX, float rotationZ, float rotationYZ, float rotationXY, float rotationXZ) { @@ -72,20 +79,23 @@ private void handle(EntityFX instance, WorldRenderer worldRendererIn, Entity ent @Inject(method = "spawnEffectParticle", at = @At("HEAD")) private void spawn(int particleId, double xCoord, double yCoord, double zCoord, double xSpeed, double p_178927_10_, double p_178927_12_, int[] p_178927_14_, CallbackInfoReturnable cir) { - ID = particleId; + overflowParticles$ID = particleId; } - @ModifyArgs(method = "spawnEffectParticle", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/particle/EffectRenderer;addEffect(Lnet/minecraft/client/particle/EntityFX;)V")) - private void spawn(Args args) { - put(args.get(0), ID); + @ModifyArg(method = "spawnEffectParticle", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/particle/EffectRenderer;addEffect(Lnet/minecraft/client/particle/EntityFX;)V", ordinal = 0)) + private EntityFX spawn(EntityFX effect) { + put(effect, overflowParticles$ID); + return effect; } - @ModifyArgs(method = "updateEffectAlphaLayer", at = @At(value = "INVOKE", target = "Ljava/util/List;removeAll(Ljava/util/Collection;)Z")) - private void update(Args args) { - List list = args.get(0); + @ModifyArg(method = "updateEffectAlphaLayer", at = @At(value = "INVOKE", target = "Ljava/util/List;removeAll(Ljava/util/Collection;)Z", ordinal = 0)) + private Collection update(Collection c) { + List list = c instanceof List ? (List) c : null; + if (list == null) return c; for (EntityFX entityFX : list) { remove(entityFX); } + return c; } @Inject(method = "addEffect", at = @At("HEAD")) @@ -139,5 +149,4 @@ private void removeBlockBreakingParticles_Forge(CallbackInfo ci) { ci.cancel(); } } - } diff --git a/src/main/java/org/polyfrost/overflowparticles/mixin/EntityLivingBaseMixin.java b/src/main/java/org/polyfrost/overflowparticles/mixin/EntityLivingBaseMixin.java index 7b6a5fe..657d820 100644 --- a/src/main/java/org/polyfrost/overflowparticles/mixin/EntityLivingBaseMixin.java +++ b/src/main/java/org/polyfrost/overflowparticles/mixin/EntityLivingBaseMixin.java @@ -5,20 +5,29 @@ import net.minecraft.block.material.Material; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; +import net.minecraft.world.World; import org.polyfrost.overflowparticles.OverflowParticles; import org.polyfrost.overflowparticles.config.BlockParticleEntry; import org.polyfrost.overflowparticles.config.MainConfig; import org.polyfrost.overflowparticles.config.ModConfig; import org.polyfrost.overflowparticles.config.ParticleConfig; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.*; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(EntityLivingBase.class) -public class EntityLivingBaseMixin { +public abstract class EntityLivingBaseMixin extends Entity { + public EntityLivingBaseMixin(World worldIn) { + super(worldIn); + } + + @Shadow public abstract boolean isServerWorld(); + @SuppressWarnings({"ConstantConditions"}) @Inject(method = "updatePotionEffects", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/World;spawnParticle(Lnet/minecraft/util/EnumParticleTypes;DDDDDD[I)V"), cancellable = true) private void cleanView(CallbackInfo ci) { + if (worldObj != null & isServerWorld()) return; if (MainConfig.INSTANCE.getSettings().getCleanView() && (Object) this == UMinecraft.getPlayer()) { ci.cancel(); } @@ -26,13 +35,14 @@ private void cleanView(CallbackInfo ci) { @Redirect(method = "updateFallState", at = @At(value = "INVOKE", target = "Lnet/minecraft/block/Block;getMaterial()Lnet/minecraft/block/material/Material;")) private Material fall(Block instance) { + if (worldObj != null & isServerWorld()) return instance.getMaterial(); ParticleConfig config = OverflowParticles.INSTANCE.getConfigs().get(37); if (!config.enabled) return Material.air; BlockParticleEntry entry = ModConfig.INSTANCE.getBlockSetting(); if (entry.getHideRunning()) { if (entry.getHideMode()) { return Material.air; - } else if (!((Entity) (Object) this).isInvisible()) { + } else if (!isInvisible()) { return Material.air; } } diff --git a/src/main/java/org/polyfrost/overflowparticles/mixin/EntityMixin.java b/src/main/java/org/polyfrost/overflowparticles/mixin/EntityMixin.java index e8136be..364ef7b 100644 --- a/src/main/java/org/polyfrost/overflowparticles/mixin/EntityMixin.java +++ b/src/main/java/org/polyfrost/overflowparticles/mixin/EntityMixin.java @@ -3,6 +3,7 @@ import net.minecraft.client.particle.EntityFX; import net.minecraft.entity.Entity; import net.minecraft.util.AxisAlignedBB; +import net.minecraft.world.World; import org.polyfrost.overflowparticles.OverflowParticles; import org.polyfrost.overflowparticles.config.BlockParticleEntry; import org.polyfrost.overflowparticles.config.MainConfig; @@ -24,6 +25,8 @@ public abstract class EntityMixin { @Shadow protected abstract void resetPositionToBB(); + @Shadow public World worldObj; + @Inject(method = "getBrightnessForRender", at = @At("HEAD"), cancellable = true) private void staticColor(float partialTicks, CallbackInfoReturnable cir) { if (MainConfig.INSTANCE.getSettings().getStaticParticleColor() && ((Entity) (Object) this) instanceof EntityFX) { @@ -33,6 +36,7 @@ private void staticColor(float partialTicks, CallbackInfoReturnable cir @Inject(method = "moveEntity", at = @At("HEAD"), cancellable = true) private void enableNoClip(double x, double y, double z, CallbackInfo ci) { + if (worldObj != null && !worldObj.isRemote) return; if (MainConfig.INSTANCE.getSettings().getParticleNoClip() && ((Entity) (Object) this) instanceof EntityFX) { this.setEntityBoundingBox(this.getEntityBoundingBox().offset(x, y, z)); this.resetPositionToBB(); @@ -42,6 +46,7 @@ private void enableNoClip(double x, double y, double z, CallbackInfo ci) { @Inject(method = "spawnRunningParticles", at = @At("HEAD"), cancellable = true) private void runningParticle(CallbackInfo ci) { + if (worldObj != null && !worldObj.isRemote) return; ParticleConfig config = OverflowParticles.INSTANCE.getConfigs().get(37); if (!config.enabled) ci.cancel(); BlockParticleEntry entry = ModConfig.INSTANCE.getBlockSetting(); diff --git a/src/main/java/org/polyfrost/overflowparticles/mixin/WorldMixin.java b/src/main/java/org/polyfrost/overflowparticles/mixin/WorldMixin.java index a6df8f7..b4e988e 100644 --- a/src/main/java/org/polyfrost/overflowparticles/mixin/WorldMixin.java +++ b/src/main/java/org/polyfrost/overflowparticles/mixin/WorldMixin.java @@ -5,6 +5,7 @@ import org.polyfrost.overflowparticles.OverflowParticles; import org.polyfrost.overflowparticles.config.ParticleConfig; import org.polyfrost.overflowparticles.utils.UtilKt; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; @@ -18,8 +19,11 @@ public class WorldMixin { @Shadow protected List worldAccesses; + @Shadow @Final public boolean isRemote; + @Inject(method = "spawnParticle(IZDDDDDD[I)V", at = @At("HEAD"), cancellable = true) private void multiplier(int particleID, boolean ignoreRange, double xCoord, double yCoord, double zCoord, double xOffset, double yOffset, double zOffset, int[] arguments, CallbackInfo ci) { + if (!isRemote) return; ParticleConfig config = OverflowParticles.INSTANCE.getConfigs().get(particleID); if (config == null || config.getEntry().getMultiplier() == 1 || config.getId() == 28) return; UtilKt.spawn(config, worldAccesses, particleID, ignoreRange, xCoord, yCoord, zCoord, xOffset, yOffset, zOffset, arguments); diff --git a/src/main/kotlin/org/polyfrost/overflowparticles/config/MainConfig.kt b/src/main/kotlin/org/polyfrost/overflowparticles/config/MainConfig.kt index 2d6654b..092b415 100644 --- a/src/main/kotlin/org/polyfrost/overflowparticles/config/MainConfig.kt +++ b/src/main/kotlin/org/polyfrost/overflowparticles/config/MainConfig.kt @@ -47,6 +47,7 @@ object MainConfig : SubConfig("Settings", "", "/assets/oneconfig/icons/settings- @SubscribeEvent fun onAttack(event: AttackEntityEvent) { + if (!event.target.worldObj.isRemote) return if (settings.checkInvulnerable) { if (event.entityPlayer.entityId == mc.thePlayer.entityId) { attacker = event.entityPlayer diff --git a/src/main/kotlin/org/polyfrost/overflowparticles/config/ParticleEntry.kt b/src/main/kotlin/org/polyfrost/overflowparticles/config/ParticleEntry.kt index b555631..570b36d 100644 --- a/src/main/kotlin/org/polyfrost/overflowparticles/config/ParticleEntry.kt +++ b/src/main/kotlin/org/polyfrost/overflowparticles/config/ParticleEntry.kt @@ -21,8 +21,8 @@ class ParticleEntry { var size = 1.0f get() = field.coerceIn(0f, 5f) - @Slider(name = "Multiplier", min = 1f, max = 10f) - var multiplier = 1 + @Slider(name = "Multiplier", min = 0f, max = 10f) + var multiplier = 1f @Button(name = "", text = "Reset", size = 2) var reset = Runnable { diff --git a/src/main/kotlin/org/polyfrost/overflowparticles/config/Settings.kt b/src/main/kotlin/org/polyfrost/overflowparticles/config/Settings.kt index 5a74f4a..c956ef8 100644 --- a/src/main/kotlin/org/polyfrost/overflowparticles/config/Settings.kt +++ b/src/main/kotlin/org/polyfrost/overflowparticles/config/Settings.kt @@ -7,6 +7,13 @@ import cc.polyfrost.oneconfig.config.core.ConfigUtils class Settings { + @Switch( + name = "Cleaner Particles", + description = "Remove the random offset from particles.", + subcategory = "Features" + ) + var cleanerParticles = true + @Switch( name = "Clean View", description = "Stop rendering your potion effect particles.", diff --git a/src/main/kotlin/org/polyfrost/overflowparticles/utils/Util.kt b/src/main/kotlin/org/polyfrost/overflowparticles/utils/Util.kt index 5f8dfa2..914e035 100644 --- a/src/main/kotlin/org/polyfrost/overflowparticles/utils/Util.kt +++ b/src/main/kotlin/org/polyfrost/overflowparticles/utils/Util.kt @@ -1,21 +1,58 @@ package org.polyfrost.overflowparticles.utils import net.minecraft.world.IWorldAccess +import org.polyfrost.overflowparticles.config.MainConfig import org.polyfrost.overflowparticles.config.ParticleConfig -fun color(color: Int, targetColor: Float, cfg: ParticleConfig) : Float = +fun color(color: Int, targetColor: Float, cfg: ParticleConfig): Float = if (cfg.entry.customColor) color / 255f * if (cfg.entry.colorMode) 1f else targetColor else targetColor -fun colorInt(color: Int, targetColor: Float, cfg: ParticleConfig) : Int = - (color(color, targetColor, cfg) * 255f).toInt() +fun colorInt(color: Int, targetColor: Float, cfg: ParticleConfig): Int = (color(color, targetColor, cfg) * 255f).toInt() -fun spawn(config: ParticleConfig, worldAccesses: List, particleID: Int, ignoreRange: Boolean, x: Double, y: Double, z: Double, xOffset: Double, yOffset: Double, zOffset: Double, vararg arguments: Int) { - repeat(config.entry.multiplier) { - for (worldAccess in worldAccesses) { - val modX = x - 0.5 + Math.random() - val modY = y - 0.5 + Math.random() - val modZ = z - 0.5 + Math.random() - worldAccess.spawnParticle(particleID, ignoreRange, modX, modY, modZ, xOffset, yOffset, zOffset, *arguments); +fun spawn( + config: ParticleConfig, + worldAccesses: List, + particleID: Int, + ignoreRange: Boolean, + x: Double, + y: Double, + z: Double, + xOffset: Double, + yOffset: Double, + zOffset: Double, + vararg arguments: Int +) { + val multiplier = config.entry.multiplier + val integerPart = multiplier.toInt() + val fractionalPart = multiplier - integerPart + + repeat(integerPart) { + spawnParticle(worldAccesses, particleID, ignoreRange, x, y, z, xOffset, yOffset, zOffset, *arguments) + } + + if (fractionalPart > 0) { + if (Math.random() < fractionalPart) { + spawnParticle(worldAccesses, particleID, ignoreRange, x, y, z, xOffset, yOffset, zOffset, *arguments) } } +} + +private fun spawnParticle( + worldAccesses: List, + particleID: Int, + ignoreRange: Boolean, + x: Double, + y: Double, + z: Double, + xOffset: Double, + yOffset: Double, + zOffset: Double, + vararg arguments: Int +) { + for (worldAccess in worldAccesses) { + val modX = x - (if (!MainConfig.settings.cleanerParticles) 0.5 + Math.random() else 0.0) + val modY = y - (if (!MainConfig.settings.cleanerParticles) 0.5 + Math.random() else 0.0) + val modZ = z - (if (!MainConfig.settings.cleanerParticles) 0.5 + Math.random() else 0.0) + worldAccess.spawnParticle(particleID, ignoreRange, modX, modY, modZ, xOffset, yOffset, zOffset, *arguments) + } } \ No newline at end of file