No more direct ModConfig.SERVER access outside SettingsAccessor. 32 new accessor methods, 21 consumer files rerouted.
223 lines
6.6 KiB
Java
223 lines
6.6 KiB
Java
package com.tiedup.remake.entities;
|
|
|
|
import com.tiedup.remake.core.SettingsAccessor;
|
|
import com.tiedup.remake.core.TiedUpMod;
|
|
import com.tiedup.remake.dialogue.EntityDialogueManager;
|
|
import java.util.UUID;
|
|
import net.minecraft.nbt.CompoundTag;
|
|
import net.minecraft.world.entity.Entity;
|
|
import net.minecraft.world.entity.item.ItemEntity;
|
|
import net.minecraft.world.entity.player.Player;
|
|
import net.minecraft.world.item.ItemStack;
|
|
import net.minecraft.world.item.Items;
|
|
import org.jetbrains.annotations.Nullable;
|
|
|
|
/**
|
|
* Tracks savior and reward state for EntityDamsel.
|
|
* Handles the emerald reward system when players rescue damsels.
|
|
*
|
|
* <p>Anti-abuse features:
|
|
* <ul>
|
|
* <li>No reward if already rewarded (prevents infinite reward exploit)</li>
|
|
* <li>No reward if savior is the one who tied (prevents self-rescue exploit)</li>
|
|
* </ul>
|
|
*
|
|
* <p>This system IS persisted to NBT.
|
|
*/
|
|
public class DamselRewardTracker {
|
|
|
|
private final EntityDamsel damsel;
|
|
|
|
/** Player who rescued this damsel (won't flee from them) */
|
|
@Nullable
|
|
private UUID saviorUUID;
|
|
|
|
/** Player who tied this damsel (for anti-abuse checks) */
|
|
@Nullable
|
|
private UUID tiedByUUID;
|
|
|
|
/** Whether a reward has been given (prevents re-exploitation) */
|
|
private boolean hasGivenReward = false;
|
|
|
|
public DamselRewardTracker(EntityDamsel damsel) {
|
|
this.damsel = damsel;
|
|
}
|
|
|
|
// SAVIOR GETTERS/SETTERS
|
|
|
|
/**
|
|
* Set the player who rescued this damsel.
|
|
* @param player The savior (or null to clear)
|
|
*/
|
|
public void setSavior(@Nullable Player player) {
|
|
this.saviorUUID = player != null ? player.getUUID() : null;
|
|
}
|
|
|
|
/**
|
|
* Check if the given entity is this damsel's savior.
|
|
* @param entity The entity to check
|
|
* @return true if this is the savior
|
|
*/
|
|
public boolean isSavior(Entity entity) {
|
|
if (this.saviorUUID == null || entity == null) {
|
|
return false;
|
|
}
|
|
return this.saviorUUID.equals(entity.getUUID());
|
|
}
|
|
|
|
/**
|
|
* Get the savior's UUID.
|
|
* @return The savior UUID or null if no savior
|
|
*/
|
|
@Nullable
|
|
public UUID getSaviorUUID() {
|
|
return this.saviorUUID;
|
|
}
|
|
|
|
// ANTI-ABUSE TRACKING
|
|
|
|
/**
|
|
* Set the player who tied this damsel (for reward anti-abuse).
|
|
* @param player The player who tied this damsel (or null to clear)
|
|
*/
|
|
public void setTiedBy(@Nullable Player player) {
|
|
this.tiedByUUID = player != null ? player.getUUID() : null;
|
|
}
|
|
|
|
/**
|
|
* Get the UUID of the player who tied this damsel.
|
|
* @return The tiedBy UUID or null
|
|
*/
|
|
@Nullable
|
|
public UUID getTiedByUUID() {
|
|
return this.tiedByUUID;
|
|
}
|
|
|
|
/**
|
|
* Check if this damsel has already given a reward.
|
|
* @return true if reward already given
|
|
*/
|
|
public boolean hasGivenReward() {
|
|
return this.hasGivenReward;
|
|
}
|
|
|
|
/**
|
|
* Reset the reward state (for respawn/new capture cycle).
|
|
*/
|
|
public void reset() {
|
|
this.hasGivenReward = false;
|
|
this.tiedByUUID = null;
|
|
}
|
|
|
|
// REWARD LOGIC
|
|
|
|
/**
|
|
* Reward the player who rescued this damsel.
|
|
* Gives emeralds and marks the player as savior (won't flee from them).
|
|
*
|
|
* @param savior The player who freed this damsel
|
|
*/
|
|
public void rewardSavior(Player savior) {
|
|
// Anti-abuse: Don't reward if already rewarded
|
|
if (this.hasGivenReward) {
|
|
TiedUpMod.LOGGER.debug(
|
|
"[DamselRewardTracker] {} already gave reward, skipping",
|
|
damsel.getName().getString()
|
|
);
|
|
// Still set as savior (won't flee from them)
|
|
this.setSavior(savior);
|
|
return;
|
|
}
|
|
|
|
// Anti-abuse: Don't reward if savior is the one who tied
|
|
if (
|
|
this.tiedByUUID != null && this.tiedByUUID.equals(savior.getUUID())
|
|
) {
|
|
TiedUpMod.LOGGER.debug(
|
|
"[DamselRewardTracker] {} was tied by {}, no reward for self-rescue",
|
|
damsel.getName().getString(),
|
|
savior.getName().getString()
|
|
);
|
|
// Still set as savior (won't flee) but no reward
|
|
this.setSavior(savior);
|
|
this.hasGivenReward = true; // Prevent future reward attempts too
|
|
return;
|
|
}
|
|
|
|
// Mark as rewarded BEFORE giving reward (prevents race conditions)
|
|
this.hasGivenReward = true;
|
|
|
|
// Mark as savior (damsel won't flee from this player anymore)
|
|
this.setSavior(savior);
|
|
|
|
// Create reward (1-3 emeralds)
|
|
int emeraldCount = 1 + damsel.getRandom().nextInt(3);
|
|
ItemStack reward = new ItemStack(Items.EMERALD, emeraldCount);
|
|
|
|
// Drop at damsel's location (player can pick it up)
|
|
ItemEntity itemEntity = new ItemEntity(
|
|
damsel.level(),
|
|
damsel.getX(),
|
|
damsel.getY() + 0.5,
|
|
damsel.getZ(),
|
|
reward
|
|
);
|
|
|
|
// Give slight velocity toward savior
|
|
double dx = savior.getX() - damsel.getX();
|
|
double dz = savior.getZ() - damsel.getZ();
|
|
double dist = Math.sqrt(dx * dx + dz * dz);
|
|
if (dist > 0.1) {
|
|
itemEntity.setDeltaMovement(
|
|
(dx / dist) * 0.2,
|
|
0.2,
|
|
(dz / dist) * 0.2
|
|
);
|
|
}
|
|
damsel.level().addFreshEntity(itemEntity);
|
|
|
|
// Thank the savior via dialogue
|
|
damsel.talkToPlayersInRadius(
|
|
EntityDialogueManager.DialogueCategory.DAMSEL_FREED,
|
|
SettingsAccessor.getDialogueRadius()
|
|
);
|
|
|
|
TiedUpMod.LOGGER.info(
|
|
"[DamselRewardTracker] {} rewarded {} with {} emeralds",
|
|
damsel.getName().getString(),
|
|
savior.getName().getString(),
|
|
emeraldCount
|
|
);
|
|
}
|
|
|
|
// NBT PERSISTENCE
|
|
|
|
/**
|
|
* Save reward tracker state to NBT.
|
|
* @param tag The tag to save to
|
|
*/
|
|
public void save(CompoundTag tag) {
|
|
if (saviorUUID != null) {
|
|
tag.putUUID("SaviorUUID", saviorUUID);
|
|
}
|
|
if (tiedByUUID != null) {
|
|
tag.putUUID("TiedByUUID", tiedByUUID);
|
|
}
|
|
tag.putBoolean("HasGivenReward", hasGivenReward);
|
|
}
|
|
|
|
/**
|
|
* Load reward tracker state from NBT.
|
|
* @param tag The tag to load from
|
|
*/
|
|
public void load(CompoundTag tag) {
|
|
if (tag.contains("SaviorUUID")) {
|
|
this.saviorUUID = tag.getUUID("SaviorUUID");
|
|
}
|
|
if (tag.contains("TiedByUUID")) {
|
|
this.tiedByUUID = tag.getUUID("TiedByUUID");
|
|
}
|
|
this.hasGivenReward = tag.getBoolean("HasGivenReward");
|
|
}
|
|
}
|