Files
TiedUp-/src/main/java/com/tiedup/remake/dialogue/conversation/PetRequestManager.java
NotEvil 3d61c9e9e6 feat(D-01/C): consumer migration — 85 files migrated to V2 helpers
Phase 1 (state): PlayerBindState, PlayerCaptorManager, PlayerEquipment,
  PlayerDataRetrieval, PlayerLifecycle, PlayerShockCollar, StruggleAccessory
Phase 2 (client): AnimationTickHandler, NpcAnimationTickHandler, 5 render
  handlers, DamselModel, 3 client mixins, SelfBondageInputHandler,
  SlaveManagementScreen, ActionPanel, SlaveEntryWidget, ModKeybindings
Phase 3 (entities): 28 entity/AI files migrated to CollarHelper,
  BindModeHelper, PoseTypeHelper, createStack()
Phase 4 (network): PacketSlaveAction, PacketMasterEquip,
  PacketAssignCellToCollar, PacketNpcCommand, PacketFurnitureForcemount
Phase 5 (events): RestraintTaskTickHandler, PetPlayRestrictionHandler,
  PlayerEnslavementHandler, ChatEventHandler, LaborAttackPunishmentHandler
Phase 6 (commands): BondageSubCommand, CollarCommand, NPCCommand,
  KidnapSetCommand
Phase 7 (compat): MCAKidnappedAdapter, MCA mixins
Phase 8 (misc): GagTalkManager, PetRequestManager, HangingCagePiece,
  BondageItemBlockEntity, TrappedChestBlockEntity, DispenserBehaviors,
  BondageItemLoaderUtility, RestraintApplicator, StruggleSessionManager,
  MovementStyleResolver, CampLifecycleManager

Some files retain dual V1/V2 checks (instanceof V1 || V2Helper) for
coexistence — V1-only branches removed in Branch D.
2026-04-15 00:16:50 +02:00

286 lines
9.2 KiB
Java

