Strip all Phase references, TODO/FUTURE roadmap notes, and internal planning comments from the codebase. Run Prettier for consistent formatting across all Java files.
157 lines
5.3 KiB
Java
157 lines
5.3 KiB
Java
package com.tiedup.remake.client.events;
|
|
|
|
import com.tiedup.remake.core.TiedUpMod;
|
|
import com.tiedup.remake.items.ModItems;
|
|
import com.tiedup.remake.items.base.BindVariant;
|
|
import com.tiedup.remake.state.IBondageState;
|
|
import com.tiedup.remake.util.KidnappedHelper;
|
|
import com.tiedup.remake.v2.BodyRegionV2;
|
|
import java.util.Map;
|
|
import java.util.UUID;
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
import net.minecraft.client.Minecraft;
|
|
import net.minecraft.world.entity.Entity;
|
|
import net.minecraft.world.entity.player.Player;
|
|
import net.minecraft.world.item.ItemStack;
|
|
import net.minecraft.world.level.Level;
|
|
import net.minecraft.world.phys.Vec3;
|
|
import net.minecraftforge.api.distmarker.Dist;
|
|
import net.minecraftforge.api.distmarker.OnlyIn;
|
|
import net.minecraftforge.event.TickEvent;
|
|
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
|
import net.minecraftforge.fml.common.Mod;
|
|
|
|
/**
|
|
* Client-side handler for smooth leash proxy positioning.
|
|
*
|
|
* FIX: Changed from RenderLevelStageEvent.AFTER_ENTITIES to ClientTickEvent.
|
|
* AFTER_ENTITIES positioned the proxy AFTER rendering, causing 1-frame lag.
|
|
* ClientTickEvent positions BEFORE rendering for smooth leash display.
|
|
*
|
|
* Instead of waiting for server position updates (which causes lag),
|
|
* this handler repositions the proxy entity locally each tick based
|
|
* on the player's current position.
|
|
*/
|
|
@OnlyIn(Dist.CLIENT)
|
|
@Mod.EventBusSubscriber(
|
|
modid = TiedUpMod.MOD_ID,
|
|
value = Dist.CLIENT,
|
|
bus = Mod.EventBusSubscriber.Bus.FORGE
|
|
)
|
|
public class LeashProxyClientHandler {
|
|
|
|
/**
|
|
* Map of player UUID -> proxy entity ID.
|
|
* Uses UUID for player (persistent) and entity ID for proxy (runtime).
|
|
*/
|
|
private static final Map<UUID, Integer> playerToProxy =
|
|
new ConcurrentHashMap<>();
|
|
|
|
/** Default Y offset for normal standing pose (neck height) */
|
|
private static final double DEFAULT_Y_OFFSET = 1.3;
|
|
|
|
/** Y offset for dogwalk pose (back/hip level) */
|
|
private static final double DOGWALK_Y_OFFSET = 0.35;
|
|
|
|
/**
|
|
* Handle sync packet from server.
|
|
* Called when a player gets leashed or unleashed.
|
|
*/
|
|
public static void handleSyncPacket(
|
|
UUID targetPlayerUUID,
|
|
int proxyId,
|
|
boolean attach
|
|
) {
|
|
if (attach) {
|
|
playerToProxy.put(targetPlayerUUID, proxyId);
|
|
TiedUpMod.LOGGER.debug(
|
|
"[LeashProxyClient] Registered proxy {} for player {}",
|
|
proxyId,
|
|
targetPlayerUUID
|
|
);
|
|
} else {
|
|
playerToProxy.remove(targetPlayerUUID);
|
|
TiedUpMod.LOGGER.debug(
|
|
"[LeashProxyClient] Removed proxy for player {}",
|
|
targetPlayerUUID
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* FIX: Use ClientTickEvent instead of RenderLevelStageEvent.AFTER_ENTITIES.
|
|
* This positions proxies BEFORE rendering, eliminating the 1-frame lag
|
|
* that caused jittery leash rendering.
|
|
*/
|
|
@SubscribeEvent
|
|
public static void onClientTick(TickEvent.ClientTickEvent event) {
|
|
// Only run at end of tick (after player position is updated)
|
|
if (event.phase != TickEvent.Phase.END) {
|
|
return;
|
|
}
|
|
|
|
if (playerToProxy.isEmpty()) {
|
|
return;
|
|
}
|
|
|
|
Minecraft mc = Minecraft.getInstance();
|
|
if (mc == null || mc.level == null || mc.isPaused()) {
|
|
return;
|
|
}
|
|
Level level = mc.level;
|
|
|
|
// Reposition each tracked proxy
|
|
for (Map.Entry<UUID, Integer> entry : playerToProxy.entrySet()) {
|
|
UUID playerUUID = entry.getKey();
|
|
int proxyId = entry.getValue();
|
|
|
|
Player playerEntity = level.getPlayerByUUID(playerUUID);
|
|
Entity proxyEntity = level.getEntity(proxyId);
|
|
|
|
if (playerEntity != null && proxyEntity != null) {
|
|
// FIX: Calculate Y offset based on bind type (dogwalk vs normal)
|
|
double yOffset = calculateYOffset(playerEntity);
|
|
|
|
// Use current position (interpolation will be handled by renderer)
|
|
double x = playerEntity.getX();
|
|
double y = playerEntity.getY() + yOffset;
|
|
double z = playerEntity.getZ() - 0.15;
|
|
|
|
// Set proxy position
|
|
proxyEntity.setPos(x, y, z);
|
|
|
|
// Update old positions for smooth interpolation
|
|
proxyEntity.xOld = proxyEntity.xo = x;
|
|
proxyEntity.yOld = proxyEntity.yo = y;
|
|
proxyEntity.zOld = proxyEntity.zo = z;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Calculate Y offset based on player's bind type.
|
|
* Dogwalk (DOGBINDER) uses lower offset for 4-legged pose.
|
|
*/
|
|
private static double calculateYOffset(Player player) {
|
|
IBondageState state = KidnappedHelper.getKidnappedState(player);
|
|
if (state != null && state.isTiedUp()) {
|
|
ItemStack bind = state.getEquipment(BodyRegionV2.ARMS);
|
|
if (
|
|
!bind.isEmpty() &&
|
|
bind.getItem() == ModItems.getBind(BindVariant.DOGBINDER)
|
|
) {
|
|
return DOGWALK_Y_OFFSET;
|
|
}
|
|
}
|
|
return DEFAULT_Y_OFFSET;
|
|
}
|
|
|
|
/**
|
|
* Clear all tracked proxies.
|
|
* Called when disconnecting from server.
|
|
*/
|
|
public static void clearAll() {
|
|
playerToProxy.clear();
|
|
}
|
|
}
|