From dd9f5680a24589bae8990dfc25bc558935743f7c Mon Sep 17 00:00:00 2001 From: asanetargoss Date: Fri, 17 Apr 2020 22:54:22 -0700 Subject: [PATCH] Add config to prevent self morph particles --- .../java/mchorse/metamorph/ClientProxy.java | 5 + .../java/mchorse/metamorph/CommonProxy.java | 14 ++- .../java/mchorse/metamorph/Metamorph.java | 2 + .../metamorph/api/morphs/EntityMorph.java | 12 +- .../world/WorldEventListenerWrapper.java | 103 ++++++++++++++++++ .../mchorse/metamorph/world/WorldHandler.java | 102 +++++++++++++++++ .../assets/metamorph/lang/en_US.lang | 2 + 7 files changed, 237 insertions(+), 3 deletions(-) create mode 100644 src/main/java/mchorse/metamorph/world/WorldEventListenerWrapper.java create mode 100644 src/main/java/mchorse/metamorph/world/WorldHandler.java diff --git a/src/main/java/mchorse/metamorph/ClientProxy.java b/src/main/java/mchorse/metamorph/ClientProxy.java index a2e6628a..f88021f1 100644 --- a/src/main/java/mchorse/metamorph/ClientProxy.java +++ b/src/main/java/mchorse/metamorph/ClientProxy.java @@ -187,4 +187,9 @@ public boolean canEditSelectors() { return OpHelper.isPlayerOp() || Metamorph.opEntitySelector.get(); } + + public boolean isDedicatedServer() + { + return false; + } } \ No newline at end of file diff --git a/src/main/java/mchorse/metamorph/CommonProxy.java b/src/main/java/mchorse/metamorph/CommonProxy.java index 20a34164..40ad6915 100644 --- a/src/main/java/mchorse/metamorph/CommonProxy.java +++ b/src/main/java/mchorse/metamorph/CommonProxy.java @@ -1,5 +1,7 @@ package mchorse.metamorph; +import java.io.File; + import mchorse.metamorph.api.MorphHandler; import mchorse.metamorph.api.MorphManager; import mchorse.metamorph.api.MorphUtils; @@ -14,6 +16,7 @@ import mchorse.metamorph.entity.EntityMorph; import mchorse.metamorph.entity.SoundHandler; import mchorse.metamorph.network.Dispatcher; +import mchorse.metamorph.world.WorldHandler; import mchorse.vanilla_pack.MetamorphFactory; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.util.ResourceLocation; @@ -23,8 +26,6 @@ import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; import net.minecraftforge.fml.common.registry.EntityRegistry; -import java.io.File; - /** * Common proxy * @@ -90,6 +91,7 @@ public void load() /* Event listeners */ MinecraftForge.EVENT_BUS.register(new MorphHandler()); MinecraftForge.EVENT_BUS.register(new SoundHandler()); + MinecraftForge.EVENT_BUS.register(new WorldHandler()); MinecraftForge.EVENT_BUS.register(new CapabilityHandler()); MinecraftForge.EVENT_BUS.register(new RegisterHandler()); @@ -132,4 +134,12 @@ public boolean canEditSelectors() { return true; } + + /** + * Changed to false in ClientProxy + */ + public boolean isDedicatedServer() + { + return true; + } } \ No newline at end of file diff --git a/src/main/java/mchorse/metamorph/Metamorph.java b/src/main/java/mchorse/metamorph/Metamorph.java index f1e5fd37..635a7977 100644 --- a/src/main/java/mchorse/metamorph/Metamorph.java +++ b/src/main/java/mchorse/metamorph/Metamorph.java @@ -77,6 +77,7 @@ public class Metamorph public static ValueBoolean disableFirstPersonHand; public static ValueBoolean morphInTightSpaces; public static ValueBoolean showMorphIdleSounds; + public static ValueBoolean spawnParticlesFirstPerson; public static ValueBoolean pauseGUIInSP; public static ValueBoolean renderBodyPartAxis; public static ValueInt maxRecentMorphs; @@ -107,6 +108,7 @@ public void onConfigRegister(RegisterConfigEvent event) disableFirstPersonHand.clientSide(); morphInTightSpaces = builder.getBoolean("morph_in_tight_spaces", false); showMorphIdleSounds = builder.getBoolean("show_morph_idle_sounds", true); + spawnParticlesFirstPerson = builder.getBoolean("spawn_particles_first_person", false); pauseGUIInSP = builder.getBoolean("pause_gui_in_sp", true); pauseGUIInSP.clientSide(); renderBodyPartAxis = builder.getBoolean("render_bodypart_axis", true); diff --git a/src/main/java/mchorse/metamorph/api/morphs/EntityMorph.java b/src/main/java/mchorse/metamorph/api/morphs/EntityMorph.java index e32863b8..40aa2c4f 100644 --- a/src/main/java/mchorse/metamorph/api/morphs/EntityMorph.java +++ b/src/main/java/mchorse/metamorph/api/morphs/EntityMorph.java @@ -13,6 +13,7 @@ import mchorse.metamorph.capabilities.morphing.Morphing; import mchorse.metamorph.entity.SoundHandler; import mchorse.metamorph.util.InvokeUtil; +import mchorse.metamorph.world.WorldHandler; import net.minecraft.block.Block; import net.minecraft.client.Minecraft; import net.minecraft.client.model.ModelBase; @@ -782,8 +783,17 @@ protected void updateEntity(EntityLivingBase target) { this.entity.setSilent(true); } - + boolean spawnParticles = WorldHandler.shouldSpawnMorphParticles(target); + if (!spawnParticles) + { + // Blaze morphs generate so many particles that it makes it too hard to see in first person + WorldHandler.setEnableWorldParticles(target.world, false); + } this.entity.onUpdate(); + if (!spawnParticles) + { + WorldHandler.setEnableWorldParticles(target.world, true); + } this.entity.setSilent(false); } } diff --git a/src/main/java/mchorse/metamorph/world/WorldEventListenerWrapper.java b/src/main/java/mchorse/metamorph/world/WorldEventListenerWrapper.java new file mode 100644 index 00000000..244bf834 --- /dev/null +++ b/src/main/java/mchorse/metamorph/world/WorldEventListenerWrapper.java @@ -0,0 +1,103 @@ +package mchorse.metamorph.world; + +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.SoundCategory; +import net.minecraft.util.SoundEvent; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IWorldEventListener; +import net.minecraft.world.World; + +public class WorldEventListenerWrapper implements IWorldEventListener +{ + public boolean spawnParticles = true; + + protected IWorldEventListener delegate; + + public WorldEventListenerWrapper(IWorldEventListener delegate) + { + this.delegate = delegate; + } + + @Override + public void notifyBlockUpdate(World worldIn, BlockPos pos, IBlockState oldState, IBlockState newState, int flags) + { + delegate.notifyBlockUpdate(worldIn, pos, oldState, newState, flags); + } + + @Override + public void notifyLightSet(BlockPos pos) + { + delegate.notifyLightSet(pos); + } + + @Override + public void markBlockRangeForRenderUpdate(int x1, int y1, int z1, int x2, int y2, int z2) + { + delegate.markBlockRangeForRenderUpdate(x1, y1, z1, x2, y2, z2); + } + + @Override + public void playSoundToAllNearExcept(EntityPlayer player, SoundEvent soundIn, SoundCategory category, double x, + double y, double z, float volume, float pitch) + { + delegate.playSoundToAllNearExcept(player, soundIn, category, x, y, z, volume, pitch); + } + + @Override + public void playRecord(SoundEvent soundIn, BlockPos pos) + { + delegate.playRecord(soundIn, pos); + } + + @Override + public void spawnParticle(int particleID, boolean ignoreRange, double xCoord, double yCoord, double zCoord, + double xSpeed, double ySpeed, double zSpeed, int... parameters) + { + if (spawnParticles) + { + delegate.spawnParticle(particleID, ignoreRange, xCoord, yCoord, zCoord, xSpeed, ySpeed, zSpeed, parameters); + } + } + + @Override + public void spawnParticle(int particleID, boolean ignoreRange, boolean p_190570_3_, double xCoord, double yCoord, double zCoord, + double xSpeed, double ySpeed, double zSpeed, int... parameters) + { + if (spawnParticles) + { + delegate.spawnParticle(particleID, ignoreRange, p_190570_3_, xCoord, yCoord, zCoord, xSpeed, ySpeed, zSpeed, parameters); + } + } + + @Override + public void onEntityAdded(Entity entityIn) + { + delegate.onEntityAdded(entityIn); + } + + @Override + public void onEntityRemoved(Entity entityIn) + { + delegate.onEntityRemoved(entityIn); + } + + @Override + public void broadcastSound(int soundID, BlockPos pos, int data) + { + delegate.broadcastSound(soundID, pos, data); + } + + @Override + public void playEvent(EntityPlayer player, int type, BlockPos blockPosIn, int data) + { + delegate.playEvent(player, type, blockPosIn, data); + } + + @Override + public void sendBlockBreakProgress(int breakerId, BlockPos pos, int progress) + { + delegate.sendBlockBreakProgress(breakerId, pos, progress); + } +} diff --git a/src/main/java/mchorse/metamorph/world/WorldHandler.java b/src/main/java/mchorse/metamorph/world/WorldHandler.java new file mode 100644 index 00000000..65490ce8 --- /dev/null +++ b/src/main/java/mchorse/metamorph/world/WorldHandler.java @@ -0,0 +1,102 @@ +package mchorse.metamorph.world; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; +import java.util.WeakHashMap; + +import mchorse.metamorph.Metamorph; +import mchorse.metamorph.util.ObfuscatedName; +import net.minecraft.client.Minecraft; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.world.IWorldEventListener; +import net.minecraft.world.World; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.TickEvent.ClientTickEvent; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +/** + * Adds hook to prevent particles spawning in first person + */ +public class WorldHandler +{ + public static final ObfuscatedName EVENT_LISTENERS = new ObfuscatedName("field_73021_x"); + + protected static boolean spawnClientParticles = true; + + protected static WeakHashMap> worldListenersClient = new WeakHashMap<>(); + protected static WeakHashMap> worldListenersServer = new WeakHashMap<>(); + + public static List getListenersForWorld(World world) + { + WeakHashMap> listenersPerWorld = world.isRemote ? worldListenersClient : worldListenersServer; + List ourListeners = listenersPerWorld.get(world); + if (ourListeners == null) + { + ourListeners = new ArrayList(); + listenersPerWorld.put(world, ourListeners); + try + { + Field eventListenersField = World.class.getDeclaredField(EVENT_LISTENERS.getName()); + eventListenersField.setAccessible(true); + @SuppressWarnings("unchecked") + List vanillaListeners = (List)eventListenersField.get(world); + int listenerCount = vanillaListeners.size(); + for (int i = 0; i < listenerCount; ++i) + { + WorldEventListenerWrapper wrapper = new WorldEventListenerWrapper(vanillaListeners.get(i)); + vanillaListeners.set(i, wrapper); + ourListeners.add(wrapper); + } + } + catch (Exception e) + { + e.printStackTrace(); + } + } + return ourListeners; + } + + public static void setEnableWorldParticles(World world, boolean enable) { + List worldListeners = getListenersForWorld(world); + for (WorldEventListenerWrapper listener : worldListeners) { + listener.spawnParticles = enable; + } + } + + @SubscribeEvent + public void onUpdateClient(ClientTickEvent event) + { + spawnClientParticles = Metamorph.spawnParticlesFirstPerson.get() || !ClientSide.isFirstPerson(); + } + + public static boolean shouldSpawnMorphParticles(Entity entity) + { + return spawnClientParticles || Metamorph.proxy.isDedicatedServer() || !ClientSide.isThePlayerByID(entity); + } + + @SideOnly(Side.CLIENT) + public static class ClientSide + { + public static boolean isFirstPerson() + { + return Minecraft.getMinecraft().gameSettings.thirdPersonView == 0; + } + + public static boolean isThePlayerByID(Entity entity) + { + if (entity == null) + { + return false; + } + EntityPlayer thePlayer = Minecraft.getMinecraft().player; + if (thePlayer == null) + { + return false; + } + return entity.getEntityId() == thePlayer.getEntityId(); + } + } +} diff --git a/src/main/resources/assets/metamorph/lang/en_US.lang b/src/main/resources/assets/metamorph/lang/en_US.lang index 1336bded..f556d62b 100644 --- a/src/main/resources/assets/metamorph/lang/en_US.lang +++ b/src/main/resources/assets/metamorph/lang/en_US.lang @@ -198,6 +198,8 @@ metamorph.config.morphs.morph_in_tight_spaces=Allow morphing in tight spaces metamorph.config.comments.morphs.morph_in_tight_spaces=Allows morphing even if it could cause suffocation and allow passing through walls metamorph.config.morphs.show_morph_idle_sounds=Show morph idle sounds metamorph.config.comments.morphs.show_morph_idle_sounds=Whether players make entity idle sounds when morphed +metamorph.config.morphs.spawn_particles_first_person=Spawn morph particles in first person +metamorph.config.comments.morphs.spawn_particles_first_person=If false, prevents the player's own morph from spawning particles when using the first-person camera. metamorph.config.morphs.pause_gui_in_sp=Pause morph GUIs metamorph.config.comments.morphs.pause_gui_in_sp=Whether creative and survival morph GUIs should be paused in singleplayer metamorph.config.morphs.max_recent_morphs=Max. recent morphs