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:
NotEvil
2026-04-12 00:51:22 +02:00
parent 2e7a1d403b
commit f6466360b6
1947 changed files with 238025 additions and 1 deletions

View File

@@ -0,0 +1,397 @@
package com.tiedup.remake.tasks;
import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.entities.EntityDamsel;
import com.tiedup.remake.entities.NpcTypeHelper;
import com.tiedup.remake.network.ModNetwork;
import com.tiedup.remake.network.action.PacketUntying;
import com.tiedup.remake.state.IBondageState;
import com.tiedup.remake.state.PlayerBindState;
import com.tiedup.remake.v2.BodyRegionV2;
import com.tiedup.remake.v2.bondage.capability.V2EquipmentHelper;
import java.util.Map;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
/**
* Phase 6: Concrete untying task for freeing a tied entity.
* Phase 14.2.6: Unified to work with both Players and NPCs.
*
* Based on original UntyingPlayerTask from 1.12.2
*
* This task:
* 1. Tracks progress as the helper repeatedly right-clicks the tied target
* 2. Sends progress updates to both helper and target clients (if player)
* 3. Removes all restraints and drops items when the timer completes
* 4. Sets up target's restraint state for client-side visualization (if player)
*
* Epic 5F: Uses V2EquipmentHelper/BodyRegionV2.
*/
public class UntyingPlayerTask extends UntyingTask {
/** The player performing the untying action. */
private Player helper;
/**
* Create a new untying task.
*
* @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 UntyingPlayerTask(
IBondageState targetState,
LivingEntity targetEntity,
int seconds,
Level level
) {
super(targetState, targetEntity, seconds, level);
}
/**
* Create a new untying task with helper reference.
*
* @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 helper The player performing the untying
*/
public UntyingPlayerTask(
IBondageState targetState,
LivingEntity targetEntity,
int seconds,
Level level,
Player helper
) {
super(targetState, targetEntity, seconds, level);
this.helper = helper;
}
/**
* Set the helper (the player doing the untying).
*/
public void setHelper(Player helper) {
this.helper = helper;
}
/**
* Update the untying progress.
* Called each time the helper right-clicks the tied target.
*
* In the new progress-based system, this method only:
* 1. Marks this tick as "active" (progress will increase in tick())
* 2. Validates helper is still close to target
*
* The actual progress increment and completion check happen in tick().
*/
@Override
public synchronized void update() {
// ========================================
// SECURITY: Validate helper is still close to target
// ========================================
if (helper != null && targetEntity != null) {
double distance = helper.distanceTo(targetEntity);
if (distance > 4.0) {
TiedUpMod.LOGGER.debug(
"[UntyingPlayerTask] Helper {} moved too far from target ({} blocks), cancelling",
helper.getName().getString(),
String.format("%.1f", distance)
);
stop();
return;
}
// Check line-of-sight
if (!helper.hasLineOfSight(targetEntity)) {
TiedUpMod.LOGGER.debug(
"[UntyingPlayerTask] Helper {} lost line of sight to target, cancelling",
helper.getName().getString()
);
stop();
return;
}
}
// Mark this tick as active (player is clicking on target)
super.update();
}
/**
* Send progress packets to both helper and target (if players).
* Called every tick from RestraintTaskTickHandler.onPlayerTick().
*/
@Override
public void sendProgressPackets() {
if (stopped) return;
String helperName =
helper != null ? helper.getName().getString() : "Someone";
String targetName = targetEntity.getName().getString();
// Packet to victim: isHelper=false, shows helper's name
if (targetEntity instanceof ServerPlayer serverTarget) {
PacketUntying victimPacket = new PacketUntying(
this.getState(),
this.getMaxSeconds(),
false,
helperName
);
ModNetwork.sendToPlayer(victimPacket, serverTarget);
}
// Packet to helper: isHelper=true, shows target's name
if (helper instanceof ServerPlayer serverHelper) {
PacketUntying helperPacket = new PacketUntying(
this.getState(),
this.getMaxSeconds(),
true,
targetName
);
ModNetwork.sendToPlayer(helperPacket, serverHelper);
}
}
/**
* Called when the task completes successfully.
* Drops bondage items, frees the target, and sends completion packets.
*/
@Override
protected void onComplete() {
// Verify target entity still exists and is alive
if (!isTargetValid()) {
TiedUpMod.LOGGER.warn(
"[UntyingPlayerTask] Target entity no longer valid, cancelling task"
);
stop();
return;
}
TiedUpMod.LOGGER.info(
"[UntyingPlayerTask] Untying complete for {}",
targetEntity.getName().getString()
);
// Drop all bondage items on the ground
dropBondageItems();
// Remove all restraints from target
untieTarget();
// Handle Damsel-specific rewards
if (targetEntity instanceof EntityDamsel damsel && NpcTypeHelper.isDamselOnly(targetEntity) && helper != null) {
// Reward the savior (gives emeralds and marks player as savior)
damsel.rewardSavior(helper);
}
// Mark task as stopped
stop();
// Send completion packets to both parties
String helperName =
helper != null ? helper.getName().getString() : "Someone";
String targetName = targetEntity.getName().getString();
if (targetEntity instanceof ServerPlayer serverTarget) {
PacketUntying completionPacket = new PacketUntying(
-1,
this.getMaxSeconds(),
false,
helperName
);
ModNetwork.sendToPlayer(completionPacket, serverTarget);
PlayerBindState playerState = PlayerBindState.getInstance(
serverTarget
);
if (playerState != null) {
playerState.setRestrainedState(null);
}
}
if (helper instanceof ServerPlayer serverHelper) {
PacketUntying completionPacket = new PacketUntying(
-1,
this.getMaxSeconds(),
true,
targetName
);
ModNetwork.sendToPlayer(completionPacket, serverHelper);
}
}
/**
* 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 (PacketUntying) 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
}
/**
* Drop all bondage items on the ground.
* Works for both players (via V2EquipmentHelper) and NPCs (via IBondageState).
*/
private void dropBondageItems() {
// For player targets: use V2EquipmentHelper to get all equipped items
if (targetEntity instanceof Player player) {
Map<BodyRegionV2, ItemStack> equipped = V2EquipmentHelper.getAllEquipped(player);
for (Map.Entry<BodyRegionV2, ItemStack> entry : equipped.entrySet()) {
ItemStack stack = entry.getValue();
if (!stack.isEmpty()) {
// Drop item at player's position
ItemEntity itemEntity = new ItemEntity(
targetEntity.level(),
targetEntity.getX(),
targetEntity.getY(),
targetEntity.getZ(),
stack.copy()
);
targetEntity.level().addFreshEntity(itemEntity);
TiedUpMod.LOGGER.debug(
"[UntyingPlayerTask] Dropped {} from region {}",
stack.getHoverName().getString(),
entry.getKey().name()
);
}
}
} else {
// For NPC targets: use IBondageState interface
// Drop bind if present
ItemStack bind = targetState.getEquipment(BodyRegionV2.ARMS);
if (bind != null && !bind.isEmpty()) {
ItemEntity itemEntity = new ItemEntity(
targetEntity.level(),
targetEntity.getX(),
targetEntity.getY(),
targetEntity.getZ(),
bind.copy()
);
targetEntity.level().addFreshEntity(itemEntity);
TiedUpMod.LOGGER.debug(
"[UntyingPlayerTask] Dropped bind: {}",
bind.getHoverName().getString()
);
}
// Drop gag if present
ItemStack gag = targetState.getEquipment(BodyRegionV2.MOUTH);
if (gag != null && !gag.isEmpty()) {
ItemEntity itemEntity = new ItemEntity(
targetEntity.level(),
targetEntity.getX(),
targetEntity.getY(),
targetEntity.getZ(),
gag.copy()
);
targetEntity.level().addFreshEntity(itemEntity);
TiedUpMod.LOGGER.debug(
"[UntyingPlayerTask] Dropped gag: {}",
gag.getHoverName().getString()
);
}
// Drop blindfold if present
ItemStack blindfold = targetState.getEquipment(BodyRegionV2.EYES);
if (blindfold != null && !blindfold.isEmpty()) {
ItemEntity itemEntity = new ItemEntity(
targetEntity.level(),
targetEntity.getX(),
targetEntity.getY(),
targetEntity.getZ(),
blindfold.copy()
);
targetEntity.level().addFreshEntity(itemEntity);
TiedUpMod.LOGGER.debug(
"[UntyingPlayerTask] Dropped blindfold: {}",
blindfold.getHoverName().getString()
);
}
// Drop earplugs if present
ItemStack earplugs = targetState.getEquipment(BodyRegionV2.EARS);
if (earplugs != null && !earplugs.isEmpty()) {
ItemEntity itemEntity = new ItemEntity(
targetEntity.level(),
targetEntity.getX(),
targetEntity.getY(),
targetEntity.getZ(),
earplugs.copy()
);
targetEntity.level().addFreshEntity(itemEntity);
TiedUpMod.LOGGER.debug(
"[UntyingPlayerTask] Dropped earplugs: {}",
earplugs.getHoverName().getString()
);
}
// Drop mittens if present
ItemStack mittens = targetState.getEquipment(BodyRegionV2.HANDS);
if (mittens != null && !mittens.isEmpty()) {
ItemEntity itemEntity = new ItemEntity(
targetEntity.level(),
targetEntity.getX(),
targetEntity.getY(),
targetEntity.getZ(),
mittens.copy()
);
targetEntity.level().addFreshEntity(itemEntity);
TiedUpMod.LOGGER.debug(
"[UntyingPlayerTask] Dropped mittens: {}",
mittens.getHoverName().getString()
);
}
}
}
/**
* Remove all restraints from the target entity.
* Works for both players and NPCs via IBondageState interface.
*/
private void untieTarget() {
// For player targets: clear all V2 equipment (fires onUnequipped callbacks)
if (targetEntity instanceof Player player) {
V2EquipmentHelper.clearAll(player);
// Phase 17: Free from captivity/leash if applicable (player-specific)
PlayerBindState playerState = PlayerBindState.getInstance(player);
if (playerState != null && playerState.isCaptive()) {
playerState.free();
}
} else {
// For NPC targets: use IBondageState interface directly
targetState.unequip(BodyRegionV2.ARMS);
targetState.unequip(BodyRegionV2.MOUTH);
targetState.unequip(BodyRegionV2.EYES);
targetState.unequip(BodyRegionV2.EARS);
targetState.unequip(BodyRegionV2.HANDS);
}
TiedUpMod.LOGGER.info(
"[UntyingPlayerTask] Fully untied {}",
targetEntity.getName().getString()
);
}
}