feature/d01-branch-a-bridge #6
@@ -248,8 +248,8 @@ public class PacketSelfBondage {
|
|||||||
IV2BondageItem v2Item,
|
IV2BondageItem v2Item,
|
||||||
IBondageState state
|
IBondageState state
|
||||||
) {
|
) {
|
||||||
// Can't self-tie if already tied
|
// Can't self-tie if already tied (check both V1 state and V2 region to prevent dual-bind)
|
||||||
if (state.isTiedUp()) {
|
if (state.isTiedUp() || V2EquipmentHelper.isRegionOccupied(player, BodyRegionV2.ARMS)) {
|
||||||
TiedUpMod.LOGGER.debug("[SelfBondage] {} tried V2 self-tie but already tied", player.getName().getString());
|
TiedUpMod.LOGGER.debug("[SelfBondage] {} tried V2 self-tie but already tied", player.getName().getString());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,8 +46,8 @@ public final class TyingInteractionHelper {
|
|||||||
return InteractionResult.PASS;
|
return InteractionResult.PASS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Already tied — try to swap
|
// Already tied — try to swap (check both V1 state and V2 region to prevent dual-bind)
|
||||||
if (targetState.isTiedUp()) {
|
if (targetState.isTiedUp() || V2EquipmentHelper.isRegionOccupied(target, BodyRegionV2.ARMS)) {
|
||||||
if (stack.isEmpty()) return InteractionResult.PASS;
|
if (stack.isEmpty()) return InteractionResult.PASS;
|
||||||
ItemStack oldBind = V2EquipmentHelper.unequipFromRegion(target, BodyRegionV2.ARMS);
|
ItemStack oldBind = V2EquipmentHelper.unequipFromRegion(target, BodyRegionV2.ARMS);
|
||||||
if (!oldBind.isEmpty()) {
|
if (!oldBind.isEmpty()) {
|
||||||
@@ -59,8 +59,14 @@ public final class TyingInteractionHelper {
|
|||||||
return InteractionResult.SUCCESS;
|
return InteractionResult.SUCCESS;
|
||||||
} else {
|
} else {
|
||||||
// Equip failed — rollback: re-equip old bind
|
// Equip failed — rollback: re-equip old bind
|
||||||
V2EquipmentHelper.equipItem(target, oldBind);
|
V2EquipResult rollback = V2EquipmentHelper.equipItem(target, oldBind);
|
||||||
TiedUpMod.LOGGER.debug("[TyingInteraction] Swap failed, rolled back old bind on {}", target.getName().getString());
|
if (!rollback.isSuccess()) {
|
||||||
|
// Rollback also failed — drop old bind as safety net
|
||||||
|
target.spawnAtLocation(oldBind);
|
||||||
|
TiedUpMod.LOGGER.warn("[TyingInteraction] Swap AND rollback failed, dropped old bind for {}", target.getName().getString());
|
||||||
|
} else {
|
||||||
|
TiedUpMod.LOGGER.debug("[TyingInteraction] Swap failed, rolled back old bind on {}", target.getName().getString());
|
||||||
|
}
|
||||||
return InteractionResult.PASS;
|
return InteractionResult.PASS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,11 +23,14 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
public class GaggingComponent implements IItemComponent {
|
public class GaggingComponent implements IItemComponent {
|
||||||
|
|
||||||
private final @Nullable String material;
|
private final @Nullable String material;
|
||||||
|
private final @Nullable GagMaterial cachedMaterial;
|
||||||
private final double comprehensionOverride;
|
private final double comprehensionOverride;
|
||||||
private final double rangeOverride;
|
private final double rangeOverride;
|
||||||
|
|
||||||
private GaggingComponent(@Nullable String material, double comprehensionOverride, double rangeOverride) {
|
private GaggingComponent(@Nullable String material, @Nullable GagMaterial cachedMaterial,
|
||||||
|
double comprehensionOverride, double rangeOverride) {
|
||||||
this.material = material;
|
this.material = material;
|
||||||
|
this.cachedMaterial = cachedMaterial;
|
||||||
this.comprehensionOverride = comprehensionOverride;
|
this.comprehensionOverride = comprehensionOverride;
|
||||||
this.rangeOverride = rangeOverride;
|
this.rangeOverride = rangeOverride;
|
||||||
}
|
}
|
||||||
@@ -47,7 +50,16 @@ public class GaggingComponent implements IItemComponent {
|
|||||||
range = Math.max(0.0, config.get("range").getAsDouble());
|
range = Math.max(0.0, config.get("range").getAsDouble());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new GaggingComponent(material, comprehension, range);
|
// Resolve and cache GagMaterial at load time to avoid valueOf() on every chat message
|
||||||
|
GagMaterial resolved = null;
|
||||||
|
if (material != null) {
|
||||||
|
try {
|
||||||
|
resolved = GagMaterial.valueOf(material.toUpperCase());
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
TiedUpMod.LOGGER.warn("[GaggingComponent] Unknown gag material '{}' — using defaults", material);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new GaggingComponent(material, resolved, comprehension, range);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** How much of the gagged speech is comprehensible (0.0 = nothing, 1.0 = full). */
|
/** How much of the gagged speech is comprehensible (0.0 = nothing, 1.0 = full). */
|
||||||
@@ -66,15 +78,9 @@ public class GaggingComponent implements IItemComponent {
|
|||||||
return 10.0;
|
return 10.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The gag material enum, or null if not configured or invalid. */
|
/** The gag material enum, or null if not configured or invalid. Cached at load time. */
|
||||||
public @Nullable GagMaterial getMaterial() {
|
public @Nullable GagMaterial getMaterial() {
|
||||||
if (material == null) return null;
|
return cachedMaterial;
|
||||||
try {
|
|
||||||
return GagMaterial.valueOf(material.toUpperCase());
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
TiedUpMod.LOGGER.warn("[GaggingComponent] Unknown gag material: {}", material);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The raw material string from JSON, or null. */
|
/** The raw material string from JSON, or null. */
|
||||||
|
|||||||
@@ -167,8 +167,13 @@ public class DataDrivenBondageItem extends AbstractV2BondageItem {
|
|||||||
return TyingInteractionHelper.handleTying(serverPlayer, target, stack, hand);
|
return TyingInteractionHelper.handleTying(serverPlayer, target, stack, hand);
|
||||||
}
|
}
|
||||||
|
|
||||||
// NECK: collar equip blocked for now — V2 collar JSONs don't exist in Branch A.
|
// NECK: blocked until Branch C wires the full collar equip flow
|
||||||
// Full collar equip flow (add owner, register, sound) wired in Branch C.
|
// (add owner to NBT, register in CollarRegistry, play sound, sync).
|
||||||
|
// Without this, V2 collars equip without ownership — breaking GPS, shock, alerts.
|
||||||
|
if (regions.contains(BodyRegionV2.NECK)) {
|
||||||
|
TiedUpMod.LOGGER.debug("[DataDrivenBondageItem] NECK equip blocked — collar flow not wired yet");
|
||||||
|
return InteractionResult.PASS;
|
||||||
|
}
|
||||||
|
|
||||||
// All other regions (MOUTH, EYES, EARS, HANDS): instant equip via parent
|
// All other regions (MOUTH, EYES, EARS, HANDS): instant equip via parent
|
||||||
return super.interactLivingEntity(stack, player, target, hand);
|
return super.interactLivingEntity(stack, player, target, hand);
|
||||||
|
|||||||
Reference in New Issue
Block a user