Clean repo for open source release
Remove build artifacts, dev tool configs, unused dependencies, and third-party source dumps. Add proper README, update .gitignore, clean up Makefile.
This commit is contained in:
576
src/main/java/com/tiedup/remake/cells/CampOwnership.java
Normal file
576
src/main/java/com/tiedup/remake/cells/CampOwnership.java
Normal file
@@ -0,0 +1,576 @@
|
||||
package com.tiedup.remake.cells;
|
||||
|
||||
import com.tiedup.remake.core.TiedUpMod;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.ListTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.saveddata.SavedData;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Global registry for camp ownership linking camps to their SlaveTrader.
|
||||
*
|
||||
* This registry tracks:
|
||||
* - Camp UUID -> CampData (trader, maid, alive status)
|
||||
* - When a trader dies, the camp becomes inactive
|
||||
*
|
||||
* Persists across server restarts using Minecraft's SavedData system.
|
||||
*/
|
||||
public class CampOwnership extends SavedData {
|
||||
|
||||
private static final String DATA_NAME = "tiedup_camp_ownership";
|
||||
|
||||
// Camp UUID -> CampData
|
||||
private final Map<UUID, CampData> camps = new ConcurrentHashMap<>();
|
||||
|
||||
// Prisoners that have been processed (to avoid re-processing)
|
||||
private final Set<UUID> processedPrisoners = ConcurrentHashMap.newKeySet();
|
||||
|
||||
// ==================== CAMP DATA CLASS ====================
|
||||
|
||||
/**
|
||||
* Data structure representing a camp and its owner.
|
||||
* Uses thread-safe collections for concurrent access.
|
||||
*/
|
||||
/** Maid respawn delay in ticks (5 minutes = 6000 ticks) */
|
||||
public static final long MAID_RESPAWN_DELAY = 6000;
|
||||
|
||||
public static class CampData {
|
||||
|
||||
private final UUID campId;
|
||||
private volatile UUID traderUUID;
|
||||
private volatile UUID maidUUID;
|
||||
private volatile boolean isAlive = true;
|
||||
private volatile BlockPos center;
|
||||
private final Set<UUID> linkedKidnapperUUIDs =
|
||||
ConcurrentHashMap.newKeySet();
|
||||
|
||||
/** Time when maid died (for respawn timer), -1 if alive */
|
||||
private volatile long maidDeathTime = -1;
|
||||
|
||||
/** Cached positions of LOOT chests (below LOOT markers) */
|
||||
private final List<BlockPos> lootChestPositions = new ArrayList<>();
|
||||
|
||||
public CampData(UUID campId) {
|
||||
this.campId = campId;
|
||||
}
|
||||
|
||||
public CampData(
|
||||
UUID campId,
|
||||
UUID traderUUID,
|
||||
@Nullable UUID maidUUID,
|
||||
BlockPos center
|
||||
) {
|
||||
this.campId = campId;
|
||||
this.traderUUID = traderUUID;
|
||||
this.maidUUID = maidUUID;
|
||||
this.center = center;
|
||||
this.isAlive = true;
|
||||
}
|
||||
|
||||
// Getters
|
||||
public UUID getCampId() {
|
||||
return campId;
|
||||
}
|
||||
|
||||
public UUID getTraderUUID() {
|
||||
return traderUUID;
|
||||
}
|
||||
|
||||
public UUID getMaidUUID() {
|
||||
return maidUUID;
|
||||
}
|
||||
|
||||
public boolean isAlive() {
|
||||
return isAlive;
|
||||
}
|
||||
|
||||
public BlockPos getCenter() {
|
||||
return center;
|
||||
}
|
||||
|
||||
// Setters
|
||||
public void setTraderUUID(UUID traderUUID) {
|
||||
this.traderUUID = traderUUID;
|
||||
}
|
||||
|
||||
public void setMaidUUID(UUID maidUUID) {
|
||||
this.maidUUID = maidUUID;
|
||||
}
|
||||
|
||||
public void setAlive(boolean alive) {
|
||||
this.isAlive = alive;
|
||||
}
|
||||
|
||||
public void setCenter(BlockPos center) {
|
||||
this.center = center;
|
||||
}
|
||||
|
||||
// Maid death/respawn
|
||||
public long getMaidDeathTime() {
|
||||
return maidDeathTime;
|
||||
}
|
||||
|
||||
public void setMaidDeathTime(long time) {
|
||||
this.maidDeathTime = time;
|
||||
}
|
||||
|
||||
public boolean isMaidDead() {
|
||||
return maidDeathTime >= 0;
|
||||
}
|
||||
|
||||
public boolean canRespawnMaid(long currentTime) {
|
||||
return (
|
||||
isMaidDead() &&
|
||||
(currentTime - maidDeathTime) >= MAID_RESPAWN_DELAY
|
||||
);
|
||||
}
|
||||
|
||||
// Loot chest management
|
||||
public List<BlockPos> getLootChestPositions() {
|
||||
return lootChestPositions;
|
||||
}
|
||||
|
||||
public void addLootChestPosition(BlockPos pos) {
|
||||
if (!lootChestPositions.contains(pos)) {
|
||||
lootChestPositions.add(pos);
|
||||
}
|
||||
}
|
||||
|
||||
// Kidnapper management
|
||||
public void addKidnapper(UUID kidnapperUUID) {
|
||||
linkedKidnapperUUIDs.add(kidnapperUUID);
|
||||
}
|
||||
|
||||
public void removeKidnapper(UUID kidnapperUUID) {
|
||||
linkedKidnapperUUIDs.remove(kidnapperUUID);
|
||||
}
|
||||
|
||||
public Set<UUID> getLinkedKidnappers() {
|
||||
return Collections.unmodifiableSet(linkedKidnapperUUIDs);
|
||||
}
|
||||
|
||||
public boolean hasKidnapper(UUID kidnapperUUID) {
|
||||
return linkedKidnapperUUIDs.contains(kidnapperUUID);
|
||||
}
|
||||
|
||||
public int getKidnapperCount() {
|
||||
return linkedKidnapperUUIDs.size();
|
||||
}
|
||||
|
||||
// NBT Serialization
|
||||
public CompoundTag save() {
|
||||
CompoundTag tag = new CompoundTag();
|
||||
tag.putUUID("campId", campId);
|
||||
if (traderUUID != null) tag.putUUID("traderUUID", traderUUID);
|
||||
if (maidUUID != null) tag.putUUID("maidUUID", maidUUID);
|
||||
tag.putBoolean("isAlive", isAlive);
|
||||
if (center != null) {
|
||||
tag.putInt("centerX", center.getX());
|
||||
tag.putInt("centerY", center.getY());
|
||||
tag.putInt("centerZ", center.getZ());
|
||||
}
|
||||
// Save linked kidnappers
|
||||
if (!linkedKidnapperUUIDs.isEmpty()) {
|
||||
ListTag kidnapperList = new ListTag();
|
||||
for (UUID uuid : linkedKidnapperUUIDs) {
|
||||
CompoundTag uuidTag = new CompoundTag();
|
||||
uuidTag.putUUID("uuid", uuid);
|
||||
kidnapperList.add(uuidTag);
|
||||
}
|
||||
tag.put("linkedKidnappers", kidnapperList);
|
||||
}
|
||||
// Save maid death time
|
||||
tag.putLong("maidDeathTime", maidDeathTime);
|
||||
// Save loot chest positions
|
||||
if (!lootChestPositions.isEmpty()) {
|
||||
ListTag lootList = new ListTag();
|
||||
for (BlockPos pos : lootChestPositions) {
|
||||
CompoundTag posTag = new CompoundTag();
|
||||
posTag.putInt("x", pos.getX());
|
||||
posTag.putInt("y", pos.getY());
|
||||
posTag.putInt("z", pos.getZ());
|
||||
lootList.add(posTag);
|
||||
}
|
||||
tag.put("lootChestPositions", lootList);
|
||||
}
|
||||
return tag;
|
||||
}
|
||||
|
||||
public static CampData load(CompoundTag tag) {
|
||||
UUID campId = tag.getUUID("campId");
|
||||
CampData data = new CampData(campId);
|
||||
if (tag.contains("traderUUID")) data.traderUUID = tag.getUUID(
|
||||
"traderUUID"
|
||||
);
|
||||
if (tag.contains("maidUUID")) data.maidUUID = tag.getUUID(
|
||||
"maidUUID"
|
||||
);
|
||||
data.isAlive = tag.getBoolean("isAlive");
|
||||
if (tag.contains("centerX")) {
|
||||
data.center = new BlockPos(
|
||||
tag.getInt("centerX"),
|
||||
tag.getInt("centerY"),
|
||||
tag.getInt("centerZ")
|
||||
);
|
||||
}
|
||||
// Load linked kidnappers
|
||||
if (tag.contains("linkedKidnappers")) {
|
||||
ListTag kidnapperList = tag.getList(
|
||||
"linkedKidnappers",
|
||||
Tag.TAG_COMPOUND
|
||||
);
|
||||
for (int i = 0; i < kidnapperList.size(); i++) {
|
||||
CompoundTag uuidTag = kidnapperList.getCompound(i);
|
||||
if (uuidTag.contains("uuid")) {
|
||||
data.linkedKidnapperUUIDs.add(uuidTag.getUUID("uuid"));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Load maid death time
|
||||
if (tag.contains("maidDeathTime")) {
|
||||
data.maidDeathTime = tag.getLong("maidDeathTime");
|
||||
}
|
||||
// Load loot chest positions
|
||||
if (tag.contains("lootChestPositions")) {
|
||||
ListTag lootList = tag.getList(
|
||||
"lootChestPositions",
|
||||
Tag.TAG_COMPOUND
|
||||
);
|
||||
for (int i = 0; i < lootList.size(); i++) {
|
||||
CompoundTag posTag = lootList.getCompound(i);
|
||||
data.lootChestPositions.add(
|
||||
new BlockPos(
|
||||
posTag.getInt("x"),
|
||||
posTag.getInt("y"),
|
||||
posTag.getInt("z")
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== STATIC ACCESS ====================
|
||||
|
||||
/**
|
||||
* Get the CampOwnership registry for a server level.
|
||||
*/
|
||||
public static CampOwnership get(ServerLevel level) {
|
||||
return level
|
||||
.getDataStorage()
|
||||
.computeIfAbsent(
|
||||
CampOwnership::load,
|
||||
CampOwnership::new,
|
||||
DATA_NAME
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the CampOwnership from a MinecraftServer.
|
||||
*/
|
||||
public static CampOwnership get(MinecraftServer server) {
|
||||
ServerLevel overworld = server.overworld();
|
||||
return get(overworld);
|
||||
}
|
||||
|
||||
// ==================== CAMP MANAGEMENT ====================
|
||||
|
||||
/**
|
||||
* Register a new camp with its trader and maid.
|
||||
*
|
||||
* @param campId The camp/structure UUID
|
||||
* @param traderUUID The SlaveTrader entity UUID
|
||||
* @param maidUUID The Maid entity UUID (can be null)
|
||||
* @param center The center position of the camp
|
||||
*/
|
||||
public void registerCamp(
|
||||
UUID campId,
|
||||
UUID traderUUID,
|
||||
@Nullable UUID maidUUID,
|
||||
BlockPos center
|
||||
) {
|
||||
CampData data = new CampData(campId, traderUUID, maidUUID, center);
|
||||
camps.put(campId, data);
|
||||
setDirty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a camp is alive (has living trader).
|
||||
*
|
||||
* @param campId The camp UUID
|
||||
* @return true if camp exists and is alive
|
||||
*/
|
||||
public boolean isCampAlive(UUID campId) {
|
||||
CampData data = camps.get(campId);
|
||||
return data != null && data.isAlive();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get camp data by camp UUID.
|
||||
*/
|
||||
@Nullable
|
||||
public CampData getCamp(UUID campId) {
|
||||
return camps.get(campId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get camp data by trader UUID.
|
||||
*/
|
||||
@Nullable
|
||||
public CampData getCampByTrader(UUID traderUUID) {
|
||||
for (CampData camp : camps.values()) {
|
||||
if (traderUUID.equals(camp.getTraderUUID())) {
|
||||
return camp;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get camp data by maid UUID.
|
||||
*/
|
||||
@Nullable
|
||||
public CampData getCampByMaid(UUID maidUUID) {
|
||||
for (CampData camp : camps.values()) {
|
||||
if (maidUUID.equals(camp.getMaidUUID())) {
|
||||
return camp;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find camps near a position.
|
||||
*
|
||||
* @param center The center position
|
||||
* @param radius The search radius
|
||||
* @return List of camps within radius
|
||||
*/
|
||||
public List<CampData> findCampsNear(BlockPos center, double radius) {
|
||||
List<CampData> nearby = new ArrayList<>();
|
||||
double radiusSq = radius * radius;
|
||||
|
||||
for (CampData camp : camps.values()) {
|
||||
if (
|
||||
camp.getCenter() != null &&
|
||||
camp.getCenter().distSqr(center) <= radiusSq
|
||||
) {
|
||||
nearby.add(camp);
|
||||
}
|
||||
}
|
||||
return nearby;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the nearest alive camp to a position.
|
||||
*
|
||||
* @param pos The position to search from
|
||||
* @param radius Maximum search radius
|
||||
* @return The nearest alive camp, or null
|
||||
*/
|
||||
@Nullable
|
||||
public CampData findNearestAliveCamp(BlockPos pos, double radius) {
|
||||
CampData nearest = null;
|
||||
double nearestDistSq = radius * radius;
|
||||
|
||||
for (CampData camp : camps.values()) {
|
||||
if (!camp.isAlive() || camp.getCenter() == null) continue;
|
||||
|
||||
double distSq = camp.getCenter().distSqr(pos);
|
||||
if (distSq < nearestDistSq) {
|
||||
nearestDistSq = distSq;
|
||||
nearest = camp;
|
||||
}
|
||||
}
|
||||
return nearest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a camp from the registry.
|
||||
*/
|
||||
@Nullable
|
||||
public CampData removeCamp(UUID campId) {
|
||||
CampData removed = camps.remove(campId);
|
||||
if (removed != null) {
|
||||
setDirty();
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all registered camps.
|
||||
*/
|
||||
public Collection<CampData> getAllCamps() {
|
||||
return Collections.unmodifiableCollection(camps.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all alive camps.
|
||||
*/
|
||||
public List<CampData> getAliveCamps() {
|
||||
List<CampData> alive = new ArrayList<>();
|
||||
for (CampData camp : camps.values()) {
|
||||
if (camp.isAlive()) {
|
||||
alive.add(camp);
|
||||
}
|
||||
}
|
||||
return alive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Link a kidnapper to a camp.
|
||||
*
|
||||
* @param campId The camp UUID
|
||||
* @param kidnapperUUID The kidnapper UUID
|
||||
*/
|
||||
public void linkKidnapperToCamp(UUID campId, UUID kidnapperUUID) {
|
||||
CampData data = camps.get(campId);
|
||||
if (data != null) {
|
||||
data.addKidnapper(kidnapperUUID);
|
||||
setDirty();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlink a kidnapper from a camp.
|
||||
*
|
||||
* @param campId The camp UUID
|
||||
* @param kidnapperUUID The kidnapper UUID
|
||||
*/
|
||||
public void unlinkKidnapperFromCamp(UUID campId, UUID kidnapperUUID) {
|
||||
CampData data = camps.get(campId);
|
||||
if (data != null) {
|
||||
data.removeKidnapper(kidnapperUUID);
|
||||
setDirty();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a kidnapper is linked to a camp.
|
||||
*
|
||||
* @param campId The camp UUID
|
||||
* @param kidnapperUUID The kidnapper UUID
|
||||
* @return true if the kidnapper is linked to this camp
|
||||
*/
|
||||
public boolean isKidnapperLinked(UUID campId, UUID kidnapperUUID) {
|
||||
CampData data = camps.get(campId);
|
||||
return data != null && data.hasKidnapper(kidnapperUUID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the camp a kidnapper is linked to.
|
||||
*
|
||||
* @param kidnapperUUID The kidnapper UUID
|
||||
* @return The camp data, or null if not linked
|
||||
*/
|
||||
@Nullable
|
||||
public CampData findCampByKidnapper(UUID kidnapperUUID) {
|
||||
for (CampData camp : camps.values()) {
|
||||
if (camp.hasKidnapper(kidnapperUUID)) {
|
||||
return camp;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark a prisoner as processed (to avoid re-processing).
|
||||
*
|
||||
* @param prisonerId The prisoner's UUID
|
||||
*/
|
||||
public void markPrisonerProcessed(UUID prisonerId) {
|
||||
processedPrisoners.add(prisonerId);
|
||||
setDirty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a prisoner has been processed.
|
||||
*
|
||||
* @param prisonerId The prisoner's UUID
|
||||
* @return true if already processed
|
||||
*/
|
||||
public boolean isPrisonerProcessed(UUID prisonerId) {
|
||||
return processedPrisoners.contains(prisonerId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a prisoner from processed set.
|
||||
*
|
||||
* @param prisonerId The prisoner's UUID
|
||||
*/
|
||||
public void unmarkPrisonerProcessed(UUID prisonerId) {
|
||||
if (processedPrisoners.remove(prisonerId)) {
|
||||
setDirty();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the set of processed prisoners for a camp (unmodifiable).
|
||||
*
|
||||
* @return Unmodifiable set of processed prisoner UUIDs
|
||||
*/
|
||||
public Set<UUID> getProcessedPrisoners() {
|
||||
return Collections.unmodifiableSet(processedPrisoners);
|
||||
}
|
||||
|
||||
// ==================== PERSISTENCE ====================
|
||||
|
||||
@Override
|
||||
public @NotNull CompoundTag save(@NotNull CompoundTag tag) {
|
||||
// Save camps
|
||||
ListTag campList = new ListTag();
|
||||
for (CampData camp : camps.values()) {
|
||||
campList.add(camp.save());
|
||||
}
|
||||
tag.put("camps", campList);
|
||||
|
||||
// Save processed prisoners
|
||||
ListTag processedList = new ListTag();
|
||||
for (UUID uuid : processedPrisoners) {
|
||||
CompoundTag uuidTag = new CompoundTag();
|
||||
uuidTag.putUUID("uuid", uuid);
|
||||
processedList.add(uuidTag);
|
||||
}
|
||||
tag.put("processedPrisoners", processedList);
|
||||
|
||||
return tag;
|
||||
}
|
||||
|
||||
public static CampOwnership load(CompoundTag tag) {
|
||||
CampOwnership registry = new CampOwnership();
|
||||
|
||||
// Load camps
|
||||
if (tag.contains("camps")) {
|
||||
ListTag campList = tag.getList("camps", Tag.TAG_COMPOUND);
|
||||
for (int i = 0; i < campList.size(); i++) {
|
||||
CampData camp = CampData.load(campList.getCompound(i));
|
||||
registry.camps.put(camp.getCampId(), camp);
|
||||
}
|
||||
}
|
||||
|
||||
// Load processed prisoners
|
||||
if (tag.contains("processedPrisoners")) {
|
||||
ListTag processedList = tag.getList(
|
||||
"processedPrisoners",
|
||||
Tag.TAG_COMPOUND
|
||||
);
|
||||
for (int i = 0; i < processedList.size(); i++) {
|
||||
CompoundTag uuidTag = processedList.getCompound(i);
|
||||
if (uuidTag.contains("uuid")) {
|
||||
registry.processedPrisoners.add(uuidTag.getUUID("uuid"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return registry;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user