Skip to content

Commit 5610164

Browse files
committed
Added Fun Creepers
1 parent 897ed68 commit 5610164

3 files changed

Lines changed: 210 additions & 0 deletions

File tree

src/main/java/net/wurstclient/hack/HackList.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ public final class HackList implements UpdateListener
151151
public final ForceOpHack forceOpHack = new ForceOpHack();
152152
public final FreecamHack freecamHack = new FreecamHack();
153153
public final FullbrightHack fullbrightHack = new FullbrightHack();
154+
public final FunCreepersHack funCreepersHack = new FunCreepersHack();
154155
public final GlideHack glideHack = new GlideHack();
155156
public final HandNoClipHack handNoClipHack = new HandNoClipHack();
156157
public final HeadRollHack headRollHack = new HeadRollHack();
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
/*
2+
* Copyright (c) 2014-2026 Wurst-Imperium and contributors.
3+
*
4+
* This source code is subject to the terms of the GNU General Public
5+
* License, version 3. If a copy of the GPL was not distributed with this
6+
* file, You can obtain one at: https://www.gnu.org/licenses/gpl-3.0.txt
7+
*/
8+
package net.wurstclient.hacks;
9+
10+
import net.minecraft.core.particles.DustParticleOptions;
11+
import net.minecraft.core.particles.ParticleTypes;
12+
import net.minecraft.sounds.SoundEvent;
13+
import net.minecraft.sounds.SoundEvents;
14+
import net.minecraft.sounds.SoundSource;
15+
import net.minecraft.util.RandomSource;
16+
import net.minecraft.world.entity.monster.Creeper;
17+
import net.minecraft.world.phys.AABB;
18+
import net.minecraft.world.phys.Vec3;
19+
import net.wurstclient.Category;
20+
import net.wurstclient.hack.Hack;
21+
import net.wurstclient.settings.CheckboxSetting;
22+
import net.wurstclient.settings.SliderSetting;
23+
import net.wurstclient.settings.SliderSetting.ValueDisplay;
24+
25+
public final class FunCreepersHack extends Hack
26+
{
27+
private final SliderSetting excitement = new SliderSetting("Excitement",
28+
"Controls how intense and chaotic the celebration gets.", 100, 25, 300,
29+
25, ValueDisplay.PERCENTAGE);
30+
31+
private final SliderSetting creeperDetectionRange =
32+
new SliderSetting("Creeper Detection Range",
33+
"Only explosions near a creeper in this radius are transformed.", 4,
34+
1, 12, 0.5, ValueDisplay.DECIMAL);
35+
36+
private final SliderSetting fireworks = new SliderSetting("Fireworks",
37+
"How many fireworks sparks burst out per transformed explosion.", 35, 5,
38+
200, 5, ValueDisplay.INTEGER);
39+
40+
private final SliderSetting confetti = new SliderSetting("Confetti",
41+
"How much confetti-like villager happiness pops out.", 60, 10, 300, 10,
42+
ValueDisplay.INTEGER);
43+
44+
private final SliderSetting sparkles = new SliderSetting("Sparkles",
45+
"How many colorful sparkles get sprayed around.", 90, 20, 400, 10,
46+
ValueDisplay.INTEGER);
47+
48+
private final CheckboxSetting replaceSound =
49+
new CheckboxSetting("Replace Sound",
50+
"Replace explosion sound with a happy firework sound.", true);
51+
52+
private final RandomSource random = RandomSource.create();
53+
54+
public FunCreepersHack()
55+
{
56+
super("FunCreepers",
57+
"Turns creeper explosions into a colorful fireworks party.", false);
58+
setCategory(Category.FUN);
59+
addSetting(excitement);
60+
addSetting(creeperDetectionRange);
61+
addSetting(fireworks);
62+
addSetting(confetti);
63+
addSetting(sparkles);
64+
addSetting(replaceSound);
65+
}
66+
67+
public boolean shouldPartyifyExplosion(Vec3 center)
68+
{
69+
if(!isEnabled() || MC.level == null || center == null)
70+
return false;
71+
72+
double range = creeperDetectionRange.getValue();
73+
AABB box = new AABB(center, center).inflate(range);
74+
return MC.level.getEntitiesOfClass(Creeper.class, box).stream()
75+
.anyMatch(
76+
creeper -> creeper.distanceToSqr(center) <= range * range);
77+
}
78+
79+
public void spawnPartyEffects(Vec3 center)
80+
{
81+
if(!isEnabled() || MC.level == null || center == null)
82+
return;
83+
84+
int fireworksCount = scaledCount(fireworks.getValueI());
85+
int confettiCount = scaledCount(confetti.getValueI());
86+
int sparkleCount = scaledCount(sparkles.getValueI());
87+
88+
for(int i = 0; i < fireworksCount; i++)
89+
{
90+
double dx = randomRange(0.8);
91+
double dy = randomRange(0.8) + 0.25;
92+
double dz = randomRange(0.8);
93+
MC.level.addParticle(ParticleTypes.FIREWORK, center.x,
94+
center.y + 0.2, center.z, dx, dy, dz);
95+
}
96+
97+
for(int i = 0; i < confettiCount; i++)
98+
{
99+
double x = center.x + randomRange(2.5);
100+
double y = center.y + random.nextDouble() * 2.5;
101+
double z = center.z + randomRange(2.5);
102+
double dx = randomRange(0.15);
103+
double dy = random.nextDouble() * 0.2;
104+
double dz = randomRange(0.15);
105+
MC.level.addParticle(ParticleTypes.HAPPY_VILLAGER, x, y, z, dx, dy,
106+
dz);
107+
}
108+
109+
for(int i = 0; i < sparkleCount; i++)
110+
{
111+
int color = random.nextInt(0x1000000);
112+
double x = center.x + randomRange(2.0);
113+
double y = center.y + random.nextDouble() * 2.0;
114+
double z = center.z + randomRange(2.0);
115+
double dx = randomRange(0.2);
116+
double dy = random.nextDouble() * 0.25;
117+
double dz = randomRange(0.2);
118+
MC.level.addParticle(new DustParticleOptions(color, 1.0F), x, y, z,
119+
dx, dy, dz);
120+
if(random.nextBoolean())
121+
MC.level.addParticle(ParticleTypes.END_ROD, x, y, z, dx * 0.7,
122+
dy * 0.7, dz * 0.7);
123+
}
124+
}
125+
126+
public SoundEvent getReplacementExplosionSound()
127+
{
128+
if(!isEnabled() || !replaceSound.isChecked())
129+
return null;
130+
131+
return random.nextBoolean() ? SoundEvents.FIREWORK_ROCKET_BLAST
132+
: SoundEvents.FIREWORK_ROCKET_TWINKLE;
133+
}
134+
135+
public float getReplacementVolume()
136+
{
137+
return (float)Math.min(3.0, 1.2 * excitementMultiplier());
138+
}
139+
140+
public float getReplacementPitch()
141+
{
142+
float base = 1.0F + (float)(random.nextDouble() * 0.5);
143+
return base * (float)Math.min(1.8, excitementMultiplier());
144+
}
145+
146+
public SoundSource getReplacementSoundSource()
147+
{
148+
return SoundSource.PLAYERS;
149+
}
150+
151+
private int scaledCount(int base)
152+
{
153+
return (int)Math.round(base * excitementMultiplier());
154+
}
155+
156+
private double excitementMultiplier()
157+
{
158+
return excitement.getValue() / 100.0;
159+
}
160+
161+
private double randomRange(double halfSpan)
162+
{
163+
return random.nextDouble() * halfSpan * 2 - halfSpan;
164+
}
165+
}

