Skip to content

Commit 8025680

Browse files
committed
Bare bones implementation of Colored Sound Particles
1 parent 662a3fe commit 8025680

File tree

17 files changed

+245
-54
lines changed

17 files changed

+245
-54
lines changed

src/main/java/ladysnake/requiem/client/particle/SoundParticle.java

Lines changed: 32 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
* You should have received a copy of the GNU General Public License
1616
* along with this program. If not, see <https://www.gnu.org/licenses>.
1717
*
18-
* Linking this mod statically or dynamically with second
18+
* Linking this mod statically or dynamically with other
1919
* modules is making a combined work based on this mod.
2020
* Thus, the terms and conditions of the GNU General Public License cover the whole combination.
2121
*
@@ -25,7 +25,7 @@
2525
* and with code included in the standard release of Minecraft under All Rights Reserved (or
2626
* modified versions of such code, with unchanged license).
2727
* You may copy and distribute such a system following the terms of the GNU GPL for this mod
28-
* and the licenses of the second code concerned.
28+
* and the licenses of the other code concerned.
2929
*
3030
* Note that people who make modified versions of this mod are not obligated to grant
3131
* this special exception for their modified versions; it is their choice whether to do so.
@@ -36,7 +36,9 @@
3636

3737
import com.mojang.blaze3d.systems.RenderSystem;
3838
import com.mojang.blaze3d.vertex.VertexConsumer;
39+
import ladysnake.requiem.api.v1.possession.PossessionComponent;
3940
import ladysnake.requiem.client.render.RequiemRenderPhases;
41+
import ladysnake.requiem.common.particle.RequiemSoundParticleEffect;
4042
import net.minecraft.client.MinecraftClient;
4143
import net.minecraft.client.particle.Particle;
4244
import net.minecraft.client.particle.ParticleFactory;
@@ -47,7 +49,6 @@
4749
import net.minecraft.client.render.VertexConsumerProvider;
4850
import net.minecraft.client.world.ClientWorld;
4951
import net.minecraft.entity.player.PlayerEntity;
50-
import net.minecraft.particle.DefaultParticleType;
5152
import net.minecraft.util.math.Axis;
5253
import net.minecraft.util.math.MathHelper;
5354
import net.minecraft.util.math.Vec3d;
@@ -56,24 +57,38 @@
5657
import org.lwjgl.opengl.GL11;
5758
import org.quiltmc.loader.api.minecraft.ClientOnly;
5859

