Remove build artifacts, dev tool configs, unused dependencies, and third-party source dumps. Add proper README, update .gitignore, clean up Makefile.
428 lines
13 KiB
Java
428 lines
13 KiB
Java
package com.tiedup.remake.state;
|
|
|
|
import com.tiedup.remake.core.TiedUpMod;
|
|
import com.tiedup.remake.v2.BodyRegionV2;
|
|
import com.tiedup.remake.items.base.ItemCollar;
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
import java.util.concurrent.CopyOnWriteArrayList;
|
|
import net.minecraft.world.entity.Entity;
|
|
import net.minecraft.world.entity.player.Player;
|
|
import net.minecraft.world.item.ItemStack;
|
|
// C6-V2: IRestrainable → IBondageState (narrowed API)
|
|
|
|
/**
|
|
* Phase 8: Master-Captive Relationships
|
|
* Phase 17: Renamed from PlayerKidnapperManager, terminology slave → captive
|
|
*
|
|
* Manages capture relationships for player captors.
|
|
*
|
|
* Terminology (Phase 17):
|
|
* - "Captive" = Entity attached by leash (active physical control)
|
|
* - "Slave" = Entity wearing a collar owned by someone (passive ownership via CollarRegistry)
|
|
*
|
|
* Features:
|
|
* - Supports multiple captives simultaneously
|
|
* - Allows captive transfer between captors
|
|
* - Tracks captive list persistently
|
|
* - Handles cleanup on captive logout/escape
|
|
*
|
|
* Thread Safety:
|
|
* - Uses CopyOnWriteArrayList to avoid ConcurrentModificationException
|
|
* - Safe for iteration during modification
|
|
*
|
|
* Design:
|
|
* - Each PlayerBindState has one PlayerCaptorManager
|
|
* - Manager tracks all captives owned by that player
|
|
* - Implements ICaptor interface for polymorphic usage
|
|
*
|
|
* @see ICaptor
|
|
* @see PlayerBindState
|
|
*/
|
|
public class PlayerCaptorManager implements ICaptor {
|
|
|
|
/**
|
|
* The player who owns this manager (the captor).
|
|
*/
|
|
private final Player captor;
|
|
|
|
/**
|
|
* List of all captives currently owned by this captor.
|
|
* Thread-safe to avoid concurrent modification during iteration.
|
|
*
|
|
* Phase 14.1.6: Changed from List<PlayerBindState> to List<IBondageState>
|
|
* Phase 17: Renamed from slaves to captives
|
|
*/
|
|
private final List<IBondageState> captives;
|
|
|
|
/**
|
|
* Create a new captor manager for the given player.
|
|
*
|
|
* @param captor The player who will be the captor
|
|
*/
|
|
public PlayerCaptorManager(Player captor) {
|
|
this.captor = captor;
|
|
this.captives = new CopyOnWriteArrayList<>();
|
|
}
|
|
|
|
// ========================================
|
|
// ICaptor Implementation
|
|
// ========================================
|
|
|
|
/**
|
|
* Phase 14.1.6: Changed parameter from PlayerBindState to IBondageState
|
|
* Phase 17: Renamed from addSlave to addCaptive
|
|
*/
|
|
@Override
|
|
public synchronized void addCaptive(IBondageState captive) {
|
|
if (captive == null) {
|
|
TiedUpMod.LOGGER.warn(
|
|
"[PlayerCaptorManager] Attempted to add null captive"
|
|
);
|
|
return;
|
|
}
|
|
|
|
if (!captives.contains(captive)) {
|
|
captives.add(captive);
|
|
TiedUpMod.LOGGER.info(
|
|
"[PlayerCaptorManager] {} captured {} (total captives: {})",
|
|
captor.getName().getString(),
|
|
captive.getKidnappedName(),
|
|
captives.size()
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Phase 14.1.6: Changed parameter from PlayerBindState to IBondageState
|
|
* Phase 17: Renamed from removeSlave to removeCaptive
|
|
*
|
|
* Thread Safety: Synchronized on 'this' to match addCaptive and freeAllCaptives.
|
|
*/
|
|
@Override
|
|
public synchronized void removeCaptive(
|
|
IBondageState captive,
|
|
boolean transportState
|
|
) {
|
|
if (captive == null) {
|
|
TiedUpMod.LOGGER.warn(
|
|
"[PlayerCaptorManager] Attempted to remove null captive"
|
|
);
|
|
return;
|
|
}
|
|
|
|
if (captives.remove(captive)) {
|
|
TiedUpMod.LOGGER.info(
|
|
"[PlayerCaptorManager] {} freed {} (remaining captives: {})",
|
|
captor.getName().getString(),
|
|
captive.getKidnappedName(),
|
|
captives.size()
|
|
);
|
|
|
|
// If requested, also despawn the transport entity
|
|
if (transportState && captive.getTransport() != null) {
|
|
captive.getTransport().discard();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Phase 14.1.6: Changed parameter from PlayerBindState to IBondageState
|
|
* Phase 17: Renamed from canEnslave to canCapture
|
|
*/
|
|
@Override
|
|
public boolean canCapture(IBondageState target) {
|
|
if (target == null) {
|
|
return false;
|
|
}
|
|
|
|
// From original code (PlayerBindState.java:195-225):
|
|
// Can capture if:
|
|
// - Target is tied up, OR
|
|
// - Target has collar AND collar has this captor as owner
|
|
|
|
// Phase 14.1.6: Use asLivingEntity() instead of getPlayer()
|
|
net.minecraft.world.entity.LivingEntity targetEntity =
|
|
target.asLivingEntity();
|
|
if (targetEntity == null) {
|
|
return false;
|
|
}
|
|
|
|
// Check if target is tied up
|
|
if (target.isTiedUp()) {
|
|
return true;
|
|
}
|
|
|
|
// Check if target has collar with this captor as owner
|
|
if (target.hasCollar()) {
|
|
ItemStack collar = target.getEquipment(BodyRegionV2.NECK);
|
|
if (collar.getItem() instanceof ItemCollar collarItem) {
|
|
if (
|
|
collarItem.getOwners(collar).contains(this.captor.getUUID())
|
|
) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Phase 14.1.6: Changed parameter from PlayerBindState to IBondageState
|
|
* Phase 17: Renamed from canFree to canRelease
|
|
*/
|
|
@Override
|
|
public boolean canRelease(IBondageState captive) {
|
|
if (captive == null) {
|
|
return false;
|
|
}
|
|
|
|
// Can only release if this manager is the captive's captor
|
|
return captive.getCaptor() == this;
|
|
}
|
|
|
|
/**
|
|
* Phase 17: Renamed from allowSlaveTransfer to allowCaptiveTransfer
|
|
*/
|
|
@Override
|
|
public boolean allowCaptiveTransfer() {
|
|
// Players always allow captive transfer
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Phase 17: Renamed from allowMultipleSlaves to allowMultipleCaptives
|
|
*/
|
|
@Override
|
|
public boolean allowMultipleCaptives() {
|
|
// Players can have multiple captives
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Phase 14.1.6: Changed parameter from PlayerBindState to IBondageState
|
|
* Phase 17: Renamed from onSlaveLogout to onCaptiveLogout
|
|
* Note: For NPC captives, this is never called (NPCs don't log out)
|
|
*/
|
|
@Override
|
|
public void onCaptiveLogout(IBondageState captive) {
|
|
if (captive == null) {
|
|
return;
|
|
}
|
|
|
|
TiedUpMod.LOGGER.info(
|
|
"[PlayerCaptorManager] Captive {} logged out while captured by {}",
|
|
captive.getKidnappedName(),
|
|
captor.getName().getString()
|
|
);
|
|
|
|
// Keep captive in list - they might reconnect
|
|
// Transport entity will despawn after timeout
|
|
// On reconnect, checkStillCaptive() will clean up if needed
|
|
}
|
|
|
|
/**
|
|
* Phase 14.1.6: Changed parameter from PlayerBindState to IBondageState
|
|
* Phase 17: Renamed from onSlaveReleased to onCaptiveReleased
|
|
*/
|
|
@Override
|
|
public void onCaptiveReleased(IBondageState captive) {
|
|
if (captive == null) {
|
|
return;
|
|
}
|
|
|
|
TiedUpMod.LOGGER.info(
|
|
"[PlayerCaptorManager] Captive {} was released from {}",
|
|
captive.getKidnappedName(),
|
|
captor.getName().getString()
|
|
);
|
|
|
|
// No special action needed - already removed from list by removeCaptive()
|
|
}
|
|
|
|
/**
|
|
* Phase 14.1.6: Changed parameter from PlayerBindState to IBondageState
|
|
* Phase 17: Renamed from onSlaveStruggle to onCaptiveStruggle
|
|
*/
|
|
@Override
|
|
public void onCaptiveStruggle(IBondageState captive) {
|
|
if (captive == null) {
|
|
return;
|
|
}
|
|
|
|
TiedUpMod.LOGGER.debug(
|
|
"[PlayerCaptorManager] Captive {} struggled (captor: {})",
|
|
captive.getKidnappedName(),
|
|
captor.getName().getString()
|
|
);
|
|
|
|
// Phase 8: No action for basic struggle
|
|
// Phase 14: Shock collar would activate here
|
|
}
|
|
|
|
/**
|
|
* Phase 17: Renamed from hasSlaves to hasCaptives
|
|
*/
|
|
@Override
|
|
public boolean hasCaptives() {
|
|
return !captives.isEmpty();
|
|
}
|
|
|
|
@Override
|
|
public Entity getEntity() {
|
|
return captor;
|
|
}
|
|
|
|
// ========================================
|
|
// Additional Methods
|
|
// ========================================
|
|
|
|
/**
|
|
* Frees all captives currently owned by this captor.
|
|
*
|
|
* Phase 17: Renamed from freeAllSlaves to freeAllCaptives
|
|
*
|
|
* Thread Safety: Synchronized on 'this' to match addCaptive and removeCaptive.
|
|
*
|
|
* @param transportState If true, destroy the transporter entities
|
|
*/
|
|
public synchronized void freeAllCaptives(boolean transportState) {
|
|
// Use a copy to avoid concurrent modification while iterating
|
|
List<IBondageState> copy = new ArrayList<>(captives);
|
|
for (IBondageState captive : copy) {
|
|
captive.free(transportState);
|
|
}
|
|
captives.clear();
|
|
}
|
|
|
|
/**
|
|
* Frees all captives with default behavior (destroy transport entities).
|
|
*/
|
|
public void freeAllCaptives() {
|
|
freeAllCaptives(true);
|
|
}
|
|
|
|
/**
|
|
* Get a copy of the captive list.
|
|
* Safe for iteration without concurrent modification issues.
|
|
*
|
|
* Phase 17: Renamed from getSlaves to getCaptives
|
|
*
|
|
* @return Copy of the current captive list
|
|
*/
|
|
public List<IBondageState> getCaptives() {
|
|
return new ArrayList<>(captives);
|
|
}
|
|
|
|
/**
|
|
* Get the number of captives currently owned.
|
|
*
|
|
* Phase 17: Renamed from getSlaveCount to getCaptiveCount
|
|
*
|
|
* @return Captive count
|
|
*/
|
|
public int getCaptiveCount() {
|
|
return captives.size();
|
|
}
|
|
|
|
/**
|
|
* Transfer all captives from this captor to a new captor.
|
|
* Used when this player gets captured themselves.
|
|
*
|
|
* From original code:
|
|
* - When a player gets captured, their captives transfer to new captor
|
|
* - Prevents circular capture issues
|
|
*
|
|
* Phase 17: Renamed from transferAllSlavesTo to transferAllCaptivesTo
|
|
*
|
|
* @param newCaptor The new captor to transfer captives to
|
|
*/
|
|
public void transferAllCaptivesTo(ICaptor newCaptor) {
|
|
if (newCaptor == null) {
|
|
TiedUpMod.LOGGER.warn(
|
|
"[PlayerCaptorManager] Attempted to transfer captives to null captor"
|
|
);
|
|
return;
|
|
}
|
|
|
|
if (captives.isEmpty()) {
|
|
return;
|
|
}
|
|
|
|
TiedUpMod.LOGGER.info(
|
|
"[PlayerCaptorManager] Transferring {} captives from {} to {}",
|
|
captives.size(),
|
|
captor.getName().getString(),
|
|
newCaptor.getEntity().getName().getString()
|
|
);
|
|
|
|
// Create copy to avoid concurrent modification
|
|
List<IBondageState> captivesToTransfer = new ArrayList<>(captives);
|
|
|
|
for (IBondageState captive : captivesToTransfer) {
|
|
if (captive != null) {
|
|
captive.transferCaptivityTo(newCaptor);
|
|
}
|
|
}
|
|
|
|
// All captives should now be removed from this manager's list
|
|
if (!captives.isEmpty()) {
|
|
TiedUpMod.LOGGER.warn(
|
|
"[PlayerCaptorManager] {} captives remain after transfer - cleaning up",
|
|
captives.size()
|
|
);
|
|
captives.clear();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the captor player.
|
|
*
|
|
* @return The player who owns this manager
|
|
*/
|
|
public Player getCaptor() {
|
|
return captor;
|
|
}
|
|
|
|
/**
|
|
* Clean up invalid captives from the list.
|
|
* Removes captives that are no longer valid (offline, transport gone, etc.).
|
|
*
|
|
* Phase 17: Renamed from cleanupInvalidSlaves to cleanupInvalidCaptives
|
|
*
|
|
* Should be called periodically (e.g., on tick).
|
|
*/
|
|
public void cleanupInvalidCaptives() {
|
|
captives.removeIf(captive -> {
|
|
if (captive == null) {
|
|
return true;
|
|
}
|
|
|
|
// Remove if not actually captured anymore
|
|
if (!captive.isCaptive()) {
|
|
TiedUpMod.LOGGER.debug(
|
|
"[PlayerCaptorManager] Removing invalid captive {}",
|
|
captive.getKidnappedName()
|
|
);
|
|
return true;
|
|
}
|
|
|
|
// Remove if captured by different captor
|
|
if (captive.getCaptor() != this) {
|
|
TiedUpMod.LOGGER.debug(
|
|
"[PlayerCaptorManager] Removing captive {} (belongs to different captor)",
|
|
captive.getKidnappedName()
|
|
);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
});
|
|
}
|
|
|
|
// ========================================
|
|
// Backward Compatibility (Phase 17)
|
|
// ========================================
|
|
}
|