fix(D-01/C): missing sync + worldgen empty registry race (review)

StruggleSessionManager: add V2EquipmentHelper.sync(player) after bind
resistance update to prevent data loss on server restart during struggle

HangingCagePiece: add fallback ResourceLocation arrays for worldgen when
DataDrivenItemRegistry is empty (race with reload listener on initial
world creation). Registry-first with hardcoded fallbacks.
This commit is contained in:
NotEvil
2026-04-15 00:26:07 +02:00
parent 3d61c9e9e6
commit 3515c89f82
2 changed files with 44 additions and 42 deletions

View File

@@ -647,6 +647,7 @@ public class StruggleSessionManager {
} }
if (bindStack.getItem() instanceof IHasResistance resistanceItem) { if (bindStack.getItem() instanceof IHasResistance resistanceItem) {
resistanceItem.setCurrentResistance(bindStack, session.getCurrentResistance()); resistanceItem.setCurrentResistance(bindStack, session.getCurrentResistance());
V2EquipmentHelper.sync(player);
} }
} }

View File

@@ -16,6 +16,7 @@ import javax.annotation.Nullable;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.nbt.DoubleTag; import net.minecraft.nbt.DoubleTag;
import net.minecraft.nbt.FloatTag; import net.minecraft.nbt.FloatTag;
import net.minecraft.nbt.ListTag; import net.minecraft.nbt.ListTag;
@@ -543,36 +544,43 @@ public class HangingCagePiece extends StructurePiece {
BlockEntity be = level.getBlockEntity(chestPos); BlockEntity be = level.getBlockEntity(chestPos);
if (be instanceof TrappedChestBlockEntity trappedChest) { if (be instanceof TrappedChestBlockEntity trappedChest) {
// Random bind from data-driven ARMS items // Random bind from data-driven ARMS items
List<DataDrivenItemDefinition> binds = DataDrivenItemRegistry.getAll().stream() trappedChest.setBind(randomItemForRegion(random, BodyRegionV2.ARMS, FALLBACK_BINDS));
.filter(d -> d.occupiedRegions().contains(BodyRegionV2.ARMS))
.collect(Collectors.toList());
if (!binds.isEmpty()) {
DataDrivenItemDefinition chosenBind = binds.get(random.nextInt(binds.size()));
trappedChest.setBind(DataDrivenBondageItem.createStack(chosenBind.id()));
}
// Random gag from data-driven MOUTH items (50% chance) // Random gag (50% chance)
if (random.nextFloat() < 0.50f) { if (random.nextFloat() < 0.50f) {
List<DataDrivenItemDefinition> gags = DataDrivenItemRegistry.getAll().stream() trappedChest.setGag(randomItemForRegion(random, BodyRegionV2.MOUTH, FALLBACK_GAGS));
.filter(d -> d.occupiedRegions().contains(BodyRegionV2.MOUTH)) }
.collect(Collectors.toList());
if (!gags.isEmpty()) { // Random blindfold (30% chance)
DataDrivenItemDefinition chosenGag = gags.get(random.nextInt(gags.size())); if (random.nextFloat() < 0.30f) {
trappedChest.setGag(DataDrivenBondageItem.createStack(chosenGag.id())); trappedChest.setBlindfold(randomItemForRegion(random, BodyRegionV2.EYES, FALLBACK_BLINDFOLDS));
}
} }
} }
// Random blindfold from data-driven EYES items (30% chance) // Fallback item IDs for worldgen when DataDrivenItemRegistry is empty (race with reload)
if (random.nextFloat() < 0.30f) { private static final ResourceLocation[] FALLBACK_BINDS = {
List<DataDrivenItemDefinition> blindfolds = DataDrivenItemRegistry.getAll().stream() new ResourceLocation("tiedup", "ropes"),
.filter(d -> d.occupiedRegions().contains(BodyRegionV2.EYES)) new ResourceLocation("tiedup", "chain"),
new ResourceLocation("tiedup", "armbinder")
};
private static final ResourceLocation[] FALLBACK_GAGS = {
new ResourceLocation("tiedup", "cloth_gag"),
new ResourceLocation("tiedup", "ball_gag")
};
private static final ResourceLocation[] FALLBACK_BLINDFOLDS = {
new ResourceLocation("tiedup", "classic_blindfold")
};
private static ItemStack randomItemForRegion(RandomSource random, BodyRegionV2 region, ResourceLocation[] fallbacks) {
List<DataDrivenItemDefinition> defs = DataDrivenItemRegistry.getAll().stream()
.filter(d -> d.occupiedRegions().contains(region))
.collect(Collectors.toList()); .collect(Collectors.toList());
if (!blindfolds.isEmpty()) { if (!defs.isEmpty()) {
DataDrivenItemDefinition chosenBf = blindfolds.get(random.nextInt(blindfolds.size())); return DataDrivenBondageItem.createStack(defs.get(random.nextInt(defs.size())).id());
trappedChest.setBlindfold(DataDrivenBondageItem.createStack(chosenBf.id()));
}
}
} }
// Fallback for worldgen race condition (registry not loaded yet)
return DataDrivenBondageItem.createStack(fallbacks[random.nextInt(fallbacks.length)]);
} }
static void safeSetBlock( static void safeSetBlock(
@@ -632,12 +640,7 @@ public class HangingCagePiece extends StructurePiece {
entityTag.putUUID("UUID", java.util.UUID.randomUUID()); entityTag.putUUID("UUID", java.util.UUID.randomUUID());
// Random bind item — the damsel spawns already restrained // Random bind item — the damsel spawns already restrained
List<DataDrivenItemDefinition> bindDefs = DataDrivenItemRegistry.getAll().stream() ItemStack bindStack = randomItemForRegion(random, BodyRegionV2.ARMS, FALLBACK_BINDS);
.filter(d -> d.occupiedRegions().contains(BodyRegionV2.ARMS))
.collect(Collectors.toList());
if (!bindDefs.isEmpty()) {
DataDrivenItemDefinition chosenBind = bindDefs.get(random.nextInt(bindDefs.size()));
ItemStack bindStack = DataDrivenBondageItem.createStack(chosenBind.id());
bindStack.getOrCreateTag().putString("bindMode", "full"); bindStack.getOrCreateTag().putString("bindMode", "full");
entityTag.put("Bind", bindStack.save(new CompoundTag())); entityTag.put("Bind", bindStack.save(new CompoundTag()));
@@ -646,12 +649,10 @@ public class HangingCagePiece extends StructurePiece {
if (chunk instanceof ProtoChunk protoChunk) { if (chunk instanceof ProtoChunk protoChunk) {
protoChunk.addEntity(entityTag); protoChunk.addEntity(entityTag);
TiedUpMod.LOGGER.info( TiedUpMod.LOGGER.info(
"[HangingCage] Scheduled {} damsel with {} at {}", "[HangingCage] Scheduled {} damsel at {}",
shiny ? "shiny" : "regular", shiny ? "shiny" : "regular",
chosenBind.id(),
masterPos.toShortString() masterPos.toShortString()
); );
} }
} }
}
} }