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,548 @@
package com.tiedup.remake.minigame;
import com.tiedup.remake.v2.BodyRegionV2;
import java.util.Random;
import java.util.UUID;
import org.jetbrains.annotations.Nullable;
/**
* Server-side state for the continuous Struggle mini-game session.
*
* New system: Player holds a direction key to continuously reduce resistance.
* - Progression: 1 resistance per second when holding correct direction
* - Direction changes randomly every 3-5 seconds
* - Shock collar check: 10% chance every 5 seconds (if locked collar equipped)
* - No cooldown, no penalty for wrong key (just no progress)
*/
public class ContinuousStruggleMiniGameState {
/**
* Possible directions for struggling.
*/
public enum Direction {
UP(0), // W / Forward
LEFT(1), // A / Strafe Left
DOWN(2), // S / Back
RIGHT(3); // D / Strafe Right
private final int index;
Direction(int index) {
this.index = index;
}
public int getIndex() {
return index;
}
public static Direction fromIndex(int index) {
return switch (index) {
case 0 -> UP;
case 1 -> LEFT;
case 2 -> DOWN;
case 3 -> RIGHT;
default -> UP;
};
}
public static Direction random(Random random) {
return fromIndex(random.nextInt(4));
}
}
/**
* State of the continuous struggle session.
*/
public enum State {
/** Actively struggling */
ACTIVE,
/** Temporarily interrupted by shock collar */
SHOCKED,
/** Successfully escaped (resistance reached 0) */
ESCAPED,
/** Cancelled by player or damage */
CANCELLED,
}
/**
* Type of state update sent to client.
*/
public enum UpdateType {
START,
DIRECTION_CHANGE,
RESISTANCE_UPDATE,
SHOCK,
ESCAPE,
END,
}
// ==================== CONSTANTS ====================
/** Minimum interval for direction change (3 seconds = 60 ticks) */
private static final int DIRECTION_CHANGE_MIN_TICKS = 60;
/** Maximum interval for direction change (5 seconds = 100 ticks) */
private static final int DIRECTION_CHANGE_MAX_TICKS = 100;
/** Interval for shock collar check (5 seconds = 100 ticks) */
private static final int SHOCK_CHECK_INTERVAL_TICKS = 100;
/** Shock probability (10% = 10 out of 100) */
private static final int SHOCK_PROBABILITY = 10;
/** Default ticks per 1 resistance point (20 ticks = 1 second per resistance) */
private static final int DEFAULT_TICKS_PER_RESISTANCE = 20;
/** Shock stun duration in ticks (1 second) */
private static final int SHOCK_STUN_TICKS = 20;
/** Kidnapper notification interval (2 seconds = 40 ticks) */
private static final int KIDNAPPER_NOTIFY_INTERVAL_TICKS = 40;
/** Struggle sound interval (1.5 seconds = 30 ticks) */
private static final int STRUGGLE_SOUND_INTERVAL_TICKS = 30;
/** Session timeout in milliseconds (10 minutes) */
private static final long SESSION_TIMEOUT_MS = 10L * 60L * 1000L;
// ==================== FIELDS ====================
private final UUID sessionId;
private final UUID playerId;
private final long createdAt;
/** Current required direction (0-3 for W/A/S/D) */
private Direction currentDirection;
/** Current resistance remaining */
private int currentResistance;
/** Maximum resistance (initial value) for display percentage */
private final int maxResistance;
/** Accumulated progress toward next resistance point (0.0 to 1.0) */
private float accumulatedProgress;
/** Tick when direction last changed */
private long lastDirectionChangeTick;
/** Tick when shock was last checked */
private long lastShockCheckTick;
/** Tick when kidnappers were last notified */
private long lastKidnapperNotifyTick;
/** Tick when struggle sound was last played */
private long lastStruggleSoundTick;
/** Ticks until direction change */
private int ticksUntilDirectionChange;
/** Current session state */
private State state;
/** Ticks remaining in shock stun */
private int shockStunTicksRemaining;
/** Whether player is currently holding the correct key */
private boolean isHoldingCorrectKey;
/** Direction player is currently holding (-1 if none) */
private int heldDirection;
/** Whether the bind is locked (affects display only, locks add +250 resistance) */
private boolean isLocked;
/** Target accessory slot (null = bind, otherwise = accessory) */
private Integer targetSlot;
/** Target V2 body region (null = V1 session, non-null = V2 session) */
@Nullable
private BodyRegionV2 targetRegion;
/** Target furniture entity ID (non-zero = furniture struggle session) */
private int furnitureEntityId;
/** Target seat ID for furniture struggles (null = not a furniture session) */
@Nullable
private String furnitureSeatId;
/** Resistance reduction per tick (computed from ticksPerResistance) */
private final float resistancePerTick;
private final Random random = new Random();
// ==================== CONSTRUCTOR ====================
public ContinuousStruggleMiniGameState(
UUID playerId,
int targetResistance,
boolean isLocked
) {
this(
playerId,
targetResistance,
isLocked,
null,
DEFAULT_TICKS_PER_RESISTANCE
);
}
public ContinuousStruggleMiniGameState(
UUID playerId,
int targetResistance,
boolean isLocked,
Integer targetSlot
) {
this(
playerId,
targetResistance,
isLocked,
targetSlot,
DEFAULT_TICKS_PER_RESISTANCE
);
}
/**
* Constructor with target slot and configurable rate.
*
* @param playerId Player UUID
* @param targetResistance Current resistance
* @param isLocked Whether the target is locked
* @param targetSlot Target accessory slot (null = bind)
* @param ticksPerResistance Ticks per 1 resistance point (from game rule)
*/
public ContinuousStruggleMiniGameState(
UUID playerId,
int targetResistance,
boolean isLocked,
Integer targetSlot,
int ticksPerResistance
) {
this.sessionId = UUID.randomUUID();
this.playerId = playerId;
this.createdAt = System.currentTimeMillis();
this.resistancePerTick = 1.0f / Math.max(1, ticksPerResistance);
this.currentResistance = targetResistance;
this.maxResistance = targetResistance;
this.isLocked = isLocked;
this.targetSlot = targetSlot;
// Initialize direction
this.currentDirection = Direction.random(random);
this.accumulatedProgress = 0.0f;
// Initialize timers (will be set properly on first tick)
this.lastDirectionChangeTick = 0;
this.lastShockCheckTick = 0;
this.lastKidnapperNotifyTick = 0;
this.ticksUntilDirectionChange = randomDirectionChangeInterval();
// Initial state
this.state = State.ACTIVE;
this.shockStunTicksRemaining = 0;
this.isHoldingCorrectKey = false;
this.heldDirection = -1;
}
// ==================== GETTERS ====================
public UUID getSessionId() {
return sessionId;
}
public UUID getPlayerId() {
return playerId;
}
public Direction getCurrentDirection() {
return currentDirection;
}
public int getCurrentDirectionIndex() {
return currentDirection.getIndex();
}
public int getCurrentResistance() {
return currentResistance;
}
public int getMaxResistance() {
return maxResistance;
}
public float getProgressPercentage() {
if (maxResistance == 0) return 0.0f;
return 1.0f - ((float) currentResistance / (float) maxResistance);
}
public State getState() {
return state;
}
public boolean isLocked() {
return isLocked;
}
public Integer getTargetSlot() {
return targetSlot;
}
public boolean isAccessoryStruggle() {
return targetSlot != null;
}
/** Get the V2 target region (null for V1 sessions). */
@Nullable
public BodyRegionV2 getTargetRegion() {
return targetRegion;
}
/** Set the V2 target region. */
public void setTargetRegion(@Nullable BodyRegionV2 region) {
this.targetRegion = region;
}
/** Whether this is a V2 region-based struggle session. */
public boolean isV2Struggle() {
return targetRegion != null;
}
/** Get the furniture entity ID (0 = not a furniture session). */
public int getFurnitureEntityId() {
return furnitureEntityId;
}
/** Get the furniture seat ID (null = not a furniture session). */
@Nullable
public String getFurnitureSeatId() {
return furnitureSeatId;
}
/** Set furniture struggle context. */
public void setFurnitureContext(int entityId, String seatId) {
this.furnitureEntityId = entityId;
this.furnitureSeatId = seatId;
}
/** Whether this is a furniture escape struggle session. */
public boolean isFurnitureStruggle() {
return furnitureEntityId != 0 && furnitureSeatId != null;
}
public boolean isActive() {
return state == State.ACTIVE;
}
public boolean isShocked() {
return state == State.SHOCKED;
}
public boolean isComplete() {
return state == State.ESCAPED || state == State.CANCELLED;
}
public boolean isExpired() {
return System.currentTimeMillis() - createdAt > SESSION_TIMEOUT_MS;
}
public boolean isHoldingCorrectKey() {
return isHoldingCorrectKey;
}
public int getHeldDirection() {
return heldDirection;
}
// ==================== STATE UPDATES ====================
/**
* Update the held direction from client input.
*
* @param direction Direction index (-1 if not holding any key)
* @param isHolding True if player is actively holding the key
*/
public void updateHeldDirection(int direction, boolean isHolding) {
this.heldDirection = direction;
this.isHoldingCorrectKey =
isHolding && (direction == currentDirection.getIndex());
}
/**
* Process a server tick.
*
* @param currentTick Current game tick
* @return True if state changed significantly (needs client update)
*/
public TickResult tick(long currentTick) {
if (isComplete()) {
return TickResult.NO_CHANGE;
}
// Handle shock stun
if (state == State.SHOCKED) {
shockStunTicksRemaining--;
if (shockStunTicksRemaining <= 0) {
state = State.ACTIVE;
return TickResult.SHOCK_END;
}
return TickResult.NO_CHANGE;
}
boolean needsUpdate = false;
TickResult result = TickResult.NO_CHANGE;
// Direction change check
ticksUntilDirectionChange--;
if (ticksUntilDirectionChange <= 0) {
changeDirection(currentTick);
result = TickResult.DIRECTION_CHANGE;
}
// Progress resistance if holding correct key
if (isHoldingCorrectKey) {
accumulatedProgress += resistancePerTick;
if (accumulatedProgress >= 1.0f) {
int resistanceReduced = (int) accumulatedProgress;
accumulatedProgress -= resistanceReduced;
currentResistance = Math.max(
0,
currentResistance - resistanceReduced
);
if (result == TickResult.NO_CHANGE) {
result = TickResult.RESISTANCE_UPDATE;
}
// Check for escape
if (currentResistance <= 0) {
state = State.ESCAPED;
return TickResult.ESCAPED;
}
}
}
return result;
}
/**
* Result of a tick update.
*/
public enum TickResult {
NO_CHANGE,
DIRECTION_CHANGE,
RESISTANCE_UPDATE,
SHOCK_START,
SHOCK_END,
ESCAPED,
KIDNAPPER_NOTIFY,
}
/**
* Check if shock collar should trigger.
*
* @param currentTick Current game tick
* @return True if shock should be triggered
*/
public boolean shouldTriggerShock(long currentTick) {
if (state != State.ACTIVE) return false;
if (
currentTick - lastShockCheckTick < SHOCK_CHECK_INTERVAL_TICKS
) return false;
lastShockCheckTick = currentTick;
return random.nextInt(100) < SHOCK_PROBABILITY;
}
/**
* Trigger a shock event.
*/
public void triggerShock() {
if (state != State.ACTIVE) return;
state = State.SHOCKED;
shockStunTicksRemaining = SHOCK_STUN_TICKS;
isHoldingCorrectKey = false;
}
/**
* Check if kidnappers should be notified.
*
* @param currentTick Current game tick
* @return True if kidnappers should be notified
*/
public boolean shouldNotifyKidnappers(long currentTick) {
if (state != State.ACTIVE || !isHoldingCorrectKey) return false;
if (
currentTick - lastKidnapperNotifyTick <
KIDNAPPER_NOTIFY_INTERVAL_TICKS
) return false;
lastKidnapperNotifyTick = currentTick;
return true;
}
/**
* Check if struggle sound should play.
*
* @param currentTick Current game tick
* @return True if struggle sound should be played
*/
public boolean shouldPlayStruggleSound(long currentTick) {
if (state != State.ACTIVE || !isHoldingCorrectKey) return false;
if (
currentTick - lastStruggleSoundTick < STRUGGLE_SOUND_INTERVAL_TICKS
) return false;
lastStruggleSoundTick = currentTick;
return true;
}
/**
* Cancel the session.
*/
public void cancel() {
state = State.CANCELLED;
}
// ==================== PRIVATE HELPERS ====================
private void changeDirection(long currentTick) {
Direction newDirection;
do {
newDirection = Direction.random(random);
} while (newDirection == currentDirection);
currentDirection = newDirection;
lastDirectionChangeTick = currentTick;
ticksUntilDirectionChange = randomDirectionChangeInterval();
// LOW FIX: Always reset held key status to prevent lucky guess exploit
// Player must release and re-press the key to react to direction change
// even if they were already holding the new correct key
isHoldingCorrectKey = false;
}
private int randomDirectionChangeInterval() {
return (
DIRECTION_CHANGE_MIN_TICKS +
random.nextInt(
DIRECTION_CHANGE_MAX_TICKS - DIRECTION_CHANGE_MIN_TICKS + 1
)
);
}
@Override
public String toString() {
return String.format(
"ContinuousStruggleMiniGameState{session=%s, player=%s, dir=%s, resistance=%d/%d, state=%s}",
sessionId.toString().substring(0, 8),
playerId.toString().substring(0, 8),
currentDirection,
currentResistance,
maxResistance,
state
);
}
}