package com.tiedup.remake.dialogue.conversation;
import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.dialogue.DialogueBridge;
import com.tiedup.remake.entities.EntityMaster;
import com.tiedup.remake.entities.ai.master.MasterPlaceBlockGoal;
import com.tiedup.remake.entities.ai.master.MasterState;
import com.tiedup.remake.network.ModNetwork;
import com.tiedup.remake.v2.bondage.datadriven.DataDrivenBondageItem;
import net.minecraft.resources.ResourceLocation;
import com.tiedup.remake.network.master.PacketOpenPetRequestMenu;
import com.tiedup.remake.state.PlayerBindState;
import com.tiedup.remake.v2.BodyRegionV2;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.item.ItemStack;
/**
* Manager for handling pet requests to their Master NPC.
*
* This is the server-side handler for player-initiated requests in pet play mode.
* Utilizes existing systems:
* - PlayerEquipment.equip(BodyRegionV2.ARMS, bind) / takeBindOff() for tie/untie
* - MasterState.DOGWALK for walk mode
* - MasterPlaceBlockGoal for feeding/resting
* - Leash physics via mixin for pulling the player
*/
public class PetRequestManager {
/** Maximum distance for pet request interaction */
private static final double MAX_DISTANCE = 6.0;
/**
* Open the pet request menu for a pet player.
* Sends a packet to the client to display the GUI.
*
* @param master The master entity
* @param pet The pet player
*/
public static void openRequestMenu(EntityMaster master, ServerPlayer pet) {
if (!master.isPetPlayer(pet)) {
TiedUpMod.LOGGER.warn(
"[PetRequestManager] {} is not a pet of {}",
pet.getName().getString(),
master.getNpcName()
);
return;
}
// Check distance
double dist = master.distanceTo(pet);
if (dist > MAX_DISTANCE) {
pet.sendSystemMessage(
Component.literal("You are too far from your Master to talk.")
);
return;
}
// Send packet to open GUI on client
ModNetwork.sendToPlayer(
new PacketOpenPetRequestMenu(master.getId(), master.getNpcName()),
pet
);
TiedUpMod.LOGGER.debug(
"[PetRequestManager] Opened request menu for {} with {}",
pet.getName().getString(),
master.getNpcName()
);
}
/**
* Handle a request from the pet player.
* Called when the player selects an option from the pet request menu.
*
* @param master The master entity
* @param pet The pet player making the request
* @param request The request type
*/
public static void handleRequest(
EntityMaster master,
ServerPlayer pet,
PetRequest request
) {
if (!master.isPetPlayer(pet)) {
TiedUpMod.LOGGER.warn(
"[PetRequestManager] Rejected request from non-pet {} to {}",
pet.getName().getString(),
master.getNpcName()
);
return;
}
// Check distance
double dist = master.distanceTo(pet);
if (dist > MAX_DISTANCE) {
pet.sendSystemMessage(
Component.literal("You are too far from your Master.")
);
return;
}
TiedUpMod.LOGGER.info(
"[PetRequestManager] {} requested {} from {}",
pet.getName().getString(),
request.name(),
master.getNpcName()
);
// Display what the player "says"
pet.sendSystemMessage(
Component.literal("You: " + request.getPlayerText())
);
// Handle specific request
switch (request) {
case REQUEST_FOOD -> triggerFeeding(master, pet);
case REQUEST_SLEEP -> triggerResting(master, pet);
case REQUEST_WALK_PASSIVE -> triggerDogwalk(master, pet, false);
case REQUEST_WALK_ACTIVE -> triggerDogwalk(master, pet, true);
case REQUEST_TIE -> triggerTie(master, pet);
case REQUEST_UNTIE -> triggerUntie(master, pet);
case END_CONVERSATION -> endConversation(master, pet);
}
}
/**
* Trigger feeding action - Master places bowl for pet.
*/
private static void triggerFeeding(EntityMaster master, ServerPlayer pet) {
DialogueBridge.talkTo(master, pet, "petplay.feeding");
MasterPlaceBlockGoal goal = master.getPlaceBlockGoal();
if (goal != null) {
goal.triggerFeeding();
}
}
/**
* Trigger resting action - Master places pet bed for pet.
*/
private static void triggerResting(EntityMaster master, ServerPlayer pet) {
DialogueBridge.talkTo(master, pet, "petplay.resting");
MasterPlaceBlockGoal goal = master.getPlaceBlockGoal();
if (goal != null) {
goal.triggerResting();
}
}
/**
* Trigger dogwalk mode.
* Puts dogbind on player and attaches leash.
*
* @param masterLeads If true, Master walks and pulls pet. If false, Master follows pet.
*/
private static void triggerDogwalk(
EntityMaster master,
ServerPlayer pet,
boolean masterLeads
) {
// Get player bind state
PlayerBindState state = PlayerBindState.getInstance(pet);
if (state == null) {
TiedUpMod.LOGGER.warn(
"[PetRequestManager] Could not get PlayerBindState for {}",
pet.getName().getString()
);
return;
}
// Put dogbind on player (if not already tied)
if (!state.isTiedUp()) {
ItemStack dogbind = DataDrivenBondageItem.createStack(new ResourceLocation("tiedup", "dogbinder"));
state.equip(BodyRegionV2.ARMS, dogbind);
TiedUpMod.LOGGER.debug(
"[PetRequestManager] Equipped dogbind on {} for walk",
pet.getName().getString()
);
}
// Attach leash
master.attachLeashToPet();
// Set dogwalk mode
master.setDogwalkMode(masterLeads);
master.setMasterState(MasterState.DOGWALK);
String dialogueId = masterLeads
? "petplay.walk_active"
: "petplay.walk_passive";
DialogueBridge.talkTo(master, pet, dialogueId);
TiedUpMod.LOGGER.info(
"[PetRequestManager] {} entered DOGWALK mode with {} (masterLeads={})",
master.getNpcName(),
pet.getName().getString(),
masterLeads
);
}
/**
* Trigger tie request - Master ties up the pet.
*/
private static void triggerTie(EntityMaster master, ServerPlayer pet) {
// Don't allow tie requests during dogwalk
if (master.getStateManager().getCurrentState() == MasterState.DOGWALK) {
DialogueBridge.talkTo(master, pet, "petplay.busy");
return;
}
// Get player bind state
PlayerBindState state = PlayerBindState.getInstance(pet);
if (state == null) {
TiedUpMod.LOGGER.warn(
"[PetRequestManager] Could not get PlayerBindState for {}",
pet.getName().getString()
);
return;
}
// Check if already tied
if (state.isTiedUp()) {
DialogueBridge.talkTo(master, pet, "petplay.already_tied");
return;
}
// Master equips armbinder on pet (classic pet play restraint)
ItemStack bind = DataDrivenBondageItem.createStack(new ResourceLocation("tiedup", "armbinder"));
state.equip(BodyRegionV2.ARMS, bind);
DialogueBridge.talkTo(master, pet, "petplay.tie_accept");
TiedUpMod.LOGGER.info(
"[PetRequestManager] {} tied up {} with armbinder",
master.getNpcName(),
pet.getName().getString()
);
}
/**
* Trigger untie request - Master unties the pet.
*/
private static void triggerUntie(EntityMaster master, ServerPlayer pet) {
// Don't allow untie requests during dogwalk
if (master.getStateManager().getCurrentState() == MasterState.DOGWALK) {
DialogueBridge.talkTo(master, pet, "petplay.busy");
return;
}
// Get player bind state
PlayerBindState state = PlayerBindState.getInstance(pet);
if (state == null) {
TiedUpMod.LOGGER.warn(
"[PetRequestManager] Could not get PlayerBindState for {}",
pet.getName().getString()
);
return;
}
// Check if actually tied
if (!state.isTiedUp()) {
DialogueBridge.talkTo(master, pet, "petplay.not_tied");
return;
}
// Master removes bind from pet
state.unequip(BodyRegionV2.ARMS);
DialogueBridge.talkTo(master, pet, "petplay.untie_accept");
TiedUpMod.LOGGER.info(
"[PetRequestManager] {} untied {}",
master.getNpcName(),
pet.getName().getString()
);
}
/**
* End the conversation gracefully.
*/
private static void endConversation(EntityMaster master, ServerPlayer pet) {
DialogueBridge.talkTo(master, pet, "petplay.dismiss");
}
}