Strip all Phase references, TODO/FUTURE roadmap notes, and internal planning comments from the codebase. Run Prettier for consistent formatting across all Java files.
451 lines
13 KiB
Java
451 lines
13 KiB
Java
package com.tiedup.remake.compat.mca;
|
|
|
|
import com.tiedup.remake.compat.mca.ai.MCABondageAIController;
|
|
import com.tiedup.remake.compat.mca.ai.MCABondageAILevel;
|
|
import com.tiedup.remake.compat.mca.dialogue.MCADialogueManager;
|
|
import com.tiedup.remake.compat.mca.personality.MCAMoodManager;
|
|
import com.tiedup.remake.compat.mca.personality.MCAPersonality;
|
|
import com.tiedup.remake.compat.mca.personality.MCAPersonalityManager;
|
|
import com.tiedup.remake.core.TiedUpMod;
|
|
import com.tiedup.remake.state.IRestrainable;
|
|
import java.util.Map;
|
|
import java.util.WeakHashMap;
|
|
import net.minecraft.world.entity.Entity;
|
|
import net.minecraft.world.entity.LivingEntity;
|
|
import net.minecraft.world.item.ItemStack;
|
|
import org.jetbrains.annotations.Nullable;
|
|
|
|
/**
|
|
* Central coordinator for all MCA-TiedUp integration.
|
|
*
|
|
* Responsibilities:
|
|
* - Manages AI state for tied MCA villagers
|
|
* - Coordinates sync operations
|
|
* - Provides unified API for bondage operations
|
|
* - Handles capture/release lifecycle
|
|
*
|
|
* This is the main entry point for all MCA bondage operations.
|
|
* Other code should go through this manager rather than directly
|
|
* manipulating capabilities or AI.
|
|
*/
|
|
public class MCABondageManager {
|
|
|
|
// Singleton instance
|
|
private static final MCABondageManager INSTANCE = new MCABondageManager();
|
|
|
|
// Track AI controllers for villagers (weak ref to avoid memory leaks)
|
|
private final Map<LivingEntity, MCABondageAIController> aiControllers =
|
|
new WeakHashMap<>();
|
|
|
|
private MCABondageManager() {
|
|
// Private constructor for singleton
|
|
}
|
|
|
|
/**
|
|
* Get the singleton instance.
|
|
*/
|
|
public static MCABondageManager getInstance() {
|
|
return INSTANCE;
|
|
}
|
|
|
|
// LIFECYCLE EVENTS
|
|
|
|
/** Dialogue broadcast radius in blocks */
|
|
private static final double DIALOGUE_RADIUS = 16.0;
|
|
|
|
/**
|
|
* Called when MCA villager is tied up.
|
|
* Initializes or updates AI control and syncs state.
|
|
*
|
|
* @param villager The MCA villager entity
|
|
* @param bind The bind item being applied
|
|
*/
|
|
public void onVillagerTied(LivingEntity villager, ItemStack bind) {
|
|
if (!MCACompat.isMCAVillager(villager)) return;
|
|
|
|
MCAPersonality personality =
|
|
MCAPersonalityManager.getInstance().getPersonality(villager);
|
|
|
|
TiedUpMod.LOGGER.debug(
|
|
"[MCA Manager] Villager tied: {} with {} (personality: {})",
|
|
villager.getName().getString(),
|
|
bind.getItem().getClass().getSimpleName(),
|
|
personality.getMcaId()
|
|
);
|
|
|
|
// Update AI level with personality
|
|
MCABondageAIController controller = getOrCreateAIController(villager);
|
|
controller.setPersonality(personality);
|
|
controller.updateAILevel();
|
|
|
|
// Mood change
|
|
MCAMoodManager.getInstance().onTied(villager);
|
|
|
|
// Dialogue
|
|
String dialogue = MCADialogueManager.getBeingTiedDialogue(villager);
|
|
MCADialogueManager.broadcastDialogue(
|
|
villager,
|
|
dialogue,
|
|
DIALOGUE_RADIUS
|
|
);
|
|
|
|
// Sync to clients
|
|
syncBondageState(villager);
|
|
}
|
|
|
|
/**
|
|
* Called when MCA villager is untied.
|
|
* Updates AI control and syncs state.
|
|
*
|
|
* @param villager The MCA villager entity
|
|
*/
|
|
public void onVillagerUntied(LivingEntity villager) {
|
|
if (!MCACompat.isMCAVillager(villager)) return;
|
|
|
|
TiedUpMod.LOGGER.debug(
|
|
"[MCA Manager] Villager untied: {}",
|
|
villager.getName().getString()
|
|
);
|
|
|
|
// Update AI level (may restore normal behavior)
|
|
MCABondageAIController controller = aiControllers.get(villager);
|
|
if (controller != null) {
|
|
controller.updateAILevel();
|
|
|
|
// If fully free, cleanup controller
|
|
if (controller.getCurrentLevel() == MCABondageAILevel.NONE) {
|
|
controller.cleanup();
|
|
aiControllers.remove(villager);
|
|
}
|
|
}
|
|
|
|
// Sync to clients
|
|
syncBondageState(villager);
|
|
}
|
|
|
|
/**
|
|
* Called when MCA villager is captured (leashed to a captor).
|
|
*
|
|
* @param villager The MCA villager entity
|
|
* @param captor The entity capturing the villager
|
|
*/
|
|
public void onVillagerCaptured(LivingEntity villager, Entity captor) {
|
|
if (!MCACompat.isMCAVillager(villager)) return;
|
|
|
|
TiedUpMod.LOGGER.debug(
|
|
"[MCA Manager] Villager captured: {} by {}",
|
|
villager.getName().getString(),
|
|
captor.getName().getString()
|
|
);
|
|
|
|
// Update AI to include follow behavior
|
|
MCABondageAIController controller = getOrCreateAIController(villager);
|
|
controller.updateAILevel();
|
|
|
|
// Sync to clients
|
|
syncBondageState(villager);
|
|
}
|
|
|
|
/**
|
|
* Called when MCA villager is freed from capture.
|
|
*
|
|
* @param villager The MCA villager entity
|
|
*/
|
|
public void onVillagerFreed(LivingEntity villager) {
|
|
if (!MCACompat.isMCAVillager(villager)) return;
|
|
|
|
TiedUpMod.LOGGER.debug(
|
|
"[MCA Manager] Villager freed: {}",
|
|
villager.getName().getString()
|
|
);
|
|
|
|
// Update AI level
|
|
MCABondageAIController controller = aiControllers.get(villager);
|
|
if (controller != null) {
|
|
controller.updateAILevel();
|
|
}
|
|
|
|
// Mood change (happy to be freed, usually)
|
|
MCAMoodManager.getInstance().onFreed(villager);
|
|
|
|
// Dialogue
|
|
String dialogue = MCADialogueManager.getFreedDialogue(villager);
|
|
MCADialogueManager.broadcastDialogue(
|
|
villager,
|
|
dialogue,
|
|
DIALOGUE_RADIUS
|
|
);
|
|
|
|
// Sync to clients
|
|
syncBondageState(villager);
|
|
}
|
|
|
|
/**
|
|
* Called when collar is added/removed.
|
|
*
|
|
* @param villager The MCA villager entity
|
|
* @param hasCollar Whether the villager now has a collar
|
|
*/
|
|
public void onCollarChanged(LivingEntity villager, boolean hasCollar) {
|
|
if (!MCACompat.isMCAVillager(villager)) return;
|
|
|
|
TiedUpMod.LOGGER.debug(
|
|
"[MCA Manager] Collar changed for {}: {}",
|
|
villager.getName().getString(),
|
|
hasCollar ? "added" : "removed"
|
|
);
|
|
|
|
// Update AI level
|
|
MCABondageAIController controller = getOrCreateAIController(villager);
|
|
controller.updateAILevel();
|
|
|
|
// Mood and dialogue
|
|
if (hasCollar) {
|
|
MCAMoodManager.getInstance().onCollared(villager);
|
|
String dialogue = MCADialogueManager.getCollarPutOnDialogue(
|
|
villager
|
|
);
|
|
MCADialogueManager.broadcastDialogue(
|
|
villager,
|
|
dialogue,
|
|
DIALOGUE_RADIUS
|
|
);
|
|
} else {
|
|
MCAMoodManager.getInstance().onCollarRemoved(villager);
|
|
}
|
|
|
|
// Sync to clients
|
|
syncBondageState(villager);
|
|
}
|
|
|
|
/**
|
|
* Called when gag state changes.
|
|
*
|
|
* @param villager The MCA villager entity
|
|
* @param isGagged Whether the villager is now gagged
|
|
*/
|
|
public void onGagChanged(LivingEntity villager, boolean isGagged) {
|
|
if (!MCACompat.isMCAVillager(villager)) return;
|
|
|
|
// Update AI level (gagged+blindfolded = OVERRIDE)
|
|
MCABondageAIController controller = aiControllers.get(villager);
|
|
if (controller != null) {
|
|
controller.updateAILevel();
|
|
}
|
|
|
|
// Mood change
|
|
if (isGagged) {
|
|
MCAMoodManager.getInstance().onGagged(villager);
|
|
}
|
|
|
|
// Sync to clients
|
|
syncBondageState(villager);
|
|
}
|
|
|
|
/**
|
|
* Called when blindfold state changes.
|
|
*
|
|
* @param villager The MCA villager entity
|
|
* @param isBlindfolded Whether the villager is now blindfolded
|
|
*/
|
|
public void onBlindfoldChanged(
|
|
LivingEntity villager,
|
|
boolean isBlindfolded
|
|
) {
|
|
if (!MCACompat.isMCAVillager(villager)) return;
|
|
|
|
// Update AI level (gagged+blindfolded = OVERRIDE)
|
|
MCABondageAIController controller = aiControllers.get(villager);
|
|
if (controller != null) {
|
|
controller.updateAILevel();
|
|
}
|
|
|
|
// Mood change
|
|
if (isBlindfolded) {
|
|
MCAMoodManager.getInstance().onBlindfolded(villager);
|
|
}
|
|
|
|
// Sync to clients
|
|
syncBondageState(villager);
|
|
}
|
|
|
|
/**
|
|
* Called when any sensory restriction changes (gag/blindfold).
|
|
* Legacy method for compatibility.
|
|
*
|
|
* @param villager The MCA villager entity
|
|
*/
|
|
public void onSensoryRestrictionChanged(LivingEntity villager) {
|
|
if (!MCACompat.isMCAVillager(villager)) return;
|
|
|
|
// Update AI level (gagged+blindfolded = OVERRIDE)
|
|
MCABondageAIController controller = aiControllers.get(villager);
|
|
if (controller != null) {
|
|
controller.updateAILevel();
|
|
}
|
|
|
|
// Sync to clients
|
|
syncBondageState(villager);
|
|
}
|
|
|
|
// AI CONTROL
|
|
|
|
/**
|
|
* Get or create AI controller for villager.
|
|
*
|
|
* @param villager The MCA villager entity
|
|
* @return The AI controller (never null for valid MCA villagers)
|
|
*/
|
|
public MCABondageAIController getOrCreateAIController(
|
|
LivingEntity villager
|
|
) {
|
|
return aiControllers.computeIfAbsent(
|
|
villager,
|
|
MCABondageAIController::new
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Get AI controller for villager if it exists.
|
|
*
|
|
* @param villager The MCA villager entity
|
|
* @return The AI controller, or null if none exists
|
|
*/
|
|
@Nullable
|
|
public MCABondageAIController getAIController(LivingEntity villager) {
|
|
return aiControllers.get(villager);
|
|
}
|
|
|
|
/**
|
|
* Get current AI level for villager.
|
|
*
|
|
* @param villager The MCA villager entity
|
|
* @return The AI level (NONE if no controller exists)
|
|
*/
|
|
public MCABondageAILevel getAILevel(LivingEntity villager) {
|
|
MCABondageAIController controller = aiControllers.get(villager);
|
|
return controller != null
|
|
? controller.getCurrentLevel()
|
|
: MCABondageAILevel.NONE;
|
|
}
|
|
|
|
/**
|
|
* Force a specific AI level (for debugging/commands).
|
|
*
|
|
* @param villager The MCA villager entity
|
|
* @param level The AI level to set
|
|
*/
|
|
public void setAILevel(LivingEntity villager, MCABondageAILevel level) {
|
|
MCABondageAIController controller = getOrCreateAIController(villager);
|
|
controller.setLevel(level);
|
|
}
|
|
|
|
/**
|
|
* Check if villager should have restricted AI.
|
|
*
|
|
* @param villager The MCA villager entity
|
|
* @return true if AI is restricted in any way
|
|
*/
|
|
public boolean shouldRestrictAI(LivingEntity villager) {
|
|
return getAILevel(villager) != MCABondageAILevel.NONE;
|
|
}
|
|
|
|
// SYNC
|
|
|
|
/**
|
|
* Sync all bondage state to tracking clients.
|
|
* Delegates to MCANetworkHandler.
|
|
*
|
|
* @param villager The MCA villager entity
|
|
*/
|
|
public void syncBondageState(LivingEntity villager) {
|
|
if (villager.level().isClientSide()) return;
|
|
if (!MCACompat.isMCAVillager(villager)) return;
|
|
|
|
villager
|
|
.getCapability(MCACompat.MCA_KIDNAPPED)
|
|
.ifPresent(cap -> {
|
|
com.tiedup.remake.compat.mca.network.MCANetworkHandler.syncBondageState(
|
|
villager,
|
|
cap
|
|
);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Sync bondage state to a specific player.
|
|
* Used when player starts tracking the villager.
|
|
*
|
|
* @param villager The MCA villager entity
|
|
* @param tracker The player to sync to
|
|
*/
|
|
public void syncBondageStateTo(
|
|
LivingEntity villager,
|
|
net.minecraft.server.level.ServerPlayer tracker
|
|
) {
|
|
if (villager.level().isClientSide()) return;
|
|
if (!MCACompat.isMCAVillager(villager)) return;
|
|
|
|
villager
|
|
.getCapability(MCACompat.MCA_KIDNAPPED)
|
|
.ifPresent(cap -> {
|
|
com.tiedup.remake.compat.mca.network.MCANetworkHandler.syncBondageStateTo(
|
|
villager,
|
|
cap,
|
|
tracker
|
|
);
|
|
});
|
|
}
|
|
|
|
// QUERIES
|
|
|
|
/**
|
|
* Get IRestrainable adapter for MCA villager.
|
|
* Convenience method that delegates to MCACompat.
|
|
*
|
|
* @param villager The MCA villager entity
|
|
* @return IRestrainable adapter, or null if not an MCA villager
|
|
*/
|
|
@Nullable
|
|
public IRestrainable getKidnappedState(LivingEntity villager) {
|
|
return MCACompat.getKidnappedState(villager);
|
|
}
|
|
|
|
/**
|
|
* Check if entity is a managed MCA villager.
|
|
*
|
|
* @param entity The entity to check
|
|
* @return true if this entity is tracked by the manager
|
|
*/
|
|
public boolean isManaged(Entity entity) {
|
|
if (!(entity instanceof LivingEntity living)) return false;
|
|
return aiControllers.containsKey(living);
|
|
}
|
|
|
|
// CLEANUP
|
|
|
|
/**
|
|
* Remove all tracking for a villager.
|
|
* Called when villager dies or is removed.
|
|
*
|
|
* @param villager The MCA villager entity
|
|
*/
|
|
public void removeVillager(LivingEntity villager) {
|
|
MCABondageAIController controller = aiControllers.remove(villager);
|
|
if (controller != null) {
|
|
controller.cleanup();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Clear all tracking data.
|
|
* Called on world unload.
|
|
*/
|
|
public void clearAll() {
|
|
for (MCABondageAIController controller : aiControllers.values()) {
|
|
controller.cleanup();
|
|
}
|
|
aiControllers.clear();
|
|
}
|
|
}
|