diff --git a/src/main/java/net/fretux/mindmotion/client/ClientData.java b/src/main/java/net/fretux/mindmotion/client/ClientData.java index 4d62cbe..376f524 100644 --- a/src/main/java/net/fretux/mindmotion/client/ClientData.java +++ b/src/main/java/net/fretux/mindmotion/client/ClientData.java @@ -4,4 +4,5 @@ public class ClientData { public static float SANITY = 80f; public static float INSANITY = 0f; public static int TEMPO = 0; + public static boolean IDENTITY_BLIND = false; } diff --git a/src/main/java/net/fretux/mindmotion/client/IdentityBlindnessFaceHider.java b/src/main/java/net/fretux/mindmotion/client/IdentityBlindnessFaceHider.java new file mode 100644 index 0000000..d74320b --- /dev/null +++ b/src/main/java/net/fretux/mindmotion/client/IdentityBlindnessFaceHider.java @@ -0,0 +1,27 @@ +package net.fretux.mindmotion.client; + +import net.minecraft.client.model.HumanoidModel; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.client.event.RenderLivingEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; + +@Mod.EventBusSubscriber(modid = "mindmotion", value = Dist.CLIENT) +public class IdentityBlindnessFaceHider { + + @SubscribeEvent + public static void hideFaces(RenderLivingEvent.Pre event) { + if (!ClientData.IDENTITY_BLIND) return; + if (event.getRenderer().getModel() instanceof HumanoidModel model) { + model.setAllVisible(false); + } + } + + @SubscribeEvent + public static void restoreFaces(RenderLivingEvent.Post event) { + if (event.getRenderer().getModel() instanceof HumanoidModel model) { + model.head.visible = true; + model.hat.visible = true; + } + } +} \ No newline at end of file diff --git a/src/main/java/net/fretux/mindmotion/client/IdentityBlindnessRenderer.java b/src/main/java/net/fretux/mindmotion/client/IdentityBlindnessRenderer.java new file mode 100644 index 0000000..59f0379 --- /dev/null +++ b/src/main/java/net/fretux/mindmotion/client/IdentityBlindnessRenderer.java @@ -0,0 +1,17 @@ +package net.fretux.mindmotion.client; + +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.client.event.RenderNameTagEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; + +@Mod.EventBusSubscriber(modid = "mindmotion", value = Dist.CLIENT) +public class IdentityBlindnessRenderer { + + @SubscribeEvent + public static void hideNameTags(RenderNameTagEvent event) { + if (ClientData.IDENTITY_BLIND) { + event.setResult(RenderNameTagEvent.Result.DENY); + } + } +} diff --git a/src/main/java/net/fretux/mindmotion/client/effects/SanityShaderHandler.java b/src/main/java/net/fretux/mindmotion/client/effects/SanityShaderHandler.java index 8582341..e6a5aca 100644 --- a/src/main/java/net/fretux/mindmotion/client/effects/SanityShaderHandler.java +++ b/src/main/java/net/fretux/mindmotion/client/effects/SanityShaderHandler.java @@ -90,10 +90,32 @@ public class SanityShaderHandler { for (PostPass pass : getPasses(chain)) { EffectInstance effect = pass.getEffect(); if (effect == null) continue; - var uniform = effect.getUniform("Desat"); - if (uniform != null) { - uniform.set(currentStrength); + var uDesat = effect.getUniform("Desat"); + if (uDesat != null) uDesat.set(currentStrength); + float blur = 0f; + float vig = 0f; + float fog = 0f; + + if (sanityPct < 0.5f) { + blur = (0.5f - sanityPct) * 0.6f; + vig = (0.5f - sanityPct) * 0.4f; + fog = (0.5f - sanityPct) * 0.25f; } + blur += insanityPct * 0.25f; + vig += insanityPct * 0.35f; + fog += insanityPct * 0.35f; + blur = Math.min(blur, 1f); + vig = Math.min(vig, 1f); + fog = Math.min(fog, 1f); + + var uBlur = effect.getUniform("BlurAmount"); + if (uBlur != null) uBlur.set(blur); + + var uVig = effect.getUniform("Vignette"); + if (uVig != null) uVig.set(vig); + + var uFog = effect.getUniform("FogStrength"); + if (uFog != null) uFog.set(fog); } } catch (Exception e) { e.printStackTrace(); diff --git a/src/main/java/net/fretux/mindmotion/event/PlayerTickHandler.java b/src/main/java/net/fretux/mindmotion/event/PlayerTickHandler.java index f8f379d..6e897fc 100644 --- a/src/main/java/net/fretux/mindmotion/event/PlayerTickHandler.java +++ b/src/main/java/net/fretux/mindmotion/event/PlayerTickHandler.java @@ -1,6 +1,7 @@ package net.fretux.mindmotion.event; import net.fretux.mindmotion.network.ModMessages; +import net.fretux.mindmotion.network.SyncIdentityBlindS2CPacket; import net.fretux.mindmotion.network.SyncStatsS2CPacket; import net.fretux.mindmotion.player.PlayerCapabilityProvider; import net.minecraft.server.level.ServerPlayer; @@ -11,6 +12,7 @@ import net.minecraft.world.level.block.Blocks; import net.minecraftforge.event.TickEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.network.NetworkDirection; import java.util.Map; import java.util.UUID; @@ -20,22 +22,24 @@ import java.util.concurrent.ConcurrentHashMap; public class PlayerTickHandler { private static final int SANITY_TICK_INTERVAL = 20; - private static final int TEMPO_TICK_INTERVAL = 15; - private static final int COMBAT_DECAY_DELAY = 100; + private static final int TEMPO_TICK_INTERVAL = 15; + private static final int COMBAT_DECAY_DELAY = 100; private static final Map lastCombatTick = new ConcurrentHashMap<>(); + private static final Map identityBlindUntil = new ConcurrentHashMap<>(); + private static final int IDENTITY_BLIND_DURATION = 30 * 20; @SubscribeEvent public static void onPlayerTick(TickEvent.PlayerTickEvent event) { if (event.phase != TickEvent.Phase.END) return; Player player = event.player; if (player.level().isClientSide) return; - + boolean blindActive = identityBlindUntil.getOrDefault(player.getUUID(), 0) > player.tickCount; int tick = player.tickCount; boolean sanityTick = tick % SANITY_TICK_INTERVAL == 0; - boolean tempoTick = tick % TEMPO_TICK_INTERVAL == 0; + boolean tempoTick = tick % TEMPO_TICK_INTERVAL == 0; if (sanityTick) handleSanityAndInsanity(player); - if (tempoTick) handleTempoTick(player, tick); + if (tempoTick) handleTempoTick(player, tick); if (player instanceof ServerPlayer serverPlayer && (sanityTick || tempoTick)) { player.getCapability(PlayerCapabilityProvider.SANITY).ifPresent(sanity -> @@ -52,31 +56,38 @@ public class PlayerTickHandler { ) ); } + if (player instanceof ServerPlayer serverPlayer && (sanityTick || tempoTick)) { + ModMessages.CHANNEL.sendTo( + new SyncIdentityBlindS2CPacket(blindActive), + serverPlayer.connection.connection, + NetworkDirection.PLAY_TO_CLIENT + ); + } } - + private static void handleSanityAndInsanity(Player player) { player.getCapability(PlayerCapabilityProvider.SANITY).ifPresent(sanity -> { float value = sanity.getSanity(); float insanity = sanity.getInsanity(); float delta = 0f; - boolean inDark = player.level().getMaxLocalRawBrightness(player.blockPosition()) < 5; - boolean inRain = player.level().isRainingAt(player.blockPosition()); - boolean isHungry = player.getFoodData().getFoodLevel() < 6; - boolean nearLava = player.level().getBlockState(player.blockPosition().below()).is(Blocks.LAVA); - boolean inWater = player.isInWater() && !player.isUnderWater(); - boolean underWater = player.isUnderWater(); - boolean sleeping = player.isSleeping(); - boolean inLight = player.level().getMaxLocalRawBrightness(player.blockPosition()) > 12; - boolean nearTorch = player.level().getBlockState(player.blockPosition().above()).is(Blocks.TORCH); - if (inDark) delta -= 0.02f; - if (inRain) delta -= 0.04f; - if (isHungry) delta -= 0.06f; - if (nearLava) delta -= 0.05f; - if (underWater) delta -= 0.04f; + boolean inDark = player.level().getMaxLocalRawBrightness(player.blockPosition()) < 5; + boolean inRain = player.level().isRainingAt(player.blockPosition()); + boolean isHungry = player.getFoodData().getFoodLevel() < 6; + boolean nearLava = player.level().getBlockState(player.blockPosition().below()).is(Blocks.LAVA); + boolean inWater = player.isInWater() && !player.isUnderWater(); + boolean underWater = player.isUnderWater(); + boolean sleeping = player.isSleeping(); + boolean inLight = player.level().getMaxLocalRawBrightness(player.blockPosition()) > 12; + boolean nearTorch = player.level().getBlockState(player.blockPosition().above()).is(Blocks.TORCH); + if (inDark) delta -= 2f; + if (inRain) delta -= 0.04f; + if (isHungry) delta -= 0.06f; + if (nearLava) delta -= 0.05f; + if (underWater) delta -= 0.04f; if (inWater && !underWater) delta -= 0.02f; - if (inLight) delta += 0.03f; - if (nearTorch) delta += 0.05f; - if (sleeping) delta += 0.25f; + if (inLight) delta += 0.03f; + if (nearTorch) delta += 0.05f; + if (sleeping) delta += 0.25f; if (player.getUseItem() != null && player.getUseItem().isEdible()) delta += 0.05f; sanity.setSanity(value + delta); if (sanity.getSanity() <= 0) { @@ -90,25 +101,22 @@ public class PlayerTickHandler { sanity.setInsanity(Math.max(0, insanity - 0.15f)); } float percent = (value / sanity.getMaxSanity()) * 100f; - if (percent <= 70 && percent > 50 && Math.random() < 0.03) - player.addEffect(new MobEffectInstance(MobEffects.MOVEMENT_SLOWDOWN, 40, 0)); // Shiver + if (percent <= 70 && percent > 50 && Math.random() < 0.03) { + applyShiver(player); + } if (percent <= 30 && percent > 10 && Math.random() < 0.015) { - player.addEffect(new MobEffectInstance(MobEffects.MOVEMENT_SLOWDOWN, 20, 1)); - player.hurt(player.damageSources().magic(), 1f); + applyPanic(player); } if (percent <= 10 && percent > 0 && Math.random() < 0.02) { - player.hurt(player.damageSources().magic(), 2f); - player.addEffect(new MobEffectInstance(MobEffects.MOVEMENT_SLOWDOWN, 30, 1)); + applyScratching(player); } float insanityPercent = (insanity / sanity.getMaxSanity()) * 100f; if (insanityPercent > 0) { if (insanityPercent > 60 && Math.random() < 0.02) { - player.addEffect(new MobEffectInstance(MobEffects.MOVEMENT_SLOWDOWN, 60, 1)); - player.hurt(player.damageSources().magic(), 1f); + applyPanic(player); } if (insanityPercent > 90 && Math.random() < 0.05) { - player.addEffect(new MobEffectInstance(MobEffects.MOVEMENT_SLOWDOWN, 60, 2)); - player.hurt(player.damageSources().magic(), 2f); + applyScratching(player); } } }); @@ -129,4 +137,26 @@ public class PlayerTickHandler { public static void markCombat(Player player) { lastCombatTick.put(player.getUUID(), player.tickCount); } + + public static void triggerIdentityBlindness(Player player) { + identityBlindUntil.put(player.getUUID(), player.tickCount + IDENTITY_BLIND_DURATION); + } + + private static void applyShiver(Player player) { + player.addEffect(new MobEffectInstance(MobEffects.MOVEMENT_SLOWDOWN, 40, 0)); + } + + private static void applyPanic(Player player) { + player.addEffect(new MobEffectInstance(MobEffects.MOVEMENT_SLOWDOWN, 20, 1)); + player.hurt(player.damageSources().magic(), 1f); + applyShiver(player); + triggerIdentityBlindness(player); + } + + private static void applyScratching(Player player) { + player.addEffect(new MobEffectInstance(MobEffects.MOVEMENT_SLOWDOWN, 30, 1)); + player.hurt(player.damageSources().magic(), 2f); + applyShiver(player); + triggerIdentityBlindness(player); + } } \ No newline at end of file diff --git a/src/main/java/net/fretux/mindmotion/network/ModMessages.java b/src/main/java/net/fretux/mindmotion/network/ModMessages.java index 63f06fc..0b322ab 100644 --- a/src/main/java/net/fretux/mindmotion/network/ModMessages.java +++ b/src/main/java/net/fretux/mindmotion/network/ModMessages.java @@ -26,5 +26,10 @@ public class ModMessages { .decoder(SyncStatsS2CPacket::decode) .consumerMainThread(SyncStatsS2CPacket::handle) .add(); + CHANNEL.messageBuilder(SyncIdentityBlindS2CPacket.class, nextId(), NetworkDirection.PLAY_TO_CLIENT) + .encoder(SyncIdentityBlindS2CPacket::encode) + .decoder(SyncIdentityBlindS2CPacket::decode) + .consumerMainThread(SyncIdentityBlindS2CPacket::handle) + .add(); } } diff --git a/src/main/java/net/fretux/mindmotion/network/SyncIdentityBlindS2CPacket.java b/src/main/java/net/fretux/mindmotion/network/SyncIdentityBlindS2CPacket.java new file mode 100644 index 0000000..d69b584 --- /dev/null +++ b/src/main/java/net/fretux/mindmotion/network/SyncIdentityBlindS2CPacket.java @@ -0,0 +1,31 @@ +package net.fretux.mindmotion.network; + +import net.fretux.mindmotion.client.ClientData; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraftforge.network.NetworkEvent; + +import java.util.function.Supplier; + +public class SyncIdentityBlindS2CPacket { + + private final boolean blind; + + public SyncIdentityBlindS2CPacket(boolean blind) { + this.blind = blind; + } + + public static void encode(SyncIdentityBlindS2CPacket msg, FriendlyByteBuf buf) { + buf.writeBoolean(msg.blind); + } + + public static SyncIdentityBlindS2CPacket decode(FriendlyByteBuf buf) { + return new SyncIdentityBlindS2CPacket(buf.readBoolean()); + } + + public static void handle(SyncIdentityBlindS2CPacket msg, Supplier ctx) { + ctx.get().enqueueWork(() -> { + ClientData.IDENTITY_BLIND = msg.blind; + }); + ctx.get().setPacketHandled(true); + } +} diff --git a/src/main/resources/assets/mindmotion/shaders/program/desaturate.fsh b/src/main/resources/assets/mindmotion/shaders/program/desaturate.fsh index 1dfc4af..cc0728a 100644 --- a/src/main/resources/assets/mindmotion/shaders/program/desaturate.fsh +++ b/src/main/resources/assets/mindmotion/shaders/program/desaturate.fsh @@ -2,15 +2,49 @@ uniform sampler2D DiffuseSampler; uniform float Desat; +uniform float BlurAmount; // NEW +uniform float Vignette; // NEW +uniform float FogStrength; // NEW in vec2 texCoord; -in vec2 oneTexel; // required by sobel.vsh, even if unused +in vec2 oneTexel; out vec4 fragColor; +vec4 sampleBlur() { + if (BlurAmount <= 0.001) return texture(DiffuseSampler, texCoord); + + // lighter blur kernel + float w = BlurAmount * 0.5; // reduce strength globally + + vec4 sum = vec4(0.0); + sum += texture(DiffuseSampler, texCoord + oneTexel * vec2(-1, 0)) * w; + sum += texture(DiffuseSampler, texCoord + oneTexel * vec2( 1, 0)) * w; + sum += texture(DiffuseSampler, texCoord + oneTexel * vec2( 0, -1)) * w; + sum += texture(DiffuseSampler, texCoord + oneTexel * vec2( 0, 1)) * w; + + // center weight higher to avoid total smudge + vec4 center = texture(DiffuseSampler, texCoord) * (1.0 - w * 4.0); + + return center + sum; +} + void main() { vec4 col = texture(DiffuseSampler, texCoord); + vec4 blurred = sampleBlur(); + col = mix(col, blurred, BlurAmount); // Apply blur + + // Apply grayscale/desat float gray = dot(col.rgb, vec3(0.2126, 0.7152, 0.0722)); - float d = clamp(Desat, 0.0, 1.0); - fragColor = vec4(mix(col.rgb, vec3(gray), d), col.a); -} + col.rgb = mix(col.rgb, vec3(gray), clamp(Desat, 0.0, 1.0)); + + // Fog: push color toward light gray + col.rgb = mix(col.rgb, vec3(0.75, 0.75, 0.8), FogStrength); + + // Vignette (darken edges) + float dist = distance(texCoord, vec2(0.5, 0.5)); + float vign = smoothstep(0.3, 0.7, dist); + col.rgb = mix(col.rgb, col.rgb * 0.4, vign * Vignette); + + fragColor = col; +} \ No newline at end of file diff --git a/src/main/resources/assets/mindmotion/shaders/program/desaturate.json b/src/main/resources/assets/mindmotion/shaders/program/desaturate.json index 9486a39..2a0076a 100644 --- a/src/main/resources/assets/mindmotion/shaders/program/desaturate.json +++ b/src/main/resources/assets/mindmotion/shaders/program/desaturate.json @@ -54,6 +54,24 @@ "values": [ 0.0 ] + }, + { + "name": "BlurAmount", + "type": "float", + "count": 1, + "values": [ 0.0 ] + }, + { + "name": "Vignette", + "type": "float", + "count": 1, + "values": [ 0.0 ] + }, + { + "name": "FogStrength", + "type": "float", + "count": 1, + "values": [ 0.0 ] } ] } \ No newline at end of file