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:
346
src/main/java/com/tiedup/remake/tasks/TyingPlayerTask.java
Normal file
346
src/main/java/com/tiedup/remake/tasks/TyingPlayerTask.java
Normal file
@@ -0,0 +1,346 @@
|
||||
package com.tiedup.remake.tasks;
|
||||
|
||||
import com.tiedup.remake.core.TiedUpMod;
|
||||
import com.tiedup.remake.v2.BodyRegionV2;
|
||||
import com.tiedup.remake.network.ModNetwork;
|
||||
import com.tiedup.remake.network.action.PacketTying;
|
||||
import com.tiedup.remake.state.IBondageState;
|
||||
import com.tiedup.remake.state.PlayerBindState;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
|
||||
/**
|
||||
* Phase 6: Concrete tying task for tying up any IBondageState entity.
|
||||
* Phase 14.2.6: Unified to work with both Players and NPCs.
|
||||
*
|
||||
* Based on original TyingPlayerTask from 1.12.2
|
||||
*
|
||||
* This task:
|
||||
* 1. Tracks progress as the kidnapper repeatedly right-clicks the target
|
||||
* 2. Sends progress updates to kidnapper (and target if it's a player)
|
||||
* 3. Applies the bind/gag when the timer completes
|
||||
* 4. Works with any LivingEntity that has an IBondageState state
|
||||
*/
|
||||
public class TyingPlayerTask extends TyingTask {
|
||||
|
||||
/** The player performing the tying action. */
|
||||
protected Player kidnapper;
|
||||
|
||||
/** FIX: Source inventory slot to consume from when task completes */
|
||||
private int sourceSlot = -1;
|
||||
|
||||
/** FIX: Source player whose inventory to consume from */
|
||||
private Player sourcePlayer;
|
||||
|
||||
/**
|
||||
* Create a new tying task.
|
||||
*
|
||||
* @param bind The bind/gag item to apply
|
||||
* @param targetState The target's IBondageState state
|
||||
* @param targetEntity The target entity (Player or NPC)
|
||||
* @param seconds Total duration in seconds
|
||||
* @param level The world
|
||||
*/
|
||||
public TyingPlayerTask(
|
||||
ItemStack bind,
|
||||
IBondageState targetState,
|
||||
LivingEntity targetEntity,
|
||||
int seconds,
|
||||
Level level
|
||||
) {
|
||||
super(bind, targetState, targetEntity, seconds, level);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new tying task with kidnapper reference.
|
||||
*
|
||||
* @param bind The bind/gag item to apply
|
||||
* @param targetState The target's IBondageState state
|
||||
* @param targetEntity The target entity (Player or NPC)
|
||||
* @param seconds Total duration in seconds
|
||||
* @param level The world
|
||||
* @param kidnapper The player performing the tying
|
||||
*/
|
||||
public TyingPlayerTask(
|
||||
ItemStack bind,
|
||||
IBondageState targetState,
|
||||
LivingEntity targetEntity,
|
||||
int seconds,
|
||||
Level level,
|
||||
Player kidnapper
|
||||
) {
|
||||
super(bind, targetState, targetEntity, seconds, level);
|
||||
this.kidnapper = kidnapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the kidnapper (the player doing the tying).
|
||||
*/
|
||||
public void setKidnapper(Player kidnapper) {
|
||||
this.kidnapper = kidnapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* FIX: Set the source inventory slot for item consumption.
|
||||
* Called when task starts to track which slot to consume from.
|
||||
*/
|
||||
public void setSourceSlot(int slot) {
|
||||
this.sourceSlot = slot;
|
||||
}
|
||||
|
||||
/**
|
||||
* FIX: Set the source player for item consumption.
|
||||
* Called when task starts to track whose inventory to consume from.
|
||||
*/
|
||||
public void setSourcePlayer(Player player) {
|
||||
this.sourcePlayer = player;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the tying progress.
|
||||
* Called each time the kidnapper right-clicks the target (or left-clicks for self-tying).
|
||||
*
|
||||
* In the new progress-based system, this method only:
|
||||
* 1. Validates kidnapper is still close to target
|
||||
* 2. Marks this tick as "active" (progress will increase in tick())
|
||||
*
|
||||
* The actual progress increment and completion check happen in tick().
|
||||
*/
|
||||
@Override
|
||||
public synchronized void update() {
|
||||
// Check if this is self-tying (target == kidnapper)
|
||||
boolean isSelfTying =
|
||||
kidnapper != null && kidnapper.equals(targetEntity);
|
||||
|
||||
// ========================================
|
||||
// SECURITY: Validate kidnapper is still close to target (skip for self-tying)
|
||||
// ========================================
|
||||
if (!isSelfTying && kidnapper != null && targetEntity != null) {
|
||||
double distance = kidnapper.distanceTo(targetEntity);
|
||||
if (distance > 4.0) {
|
||||
TiedUpMod.LOGGER.debug(
|
||||
"[TyingPlayerTask] Kidnapper {} moved too far from target ({} blocks), cancelling",
|
||||
kidnapper.getName().getString(),
|
||||
String.format("%.1f", distance)
|
||||
);
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
|
||||
// Check line-of-sight
|
||||
if (!kidnapper.hasLineOfSight(targetEntity)) {
|
||||
TiedUpMod.LOGGER.debug(
|
||||
"[TyingPlayerTask] Kidnapper {} lost line of sight to target, cancelling",
|
||||
kidnapper.getName().getString()
|
||||
);
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Mark this tick as active (player is clicking on target)
|
||||
super.update();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send progress packets to both kidnapper and target (if players).
|
||||
* Called every tick from ItemBind or RestraintTaskTickHandler.
|
||||
*/
|
||||
@Override
|
||||
public void sendProgressPackets() {
|
||||
if (stopped) return;
|
||||
|
||||
// Check if this is self-tying (target == kidnapper)
|
||||
boolean isSelfTying =
|
||||
kidnapper != null && kidnapper.equals(targetEntity);
|
||||
|
||||
String kidnapperName =
|
||||
kidnapper != null ? kidnapper.getName().getString() : "Someone";
|
||||
String targetName = targetEntity.getName().getString();
|
||||
|
||||
if (isSelfTying) {
|
||||
// Self-tying: Send single packet with self-tying message
|
||||
if (kidnapper instanceof ServerPlayer serverPlayer) {
|
||||
PacketTying selfPacket = new PacketTying(
|
||||
this.getState(),
|
||||
this.getMaxSeconds(),
|
||||
true, // isKidnapper (shows "Tying..." message)
|
||||
"yourself" // Special indicator for self-tying
|
||||
);
|
||||
ModNetwork.sendToPlayer(selfPacket, serverPlayer);
|
||||
}
|
||||
} else {
|
||||
// Normal tying: Send packets to both parties
|
||||
// Packet to victim: isKidnapper=false, shows kidnapper's name
|
||||
if (targetEntity instanceof ServerPlayer serverTarget) {
|
||||
PacketTying victimPacket = new PacketTying(
|
||||
this.getState(),
|
||||
this.getMaxSeconds(),
|
||||
false,
|
||||
kidnapperName
|
||||
);
|
||||
ModNetwork.sendToPlayer(victimPacket, serverTarget);
|
||||
}
|
||||
|
||||
// Packet to kidnapper: isKidnapper=true, shows target's name
|
||||
if (kidnapper instanceof ServerPlayer serverKidnapper) {
|
||||
PacketTying kidnapperPacket = new PacketTying(
|
||||
this.getState(),
|
||||
this.getMaxSeconds(),
|
||||
true,
|
||||
targetName
|
||||
);
|
||||
ModNetwork.sendToPlayer(kidnapperPacket, serverKidnapper);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the task completes successfully.
|
||||
* Applies the bind, consumes the item, and sends completion packets.
|
||||
*/
|
||||
@Override
|
||||
protected void onComplete() {
|
||||
// Verify target entity still exists and is alive
|
||||
if (!isTargetValid()) {
|
||||
TiedUpMod.LOGGER.warn(
|
||||
"[TyingPlayerTask] Target entity no longer valid, cancelling task"
|
||||
);
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
|
||||
TiedUpMod.LOGGER.info(
|
||||
"[TyingPlayerTask] Tying complete for {}",
|
||||
targetEntity.getName().getString()
|
||||
);
|
||||
|
||||
// Apply the bind/gag to the target
|
||||
targetState.equip(BodyRegionV2.ARMS, bind);
|
||||
|
||||
// FIX: Consume the item from the stored inventory slot
|
||||
// This prevents duplication by consuming from the exact slot used to start the task
|
||||
if (sourcePlayer != null && sourceSlot >= 0) {
|
||||
ItemStack slotStack = sourcePlayer
|
||||
.getInventory()
|
||||
.getItem(sourceSlot);
|
||||
if (
|
||||
!slotStack.isEmpty() &&
|
||||
ItemStack.isSameItemSameTags(slotStack, bind)
|
||||
) {
|
||||
slotStack.shrink(1);
|
||||
TiedUpMod.LOGGER.debug(
|
||||
"[TyingPlayerTask] Consumed bind item from slot {}",
|
||||
sourceSlot
|
||||
);
|
||||
} else {
|
||||
// Slot changed - try to find and consume from any matching slot
|
||||
for (
|
||||
int i = 0;
|
||||
i < sourcePlayer.getInventory().getContainerSize();
|
||||
i++
|
||||
) {
|
||||
ItemStack checkStack = sourcePlayer
|
||||
.getInventory()
|
||||
.getItem(i);
|
||||
if (
|
||||
!checkStack.isEmpty() &&
|
||||
ItemStack.isSameItemSameTags(checkStack, bind)
|
||||
) {
|
||||
checkStack.shrink(1);
|
||||
TiedUpMod.LOGGER.debug(
|
||||
"[TyingPlayerTask] Consumed bind item from fallback slot {}",
|
||||
i
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Track who tied this entity (for reward anti-abuse)
|
||||
if (
|
||||
targetEntity instanceof
|
||||
com.tiedup.remake.entities.EntityDamsel damsel
|
||||
) {
|
||||
damsel.setTiedBy(kidnapper);
|
||||
}
|
||||
|
||||
// Mark task as stopped
|
||||
stop();
|
||||
|
||||
sendCompletionPackets();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send completion packets to kidnapper and/or target.
|
||||
* Handles both self-tying and normal tying cases.
|
||||
*/
|
||||
protected void sendCompletionPackets() {
|
||||
boolean isSelfTying =
|
||||
kidnapper != null && kidnapper.equals(targetEntity);
|
||||
|
||||
String kidnapperName =
|
||||
kidnapper != null ? kidnapper.getName().getString() : "Someone";
|
||||
String targetName = targetEntity.getName().getString();
|
||||
|
||||
if (isSelfTying) {
|
||||
if (kidnapper instanceof ServerPlayer serverPlayer) {
|
||||
PacketTying completionPacket = new PacketTying(
|
||||
-1, this.getMaxSeconds(), true, "yourself"
|
||||
);
|
||||
ModNetwork.sendToPlayer(completionPacket, serverPlayer);
|
||||
|
||||
PlayerBindState playerState = PlayerBindState.getInstance(serverPlayer);
|
||||
if (playerState != null) {
|
||||
playerState.setRestrainedState(null);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (targetEntity instanceof ServerPlayer serverTarget) {
|
||||
PacketTying completionPacket = new PacketTying(
|
||||
-1, this.getMaxSeconds(), false, kidnapperName
|
||||
);
|
||||
ModNetwork.sendToPlayer(completionPacket, serverTarget);
|
||||
|
||||
PlayerBindState playerState = PlayerBindState.getInstance(serverTarget);
|
||||
if (playerState != null) {
|
||||
playerState.setRestrainedState(null);
|
||||
}
|
||||
}
|
||||
|
||||
if (kidnapper instanceof ServerPlayer serverKidnapper) {
|
||||
PacketTying completionPacket = new PacketTying(
|
||||
-1, this.getMaxSeconds(), true, targetName
|
||||
);
|
||||
ModNetwork.sendToPlayer(completionPacket, serverKidnapper);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up the target's restraint state for client-side progress tracking.
|
||||
* Only applies to player targets (NPCs don't need client-side state).
|
||||
*
|
||||
* Note: On dedicated servers, this is a no-op. The client receives
|
||||
* progress packets (PacketTying) which create the PlayerStateTask locally.
|
||||
*/
|
||||
@Override
|
||||
public void setUpTargetState() {
|
||||
// Only set up state for player targets
|
||||
if (!(targetEntity instanceof Player targetPlayer)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Server-side: nothing to do - client handles its own PlayerStateTask via packets
|
||||
if (!targetPlayer.level().isClientSide) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Client-side: set up local progress tracking (only reached in single-player/integrated server)
|
||||
// Note: This code path is rarely used since packets handle client-side state
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user