diff --git a/src/main/java/com/tiedup/remake/minigame/StruggleSessionManager.java b/src/main/java/com/tiedup/remake/minigame/StruggleSessionManager.java index 9ecdb06..654ed9a 100644 --- a/src/main/java/com/tiedup/remake/minigame/StruggleSessionManager.java +++ b/src/main/java/com/tiedup/remake/minigame/StruggleSessionManager.java @@ -83,16 +83,16 @@ public class StruggleSessionManager { ) { UUID playerId = player.getUUID(); - // Remove any existing continuous session + // RISK-002 fix: reject if active session exists (prevents direction re-roll exploit) ContinuousStruggleMiniGameState existing = continuousSessions.get( playerId ); if (existing != null) { TiedUpMod.LOGGER.debug( - "[StruggleSessionManager] Replacing existing continuous struggle session for {}", + "[StruggleSessionManager] Rejected continuous session: active session already exists for {}", player.getName().getString() ); - continuousSessions.remove(playerId); + return null; } // Create new session with configurable rate @@ -146,12 +146,16 @@ public class StruggleSessionManager { ) { UUID playerId = player.getUUID(); - // Remove any existing session + // RISK-002 fix: reject if active session exists (prevents direction re-roll exploit) ContinuousStruggleMiniGameState existing = continuousSessions.get( playerId ); if (existing != null) { - continuousSessions.remove(playerId); + TiedUpMod.LOGGER.debug( + "[StruggleSessionManager] Rejected accessory session: active session already exists for {}", + player.getName().getString() + ); + return null; } // Create new session with target slot and configurable rate diff --git a/src/main/java/com/tiedup/remake/v2/bondage/V2EquipmentManager.java b/src/main/java/com/tiedup/remake/v2/bondage/V2EquipmentManager.java index 8567a47..1f98cb6 100644 --- a/src/main/java/com/tiedup/remake/v2/bondage/V2EquipmentManager.java +++ b/src/main/java/com/tiedup/remake/v2/bondage/V2EquipmentManager.java @@ -1,6 +1,7 @@ package com.tiedup.remake.v2.bondage; import com.tiedup.remake.core.TiedUpMod; +import com.tiedup.remake.items.base.ILockable; import com.tiedup.remake.v2.BodyRegionV2; import java.util.ArrayList; import java.util.IdentityHashMap; @@ -149,7 +150,14 @@ public final class V2EquipmentManager { return V2EquipResult.swapped(conflictStack); } } else { - // Non-V2 item in region — log warning and remove + // Non-V2 item in region — RISK-003 fix: check if locked before removing + if (conflictStack.getItem() instanceof ILockable lockable && lockable.isLocked(conflictStack)) { + TiedUpMod.LOGGER.warn( + "V2EquipmentManager: blocked swap of locked non-V2 item {} from equipment", + conflictStack + ); + return V2EquipResult.BLOCKED; + } TiedUpMod.LOGGER.warn( "V2EquipmentManager: swapping out non-V2 item {} from equipment", conflictStack diff --git a/src/main/java/com/tiedup/remake/v2/bondage/network/PacketV2SelfLock.java b/src/main/java/com/tiedup/remake/v2/bondage/network/PacketV2SelfLock.java index c59ee11..b9cdfd7 100644 --- a/src/main/java/com/tiedup/remake/v2/bondage/network/PacketV2SelfLock.java +++ b/src/main/java/com/tiedup/remake/v2/bondage/network/PacketV2SelfLock.java @@ -41,9 +41,10 @@ public class PacketV2SelfLock { if (player == null) return; if (!PacketRateLimiter.allowPacket(player, "action")) return; - // Arms must be free to self-lock + // Arms and hands must be free to self-lock (RISK-006: mittens bypass) if ( - V2EquipmentHelper.isRegionOccupied(player, BodyRegionV2.ARMS) + V2EquipmentHelper.isRegionOccupied(player, BodyRegionV2.ARMS) || + V2EquipmentHelper.isRegionOccupied(player, BodyRegionV2.HANDS) ) return; ItemStack equipped = V2EquipmentHelper.getInRegion( diff --git a/src/main/java/com/tiedup/remake/v2/bondage/network/PacketV2SelfUnlock.java b/src/main/java/com/tiedup/remake/v2/bondage/network/PacketV2SelfUnlock.java index 79c5a0c..607ca69 100644 --- a/src/main/java/com/tiedup/remake/v2/bondage/network/PacketV2SelfUnlock.java +++ b/src/main/java/com/tiedup/remake/v2/bondage/network/PacketV2SelfUnlock.java @@ -42,9 +42,10 @@ public class PacketV2SelfUnlock { if (player == null) return; if (!PacketRateLimiter.allowPacket(player, "action")) return; - // Arms must be free to self-unlock + // Arms and hands must be free to self-unlock (RISK-006: mittens bypass) if ( - V2EquipmentHelper.isRegionOccupied(player, BodyRegionV2.ARMS) + V2EquipmentHelper.isRegionOccupied(player, BodyRegionV2.ARMS) || + V2EquipmentHelper.isRegionOccupied(player, BodyRegionV2.HANDS) ) return; ItemStack equipped = V2EquipmentHelper.getInRegion(