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:
@@ -0,0 +1,295 @@
|
||||
package com.tiedup.remake.state.components;
|
||||
|
||||
import com.tiedup.remake.core.TiedUpMod;
|
||||
import com.tiedup.remake.entities.LeashProxyEntity;
|
||||
import com.tiedup.remake.state.IPlayerLeashAccess;
|
||||
import com.tiedup.remake.state.ICaptor;
|
||||
import com.tiedup.remake.state.hosts.IPlayerBindStateHost;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Component responsible for captivity mechanics and leash proxy management.
|
||||
* Phase 17: Advanced capture system (proxy-based leashing)
|
||||
*
|
||||
* Single Responsibility: Captivity lifecycle and transport management
|
||||
* Complexity: VERY HIGH (mixin coupling, network sync, leash proxy coordination)
|
||||
* Risk: VERY HIGH (critical path, mixin dependency, 4 network sync points)
|
||||
*
|
||||
* Mixin Dependency: IPlayerLeashAccess for leash proxy system
|
||||
* Network Sync: 4 syncEnslavement() calls coordinated via host
|
||||
*
|
||||
* Captivity States:
|
||||
* - Not Captive: No captor, no leash
|
||||
* - Captive (by entity): Has captor, leashed to entity
|
||||
* - Pole Binding: No captor, leashed to pole (LeashFenceKnotEntity)
|
||||
*/
|
||||
public class PlayerCaptivity {
|
||||
|
||||
private final IPlayerBindStateHost host;
|
||||
|
||||
public PlayerCaptivity(IPlayerBindStateHost host) {
|
||||
this.host = host;
|
||||
}
|
||||
|
||||
// ========== Captivity Initiation ==========
|
||||
|
||||
/**
|
||||
* Phase 17: Renamed from getEnslavedBy to getCapturedBy
|
||||
* Initiates the capture process by a captor.
|
||||
* Uses the proxy-based leash system (player is NOT mounted).
|
||||
*
|
||||
* Thread Safety: Synchronized to prevent race condition where two kidnappers
|
||||
* could both pass the isCaptive() check and attempt to capture simultaneously.
|
||||
*
|
||||
* @param newCaptor The entity attempting to capture this player
|
||||
* @return true if capture succeeded
|
||||
*/
|
||||
public synchronized boolean getCapturedBy(ICaptor newCaptor) {
|
||||
Player player = host.getPlayer();
|
||||
if (player == null || newCaptor == null) return false;
|
||||
|
||||
// Must be enslavable (tied up) OR captor can capture (includes collar owner exception)
|
||||
if (
|
||||
!isEnslavable() && !newCaptor.canCapture(host.getKidnapped())
|
||||
) return false;
|
||||
|
||||
// Check if already captured (atomic check under synchronization)
|
||||
if (isCaptive()) return false;
|
||||
|
||||
// Free all captives instead of transferring (until multi-captive is implemented)
|
||||
if (host.getCaptorManager().hasCaptives()) {
|
||||
TiedUpMod.LOGGER.debug(
|
||||
"[PlayerCaptivity] {} is being captured - freeing their {} captives",
|
||||
player.getName().getString(),
|
||||
host.getCaptorManager().getCaptiveCount()
|
||||
);
|
||||
host.getCaptorManager().freeAllCaptives(true);
|
||||
}
|
||||
|
||||
// Use new proxy-based leash system
|
||||
if (player instanceof IPlayerLeashAccess access) {
|
||||
access.tiedup$attachLeash(newCaptor.getEntity());
|
||||
newCaptor.addCaptive(host.getKidnapped());
|
||||
host.setCaptor(newCaptor);
|
||||
|
||||
TiedUpMod.LOGGER.debug(
|
||||
"[PlayerCaptivity] {} captured by {} (proxy leash)",
|
||||
player.getName().getString(),
|
||||
newCaptor.getEntity().getName().getString()
|
||||
);
|
||||
|
||||
// Sync enslavement state to all clients
|
||||
host.syncEnslavement();
|
||||
return true;
|
||||
}
|
||||
|
||||
TiedUpMod.LOGGER.error(
|
||||
"[PlayerCaptivity] Player {} does not implement IPlayerLeashAccess!",
|
||||
player.getName().getString()
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
// ========== Captivity Release ==========
|
||||
|
||||
/**
|
||||
* Ends captivity with default behavior (drops leash item).
|
||||
*/
|
||||
public void free() {
|
||||
free(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Phase 17: Ends captivity and detaches the leash proxy.
|
||||
*
|
||||
* @param dropLead Whether to drop the leash item
|
||||
*/
|
||||
public void free(boolean dropLead) {
|
||||
Player player = host.getPlayer();
|
||||
if (player == null) return;
|
||||
|
||||
if (!(player instanceof IPlayerLeashAccess access)) {
|
||||
TiedUpMod.LOGGER.error(
|
||||
"[PlayerCaptivity] Player {} does not implement IPlayerLeashAccess!",
|
||||
player.getName().getString()
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
ICaptor captor = host.getCaptor();
|
||||
|
||||
// Handle pole binding (no captor) - just detach leash
|
||||
if (captor == null) {
|
||||
if (access.tiedup$isLeashed()) {
|
||||
TiedUpMod.LOGGER.debug(
|
||||
"[PlayerCaptivity] Freeing {} from pole binding",
|
||||
player.getName().getString()
|
||||
);
|
||||
if (dropLead) {
|
||||
access.tiedup$dropLeash();
|
||||
}
|
||||
access.tiedup$detachLeash();
|
||||
host.syncEnslavement();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
TiedUpMod.LOGGER.debug(
|
||||
"[PlayerCaptivity] Freeing {} from captivity",
|
||||
player.getName().getString()
|
||||
);
|
||||
|
||||
// 1. Remove from captor's tracking list
|
||||
captor.removeCaptive(host.getKidnapped(), false);
|
||||
|
||||
// 2. Detach leash proxy
|
||||
if (dropLead) {
|
||||
access.tiedup$dropLeash();
|
||||
}
|
||||
access.tiedup$detachLeash();
|
||||
|
||||
// 3. Reset state
|
||||
host.setCaptor(null);
|
||||
|
||||
// 4. Sync freed state to all clients
|
||||
host.syncEnslavement();
|
||||
}
|
||||
|
||||
// ========== Captivity Transfer ==========
|
||||
|
||||
/**
|
||||
* Phase 17: Renamed from transferSlaveryTo to transferCaptivityTo
|
||||
* Transfers captivity from current captor to a new captor.
|
||||
*
|
||||
* Thread Safety: Synchronized to prevent concurrent transfer attempts.
|
||||
*
|
||||
* @param newCaptor The new captor entity
|
||||
*/
|
||||
public synchronized void transferCaptivityTo(ICaptor newCaptor) {
|
||||
Player player = host.getPlayer();
|
||||
ICaptor currentCaptor = host.getCaptor();
|
||||
|
||||
if (
|
||||
player == null ||
|
||||
newCaptor == null ||
|
||||
currentCaptor == null ||
|
||||
!currentCaptor.allowCaptiveTransfer()
|
||||
) return;
|
||||
|
||||
currentCaptor.removeCaptive(host.getKidnapped(), false);
|
||||
|
||||
// Re-attach leash to new captor
|
||||
if (player instanceof IPlayerLeashAccess access) {
|
||||
access.tiedup$detachLeash();
|
||||
access.tiedup$attachLeash(newCaptor.getEntity());
|
||||
}
|
||||
|
||||
newCaptor.addCaptive(host.getKidnapped());
|
||||
host.setCaptor(newCaptor);
|
||||
|
||||
// Sync new captor to all clients
|
||||
host.syncEnslavement();
|
||||
}
|
||||
|
||||
// ========== State Queries ==========
|
||||
|
||||
/**
|
||||
* Check if this player can be captured (leashed).
|
||||
* Must be tied up to be leashed.
|
||||
* Collar alone is NOT enough - collar owner exception is handled in canCapture().
|
||||
*
|
||||
* @return true if player is tied up and can be leashed
|
||||
*/
|
||||
public boolean isEnslavable() {
|
||||
return host.isTiedUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Phase 17: Renamed from isSlave to isCaptive
|
||||
* Check if player is currently captured by an entity.
|
||||
*
|
||||
* @return true if player has a captor and is leashed
|
||||
*/
|
||||
public boolean isCaptive() {
|
||||
Player player = host.getPlayer();
|
||||
if (host.getCaptor() == null) return false;
|
||||
if (player instanceof IPlayerLeashAccess access) {
|
||||
return access.tiedup$isLeashed();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the leash proxy entity (transport system).
|
||||
* Phase 17: Proxy-based leashing (no mounting).
|
||||
*
|
||||
* @return The leash proxy, or null if not leashed
|
||||
*/
|
||||
@Nullable
|
||||
public LeashProxyEntity getTransport() {
|
||||
Player player = host.getPlayer();
|
||||
if (player instanceof IPlayerLeashAccess access) {
|
||||
return access.tiedup$getLeashProxy();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// ========== Captivity Monitoring ==========
|
||||
|
||||
/**
|
||||
* Phase 17: Renamed from checkStillSlave to checkStillCaptive
|
||||
* Periodically monitors captivity validity.
|
||||
* Simplified: If any condition is invalid, free the captive immediately.
|
||||
*
|
||||
* Called from RestraintTaskTickHandler every player tick.
|
||||
*/
|
||||
public void checkStillCaptive() {
|
||||
if (!isCaptive()) return;
|
||||
|
||||
Player player = host.getPlayer();
|
||||
if (player == null) return;
|
||||
|
||||
// Check if no longer tied/collared
|
||||
if (!host.isTiedUp() && !host.hasCollar()) {
|
||||
TiedUpMod.LOGGER.debug(
|
||||
"[PlayerCaptivity] Auto-freeing {} - no restraints",
|
||||
player.getName().getString()
|
||||
);
|
||||
free();
|
||||
return;
|
||||
}
|
||||
|
||||
// Check leash proxy status
|
||||
if (player instanceof IPlayerLeashAccess access) {
|
||||
LeashProxyEntity proxy = access.tiedup$getLeashProxy();
|
||||
if (proxy == null || proxy.proxyIsRemoved()) {
|
||||
TiedUpMod.LOGGER.debug(
|
||||
"[PlayerCaptivity] Auto-freeing {} - proxy invalid",
|
||||
player.getName().getString()
|
||||
);
|
||||
// Notify captor BEFORE freeing (triggers retrieval behavior)
|
||||
ICaptor captor = host.getCaptor();
|
||||
if (captor != null) {
|
||||
captor.onCaptiveReleased(host.getKidnapped());
|
||||
}
|
||||
free();
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if leash holder is still valid
|
||||
if (proxy.getLeashHolder() == null) {
|
||||
TiedUpMod.LOGGER.debug(
|
||||
"[PlayerCaptivity] Auto-freeing {} - leash holder gone",
|
||||
player.getName().getString()
|
||||
);
|
||||
// Notify captor BEFORE freeing (triggers retrieval behavior)
|
||||
ICaptor captor = host.getCaptor();
|
||||
if (captor != null) {
|
||||
captor.onCaptiveReleased(host.getKidnapped());
|
||||
}
|
||||
free();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user