Remove build artifacts, dev tool configs, unused dependencies, and third-party source dumps. Add proper README, update .gitignore, clean up Makefile.
300 lines
9.0 KiB
Java
300 lines
9.0 KiB
Java
package com.tiedup.remake.events.camp;
|
|
|
|
import com.tiedup.remake.cells.CampMaidManager;
|
|
import com.tiedup.remake.cells.CampOwnership;
|
|
import com.tiedup.remake.core.TiedUpMod;
|
|
import com.tiedup.remake.entities.EntityMaid;
|
|
import com.tiedup.remake.entities.EntitySlaveTrader;
|
|
import com.tiedup.remake.entities.ModEntities;
|
|
// Prison system v2
|
|
import com.tiedup.remake.prison.PrisonerManager;
|
|
import com.tiedup.remake.prison.service.PrisonerService;
|
|
import java.util.List;
|
|
import java.util.UUID;
|
|
import net.minecraft.ChatFormatting;
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.network.chat.Component;
|
|
import net.minecraft.server.level.ServerLevel;
|
|
import net.minecraft.server.level.ServerPlayer;
|
|
import net.minecraft.world.entity.Entity;
|
|
import net.minecraftforge.event.TickEvent;
|
|
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
|
import net.minecraftforge.fml.common.Mod;
|
|
|
|
/**
|
|
* Handles camp management tasks including maid respawn.
|
|
*
|
|
* When a maid dies:
|
|
* - Camp remains alive (trader still exists)
|
|
* - Prisoners are paused (no new tasks)
|
|
* - After 5 minutes (6000 ticks), a new maid spawns
|
|
* - Prisoners are notified and labor resumes
|
|
*/
|
|
@Mod.EventBusSubscriber(
|
|
modid = TiedUpMod.MOD_ID,
|
|
bus = Mod.EventBusSubscriber.Bus.FORGE
|
|
)
|
|
public class CampManagementHandler {
|
|
|
|
// Check every 100 ticks (5 seconds) - optimized for performance
|
|
private static final int CHECK_INTERVAL_TICKS = 100;
|
|
|
|
private static int tickCounter = 0;
|
|
|
|
/**
|
|
* Periodically check for camps needing maid respawn.
|
|
*/
|
|
@SubscribeEvent
|
|
public static void onServerTick(TickEvent.ServerTickEvent event) {
|
|
if (event.phase != TickEvent.Phase.END) return;
|
|
|
|
tickCounter++;
|
|
if (tickCounter < CHECK_INTERVAL_TICKS) return;
|
|
tickCounter = 0;
|
|
|
|
// Process all worlds
|
|
for (ServerLevel level : event.getServer().getAllLevels()) {
|
|
processCampManagement(level);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Process camp management for a specific level.
|
|
*/
|
|
private static void processCampManagement(ServerLevel level) {
|
|
// IMPORTANT: Always use server-level registry to avoid dimension fragmentation
|
|
CampOwnership ownership = CampOwnership.get(level.getServer());
|
|
long currentTime = level.getGameTime();
|
|
|
|
// Get camps that need maid respawn
|
|
List<UUID> campsNeedingMaid = CampMaidManager.getCampsNeedingMaidRespawn(
|
|
currentTime, level
|
|
);
|
|
|
|
for (UUID campId : campsNeedingMaid) {
|
|
spawnNewMaidForCamp(level, ownership, campId);
|
|
}
|
|
|
|
// Prison system v2 - tick escape service (handles escape detection)
|
|
PrisonerService.get().tick(level.getServer(), currentTime);
|
|
|
|
// Prison system v2 - tick protection expiry
|
|
PrisonerManager.get(level).tickProtectionExpiry(currentTime);
|
|
}
|
|
|
|
/**
|
|
* Spawn a new maid for a camp that needs one.
|
|
*
|
|
* @param level The server level
|
|
* @param ownership The camp ownership data
|
|
* @param campId The camp UUID
|
|
*/
|
|
private static void spawnNewMaidForCamp(
|
|
ServerLevel level,
|
|
CampOwnership ownership,
|
|
UUID campId
|
|
) {
|
|
CampOwnership.CampData campData = ownership.getCamp(campId);
|
|
if (campData == null || !campData.isAlive()) {
|
|
return;
|
|
}
|
|
|
|
BlockPos center = campData.getCenter();
|
|
if (center == null) {
|
|
TiedUpMod.LOGGER.warn(
|
|
"[CampManagementHandler] Cannot spawn maid - camp {} has no center position",
|
|
campId.toString().substring(0, 8)
|
|
);
|
|
return;
|
|
}
|
|
|
|
UUID traderUUID = campData.getTraderUUID();
|
|
if (traderUUID == null) {
|
|
TiedUpMod.LOGGER.warn(
|
|
"[CampManagementHandler] Cannot spawn maid - camp {} has no trader",
|
|
campId.toString().substring(0, 8)
|
|
);
|
|
return;
|
|
}
|
|
|
|
// Find the trader entity
|
|
Entity traderEntity = level.getEntity(traderUUID);
|
|
EntitySlaveTrader trader = null;
|
|
if (traderEntity instanceof EntitySlaveTrader t) {
|
|
trader = t;
|
|
} else {
|
|
// Trader not loaded - search near camp center
|
|
trader = findTraderNearPosition(level, center, 50);
|
|
}
|
|
|
|
if (trader == null) {
|
|
TiedUpMod.LOGGER.warn(
|
|
"[CampManagementHandler] Cannot spawn maid - trader not found for camp {}",
|
|
campId.toString().substring(0, 8)
|
|
);
|
|
return;
|
|
}
|
|
|
|
// Create new maid
|
|
EntityMaid maid = ModEntities.MAID.get().create(level);
|
|
if (maid == null) {
|
|
TiedUpMod.LOGGER.error(
|
|
"[CampManagementHandler] Failed to create maid entity for camp {}",
|
|
campId.toString().substring(0, 8)
|
|
);
|
|
return;
|
|
}
|
|
|
|
// Find spawn position near trader (slightly offset)
|
|
BlockPos spawnPos = findSafeSpawnPosition(
|
|
level,
|
|
trader.blockPosition()
|
|
);
|
|
|
|
// Position the maid
|
|
maid.moveTo(
|
|
spawnPos.getX() + 0.5,
|
|
spawnPos.getY(),
|
|
spawnPos.getZ() + 0.5,
|
|
trader.getYRot() + 180, // Face opposite direction from trader
|
|
0
|
|
);
|
|
|
|
// Link maid to trader
|
|
maid.setMasterTraderUUID(trader.getUUID());
|
|
|
|
// Add to world
|
|
level.addFreshEntity(maid);
|
|
|
|
// Update camp ownership with new maid
|
|
CampMaidManager.assignNewMaid(campId, maid.getUUID(), level);
|
|
|
|
// Update trader's maid reference
|
|
trader.setMaidUUID(maid.getUUID());
|
|
|
|
TiedUpMod.LOGGER.info(
|
|
"[CampManagementHandler] Spawned replacement maid {} for camp {} at {}",
|
|
maid.getNpcName(),
|
|
campId.toString().substring(0, 8),
|
|
spawnPos.toShortString()
|
|
);
|
|
|
|
// Notify prisoners
|
|
notifyPrisonersOfNewMaid(level, campId, maid.getNpcName());
|
|
}
|
|
|
|
/**
|
|
* Find a trader near the given position.
|
|
*/
|
|
private static EntitySlaveTrader findTraderNearPosition(
|
|
ServerLevel level,
|
|
BlockPos pos,
|
|
int radius
|
|
) {
|
|
List<EntitySlaveTrader> traders = level.getEntitiesOfClass(
|
|
EntitySlaveTrader.class,
|
|
new net.minecraft.world.phys.AABB(pos).inflate(radius)
|
|
);
|
|
return traders.isEmpty() ? null : traders.get(0);
|
|
}
|
|
|
|
/**
|
|
* Find a safe position to spawn the maid.
|
|
* Tries positions around the target, prioritizing nearby valid spots.
|
|
*/
|
|
private static BlockPos findSafeSpawnPosition(
|
|
ServerLevel level,
|
|
BlockPos targetPos
|
|
) {
|
|
// Try offsets in a spiral pattern
|
|
int[][] offsets = {
|
|
{ 1, 0 },
|
|
{ 0, 1 },
|
|
{ -1, 0 },
|
|
{ 0, -1 },
|
|
{ 1, 1 },
|
|
{ -1, 1 },
|
|
{ -1, -1 },
|
|
{ 1, -1 },
|
|
{ 2, 0 },
|
|
{ 0, 2 },
|
|
{ -2, 0 },
|
|
{ 0, -2 },
|
|
};
|
|
|
|
for (int[] offset : offsets) {
|
|
BlockPos testPos = targetPos.offset(offset[0], 0, offset[1]);
|
|
|
|
// Check if position is safe (solid ground, air above)
|
|
if (isValidSpawnPosition(level, testPos)) {
|
|
return testPos;
|
|
}
|
|
|
|
// Try one block down
|
|
BlockPos downPos = testPos.below();
|
|
if (isValidSpawnPosition(level, downPos)) {
|
|
return downPos;
|
|
}
|
|
|
|
// Try one block up
|
|
BlockPos upPos = testPos.above();
|
|
if (isValidSpawnPosition(level, upPos)) {
|
|
return upPos;
|
|
}
|
|
}
|
|
|
|
// Fallback: use target position
|
|
return targetPos;
|
|
}
|
|
|
|
/**
|
|
* Check if a position is valid for spawning.
|
|
*/
|
|
private static boolean isValidSpawnPosition(
|
|
ServerLevel level,
|
|
BlockPos pos
|
|
) {
|
|
// Ground must be solid
|
|
if (!level.getBlockState(pos.below()).isSolid()) {
|
|
return false;
|
|
}
|
|
|
|
// Position and above must be passable (air or similar)
|
|
if (!level.getBlockState(pos).isAir()) {
|
|
return false;
|
|
}
|
|
|
|
if (!level.getBlockState(pos.above()).isAir()) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Notify all prisoners of this camp that a new maid has arrived.
|
|
*/
|
|
private static void notifyPrisonersOfNewMaid(
|
|
ServerLevel level,
|
|
UUID campId,
|
|
String maidName
|
|
) {
|
|
PrisonerManager manager = PrisonerManager.get(level);
|
|
for (UUID prisonerId : manager.getPrisonersInCamp(campId)) {
|
|
ServerPlayer player = level
|
|
.getServer()
|
|
.getPlayerList()
|
|
.getPlayer(prisonerId);
|
|
if (player != null) {
|
|
player.sendSystemMessage(
|
|
Component.literal(
|
|
"A new maid, " +
|
|
maidName +
|
|
", has arrived. Work resumes."
|
|
).withStyle(ChatFormatting.GOLD)
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|