src/main/java/net/wurstclient/mixin/ClientPacketListenerMixin.java

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,17 @@
1212
import org.spongepowered.asm.mixin.Mixin;
1313
import org.spongepowered.asm.mixin.injection.At;
1414
import org.spongepowered.asm.mixin.injection.Inject;
15+
import org.spongepowered.asm.mixin.injection.Redirect;
1516
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
1617
import net.minecraft.client.Minecraft;
1718
import net.minecraft.client.gui.components.toasts.SystemToast;
1819
import net.minecraft.client.multiplayer.ClientCommonPacketListenerImpl;
20+
import net.minecraft.client.multiplayer.ClientLevel;
1921
import net.minecraft.client.multiplayer.ClientPacketListener;
2022
import net.minecraft.client.multiplayer.CommonListenerCookie;
2123
import net.minecraft.client.player.LocalPlayer;
24+
import net.minecraft.sounds.SoundEvent;
25+
import net.minecraft.sounds.SoundSource;
2226
import net.minecraft.network.Connection;
2327
import net.minecraft.network.TickablePacketListener;
2428
import net.minecraft.network.chat.Component;
@@ -113,6 +117,46 @@ private void onOnChunkDeltaUpdate(
113117
});
114118
}
115119

120+
@Inject(
121+
method = "handleExplosion(Lnet/minecraft/network/protocol/game/ClientboundExplodePacket;)V",
122+
at = @At("HEAD"))
123+
private void wurst$funCreepersParticles(ClientboundExplodePacket packet,
124+
CallbackInfo ci)
125+
{
126+
Vec3 center = packet.center();
127+
var funCreepers = WurstClient.INSTANCE.getHax().funCreepersHack;
128+
if(!funCreepers.shouldPartyifyExplosion(center))
129+
return;
130+
131+
funCreepers.spawnPartyEffects(center);
132+
}
133+
134+
@Redirect(
135+
method = "handleExplosion(Lnet/minecraft/network/protocol/game/ClientboundExplodePacket;)V",
136+
at = @At(value = "INVOKE",
137+
target = "Lnet/minecraft/client/multiplayer/ClientLevel;playLocalSound(DDDLnet/minecraft/sounds/SoundEvent;Lnet/minecraft/sounds/SoundSource;FFZ)V"))
138+
private void wurst$funCreepersSound(ClientLevel level, double x, double y,
139+
double z, SoundEvent sound, SoundSource source, float volume,
140+
float pitch, boolean useDistanceDelay, ClientboundExplodePacket packet)
141+
{
142+
var funCreepers = WurstClient.INSTANCE.getHax().funCreepersHack;
143+
if(funCreepers.shouldPartyifyExplosion(packet.center()))
144+
{
145+
SoundEvent replacement = funCreepers.getReplacementExplosionSound();
146+
if(replacement != null)
147+
{
148+
level.playLocalSound(x, y, z, replacement,
149+
funCreepers.getReplacementSoundSource(),
150+
funCreepers.getReplacementVolume(),
151+
funCreepers.getReplacementPitch(), useDistanceDelay);
152+
return;
153+
}
154+
}
155+
156+
level.playLocalSound(x, y, z, sound, source, volume, pitch,
157+
useDistanceDelay);
158+
}
159+
116160
@Inject(
117161
method = "handleExplosion(Lnet/minecraft/network/protocol/game/ClientboundExplodePacket;)V",
118162
at = @At(value = "INVOKE",

0 commit comments

Comments
 (0)