59-
public class SoundParticle extends SpriteBillboardParticle {
60-
private final SpriteProvider spriteProvider;
60+
import java.awt.*;
6161

62+
public class SoundParticle extends SpriteBillboardParticle {
63+
public final SpriteProvider spriteProvider;
64+
private float red;
65+
private float green;
66+
private float blue;
67+
//private final ParticleTextureSheet sheet;
6268
//TODO: by:Redfan2: think about which VertexConsumer to use to not conflict with Darkness fog effect
63-
private static final VertexConsumerProvider.Immediate soundVertexConsumerProvider = MinecraftClient.getInstance().getBufferBuilders().getEntityVertexConsumers();
69+
private static final VertexConsumerProvider.Immediate soundVertexConsumerProvider = MinecraftClient.getInstance().getBufferBuilders().getEntityVertexConsumers();
70+
//Tessellator.getInstance().getBufferBuilder()
71+
//Doesnt render: Investigate: VertexConsumerProvider.immediate(new BufferBuilder(RequiemRenderPhases.GHOST_PARTICLE_LAYER.getExpectedBufferSize()));
6472

65-
public SoundParticle(ClientWorld world, double x, double y, double z, double velocityX, double velocityY, double velocityZ, SpriteProvider spriteProvider) {
73+
public SoundParticle(ClientWorld world, double x, double y, double z, double velocityX, double velocityY, double velocityZ, SpriteProvider spriteProvider, int color) {
6674
super(world, x, y, z, velocityX, velocityY, velocityZ);
6775
this.spriteProvider = spriteProvider;
6876
this.setSpriteForAge(spriteProvider);
69-
77+
//Testing
78+
Color tempColor = Color.BLUE;
79+
this.green = tempColor.getGreen();
80+
//this.sheet=new TextureSheet(spriteProvider);
81+
//Tessellator.getInstance().getBufferBuilder().
82+
this.red = tempColor.getRed();
83+
this.blue = tempColor.getBlue();
7084
this.maxAge = 10;
7185
this.collidesWithWorld = false;
7286
}
7387

7488
@Override
7589
public void buildGeometry(VertexConsumer vertexConsumer, Camera camera, float tickDelta) {
76-
if (camera.getFocusedEntity() instanceof PlayerEntity) {
90+
if (camera.getFocusedEntity() instanceof PlayerEntity player && player.getComponent(PossessionComponent.KEY).isPossessionOngoing()) {
91+
//TODO Disabled for testing if (player.getComponent(PossessionComponent.KEY).getHost() instanceof WardenEntity) {
7792
VertexConsumer actualConsumer = soundVertexConsumerProvider.getBuffer(RequiemRenderPhases.GHOST_PARTICLE_LAYER);
7893

7994
RenderSystem.disableDepthTest();
@@ -112,9 +127,6 @@ public void buildGeometry(VertexConsumer vertexConsumer, Camera camera, float ti
112127
int l = 15728880;
113128
float alpha = 1;
114129

115-
float red = 1f;
116-
float green = 1f;
117-
float blue = 1f;
118130
actualConsumer.vertex(Vec3fs[0].x(), Vec3fs[0].y(), Vec3fs[0].z()).uv(maxU, maxV).color(red, green, blue, alpha).light(l).next();
119131
actualConsumer.vertex(Vec3fs[1].x(), Vec3fs[1].y(), Vec3fs[1].z()).uv(maxU, minV).color(red, green, blue, alpha).light(l).next();
120132
actualConsumer.vertex(Vec3fs[2].x(), Vec3fs[2].y(), Vec3fs[2].z()).uv(minU, minV).color(red, green, blue, alpha).light(l).next();
@@ -124,7 +136,7 @@ public void buildGeometry(VertexConsumer vertexConsumer, Camera camera, float ti
124136
soundVertexConsumerProvider.draw();
125137
RenderSystem.enableDepthTest();
126138
RenderSystem.depthFunc(GL11.GL_LEQUAL);
127-
139+
//}
128140
} else {
129141
this.markDead();
130142
}
@@ -148,19 +160,20 @@ public void tick() {
148160
}
149161

150162
@ClientOnly
151-
public static class Factory implements ParticleFactory<DefaultParticleType> {
152-
private final SpriteProvider spriteProvider;
163+
public static class Factory implements ParticleFactory<RequiemSoundParticleEffect> {
164+
private final SpriteProvider factorySpriteProvider;
153165

154166
public Factory(SpriteProvider spriteProvider) {
155-
this.spriteProvider = spriteProvider;
167+
this.factorySpriteProvider = spriteProvider;
156168
}
157169

158-
public Particle createParticle(DefaultParticleType defaultParticleType, ClientWorld clientWorld, double d, double e, double f, double g, double h, double i) {
159-
return new SoundParticle(clientWorld, d, e, f, g, h, i, this.spriteProvider);
170+
@Override
171+
public Particle createParticle(RequiemSoundParticleEffect particleEffect, ClientWorld clientWorld, double d, double e, double f, double g, double h, double i) {
172+
return new SoundParticle(clientWorld, d, e, f, g, h, i, this.factorySpriteProvider, particleEffect.getColor());
160173
}
161174
}
162175

163-
//Stolen using Linkie
176+
//Stolen using Linkie from Minecraft itself as it doesn't exist on JOML Quaternions
164177
public void hamiltonProduct(Quaternionf first, Quaternionf second) {
165178
float var2 = first.x();
166179
float var3 = first.y();

src/main/java/ladysnake/requiem/common/entity/warden/WardenSensedComponent.java

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -36,22 +36,22 @@
3636

3737
import dev.onyxstudios.cca.api.v3.component.ComponentKey;
3838
import dev.onyxstudios.cca.api.v3.component.ComponentRegistry;
39+
import dev.onyxstudios.cca.api.v3.component.TransientComponent;
3940
import dev.onyxstudios.cca.api.v3.component.sync.AutoSyncedComponent;
40-
import dev.onyxstudios.cca.api.v3.entity.PlayerComponent;
4141
import ladysnake.requiem.Requiem;
4242
import ladysnake.requiem.api.v1.possession.PossessionComponent;
4343
import ladysnake.requiem.core.RequiemCore;
4444
import net.minecraft.entity.Entity;
4545
import net.minecraft.entity.mob.warden.WardenEntity;
4646
import net.minecraft.entity.player.PlayerEntity;
47-
import net.minecraft.nbt.NbtCompound;
47+
import net.minecraft.network.PacketByteBuf;
4848
import net.minecraft.server.network.ServerPlayerEntity;
4949

5050
import java.util.HashSet;
5151
import java.util.Set;
5252
import java.util.UUID;
5353

54-
public class WardenSensedComponent implements PlayerComponent<WardenSensedComponent>, AutoSyncedComponent {
54+
public class WardenSensedComponent implements TransientComponent, AutoSyncedComponent {
5555
/*TODO proper implementation of syncing
5656
*/
5757
public static final ComponentKey<WardenSensedComponent> KEY = ComponentRegistry.getOrCreate(RequiemCore.id("warden_sensed"), WardenSensedComponent.class);
@@ -67,13 +67,13 @@ public Set<UUID> getVisible() {
6767
}
6868

6969
@Override
70-
public void readFromNbt(NbtCompound nbt) {
71-
int size = nbt.getInt("list_size");
70+
public void applySyncPacket(PacketByteBuf buf) {
71+
int size = buf.readInt();
7272
if (size > 0) {
7373
Set<UUID> uuids = new HashSet<>();
7474
for (int i=0; i < size; i++) {
7575
try {
76-
uuids.add(nbt.getUuid("warden_target_"+i));
76+
uuids.add(buf.readUuid());
7777
} catch (Exception error) {
7878
Requiem.LOGGER.error("Could not read element {}","warden_target_"+i );
7979
Requiem.LOGGER.error("Reason: {}", error.getMessage());
@@ -83,17 +83,14 @@ public void readFromNbt(NbtCompound nbt) {
8383
}
8484
}
8585

86-
8786
@Override
88-
public void writeToNbt(NbtCompound nbt) {
87+
public void writeSyncPacket(PacketByteBuf buf, ServerPlayerEntity recipient) {
88+
8989
//TODO think about a better data format for this
9090
//MC only seems to have a ByteArray as closest, no UUIDArray or even just StringArray in NBTCompound
91-
nbt.putInt("list_size", entities.size());
91+
buf.writeInt(entities.size());
9292
for (int i = 0; i < entities.size(); i++) {
93-
nbt.putUuid(
94-
"warden_target_"+i,
95-
entities.stream().toList().get(i)
96-
);
93+
buf.writeUuid(entities.stream().toList().get(i));
9794
}
9895
}
9996

src/main/java/ladysnake/requiem/common/particle/RequiemParticleTypes.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@
3636

3737
import com.mojang.serialization.Codec;
3838
import ladysnake.requiem.Requiem;
39-
import ladysnake.requiem.client.particle.SoundParticle;
4039
import net.fabricmc.fabric.api.particle.v1.FabricParticleTypes;
4140
import net.minecraft.particle.DefaultParticleType;
4241
import net.minecraft.particle.ParticleType;
@@ -62,7 +61,12 @@ public Codec<WispTrailParticleEffect> getCodec() {
6261
};
6362
public static final DefaultParticleType OBELISK_SOUL = FabricParticleTypes.simple(false);
6463
public static final DefaultParticleType PENANCE = FabricParticleTypes.simple(false);
65-
public static final DefaultParticleType SOUND = FabricParticleTypes.simple(true);
64+
public static final ParticleType<RequiemSoundParticleEffect> SOUND = new ParticleType<>(false, RequiemSoundParticleEffect.PARAMETERS_FACTORY) {
65+
@Override
66+
public Codec<RequiemSoundParticleEffect> getCodec() {
67+
return RequiemSoundParticleEffect.codec(this);
68+
}
69+
};
6670

6771
public static void init() {
6872
Registry.register(Registries.PARTICLE_TYPE, Requiem.id("attrition"), ATTRITION);
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/*
2+
* Requiem
3+
* Copyright (C) 2017-2024 Ladysnake
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program. If not, see <https://www.gnu.org/licenses>.
17+
*
18+
* Linking this mod statically or dynamically with other
19+
* modules is making a combined work based on this mod.
20+
* Thus, the terms and conditions of the GNU General Public License cover the whole combination.
21+
*
22+
* In addition, as a special exception, the copyright holders of
23+
* this mod give you permission to combine this mod
24+
* with free software programs or libraries that are released under the GNU LGPL
25+
* and with code included in the standard release of Minecraft under All Rights Reserved (or
26+
* modified versions of such code, with unchanged license).
27+
* You may copy and distribute such a system following the terms of the GNU GPL for this mod
28+
* and the licenses of the other code concerned.
29+
*
30+
* Note that people who make modified versions of this mod are not obligated to grant
31+
* this special exception for their modified versions; it is their choice whether to do so.
32+
* The GNU General Public License gives permission to release a modified version without this exception;
33+
* this exception also makes it possible to release a modified version which carries forward this exception.
34+
*/
35+
package ladysnake.requiem.common.particle;
36+
37+
import com.mojang.brigadier.StringReader;
38+
import com.mojang.brigadier.exceptions.CommandSyntaxException;
39+
import com.mojang.serialization.Codec;
40+
import com.mojang.serialization.codecs.RecordCodecBuilder;
41+
import net.minecraft.network.PacketByteBuf;
42+
import net.minecraft.particle.ParticleEffect;
43+
import net.minecraft.particle.ParticleType;
44+
import net.minecraft.registry.Registries;
45+
46+
47+
public class RequiemSoundParticleEffect implements ParticleEffect {
48+
public RequiemSoundParticleEffect(ParticleType<RequiemSoundParticleEffect> type, int color) {
49+
this.type = type;
50+
this.color = color;
51+
}
52+
53+
public int color;
54+
private final ParticleType<RequiemSoundParticleEffect> type;
55+
56+
57+
public static final Factory<RequiemSoundParticleEffect> PARAMETERS_FACTORY = new Factory<>() {
58+
@Override
59+
public RequiemSoundParticleEffect read(ParticleType<RequiemSoundParticleEffect> particleType, StringReader stringReader) throws CommandSyntaxException {
60+
stringReader.expect(' ');
61+
int color = stringReader.readInt();
62+
return new RequiemSoundParticleEffect(particleType, color);
63+
}
64+
65+
@Override
66+
public RequiemSoundParticleEffect read(ParticleType<RequiemSoundParticleEffect> particleType, PacketByteBuf buf) {
67+
return new RequiemSoundParticleEffect(particleType, buf.readInt());
68+
}
69+
};
70+
71+
@Override
72+
public void write(PacketByteBuf buf) {
73+
buf.writeInt(color);
74+
}
75+
76+
@Override
77+
public String asString() {
78+
return "%s %d".formatted(Registries.PARTICLE_TYPE.getId(this.getType()), this.color);
79+
}
80+
81+
@Override
82+
public ParticleType<RequiemSoundParticleEffect> getType() {
83+
return this.type;
84+
}
85+
86+
public int getColor() {
87+
return this.color;
88+
}
89+
90+
public static Codec<RequiemSoundParticleEffect> codec(ParticleType particleType) {
91+
return RecordCodecBuilder.create(instance -> instance.group(
92+
Codec.INT.fieldOf("color").forGetter(RequiemSoundParticleEffect::getColor)
93+
).apply(instance, color -> new RequiemSoundParticleEffect(particleType, color)));
94+
}
95+
}

src/main/java/ladysnake/requiem/mixin/client/possession/EntityRenderDispatcherMixin.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,11 +104,12 @@ private static void preventShadowRender(MatrixStack matrices, VertexConsumerProv
104104
public void notRenderNonDetectedByWarden(Entity entity, Frustum frustum, double x, double y, double z, CallbackInfoReturnable<Boolean> info) {
105105

106106
/**/if (entity instanceof WardenEntity) {
107+
//TODO: by:Redfan2: Fix posessed warden itself not rendering
107108
info.setReturnValue(true);
108109
}
109110

110111
ClientPlayerEntity player = MinecraftClient.getInstance().player;
111-
//TODO: by:Redfan2: Fix posessed warden itself not rendering
112+
112113
if (requiem_camerasPossessed != null) {
113114
//Check for posession
114115
if (requiem_camerasPossessed instanceof WardenEntity) {

src/main/java/ladysnake/requiem/mixin/common/possession/gameplay/ServerWorldMixin.java

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,19 @@
3434
*/
3535
package ladysnake.requiem.mixin.common.possession.gameplay;
3636

37+
import ladysnake.requiem.Requiem;
3738
import ladysnake.requiem.api.v1.possession.PossessionComponent;
3839
import ladysnake.requiem.common.particle.RequiemParticleTypes;
40+
import ladysnake.requiem.common.particle.RequiemSoundParticleEffect;
3941
import net.minecraft.entity.mob.warden.WardenEntity;
4042
import net.minecraft.network.packet.Packet;
4143
import net.minecraft.network.packet.s2c.play.ParticleS2CPacket;
44+
import net.minecraft.registry.RegistryKeys;
4245
import net.minecraft.registry.tag.GameEventTags;
46+
import net.minecraft.registry.tag.TagKey;
4347
import net.minecraft.server.network.ServerPlayerEntity;
4448
import net.minecraft.server.world.ServerWorld;
49+
import net.minecraft.util.Identifier;
4550
import net.minecraft.util.math.Vec3d;
4651
import net.minecraft.world.event.GameEvent;
4752
import org.spongepowered.asm.mixin.Mixin;
@@ -50,6 +55,7 @@
5055
import org.spongepowered.asm.mixin.injection.Inject;
5156
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
5257

58+
import java.awt.*;
5359
import java.util.List;
5460

5561
@Mixin(ServerWorld.class)
@@ -64,11 +70,32 @@ public abstract class ServerWorldMixin {
6470
@Inject(method = "emitGameEvent(Lnet/minecraft/world/event/GameEvent;Lnet/minecraft/util/math/Vec3d;Lnet/minecraft/world/event/GameEvent$Context;)V",at=@At("HEAD"))
6571
public void emitGameEvent(GameEvent event, Vec3d pos, GameEvent.Context context, CallbackInfo ci) {
6672
if (event.isIn(GameEventTags.WARDEN_CAN_SENSE)) {
73+
//TODO: by:Redfan2: maybe ask Tags for Color
6774

68-
Packet<?> packet = new ParticleS2CPacket(RequiemParticleTypes.SOUND, true, pos.getX() + .5f, pos.getY() + .5f, pos.getZ() + .5f, 0, 0, 0, 0, 1);
75+
//Fallback
76+
Color color = Color.white;
77+
78+
if (event.isIn(TagKey.of(RegistryKeys.GAME_EVENT, new Identifier(Requiem.MOD_ID,"blocks")))) {
79+
color = Color.green;
80+
}
81+
if (event.isIn(TagKey.of(RegistryKeys.GAME_EVENT,new Identifier(Requiem.MOD_ID,"entities")))) {
82+
color = Color.cyan;
83+
}
84+
Packet<?> packet = new ParticleS2CPacket(
85+
new RequiemSoundParticleEffect(RequiemParticleTypes.SOUND, color.getRGB()),
86+
true,
87+
pos.getX() + .5f,
88+
pos.getY() + .5f,
89+
pos.getZ() + .5f,
90+
0,
91+
0,
92+
0,
93+
0,
94+
1
95+
);
6996
for (ServerPlayerEntity player : this.getPlayers()) {
7097
if (PossessionComponent.get(player).isPossessionOngoing() && PossessionComponent.getHost(player) instanceof WardenEntity && !(context.sourceEntity() instanceof WardenEntity)) {
71-
this.sendToPlayerIfNearby(player, true, pos.getX() + .5f, pos.getY() + .5f, pos.getZ() + .5f, packet);
98+
this.sendToPlayerIfNearby(player, true, pos.getX(), pos.getY(), pos.getZ(), packet);
7299
}
73100
}
74101
}

0 commit comments

Comments
 (0)