mirror of
https://github.com/YouHaveTrouble/PreventStabby.git
synced 2026-05-11 21:06:55 +00:00
096599081b
Refactored exception handling in DatabaseSQLite to use logger instead of printStackTrace() for better error tracking. Streamlined player PvP process in PlayerManager with clear conditions and appropriate responses. Enhancements in other classes were also made to ensure smooth execution and maintain code standards.
256 lines
11 KiB
Java
256 lines
11 KiB
Java
package me.youhavetrouble.preventstabby.data;
|
|
|
|
import me.youhavetrouble.preventstabby.PreventStabby;
|
|
import me.youhavetrouble.preventstabby.api.event.PlayerEnterCombatEvent;
|
|
import me.youhavetrouble.preventstabby.api.event.PlayerLeaveCombatEvent;
|
|
import me.youhavetrouble.preventstabby.util.PluginMessages;
|
|
import me.youhavetrouble.preventstabby.util.PvpState;
|
|
import org.bukkit.Bukkit;
|
|
import org.bukkit.entity.Entity;
|
|
import org.bukkit.entity.LivingEntity;
|
|
import org.bukkit.entity.Player;
|
|
import org.bukkit.entity.Tameable;
|
|
import org.jetbrains.annotations.NotNull;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
import java.util.UUID;
|
|
import java.util.concurrent.CompletableFuture;
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
public class PlayerManager {
|
|
|
|
private final PreventStabby plugin;
|
|
private final ConcurrentHashMap<UUID, PlayerData> playerList = new ConcurrentHashMap<>();
|
|
private PvpState pvpForcedState = PvpState.NONE;
|
|
|
|
public PlayerManager(PreventStabby plugin) {
|
|
this.plugin = plugin;
|
|
Bukkit.getAsyncScheduler().runAtFixedRate(plugin, (task) -> {
|
|
// Check for entries that should be invalidated
|
|
playerList.values().removeIf(PlayerData::isCacheExpired);
|
|
}, 250, 250, TimeUnit.MILLISECONDS);
|
|
|
|
Bukkit.getScheduler().runTaskTimer(plugin, (task -> {
|
|
List<LivingEntity> entities = new ArrayList<>();
|
|
Bukkit.getWorlds().forEach((world -> entities.addAll(world.getLivingEntities())));
|
|
Bukkit.getAsyncScheduler().runNow(plugin, (asyncTask) -> entities.forEach(livingEntity -> {
|
|
if (!(livingEntity instanceof Tameable tameable)) return;
|
|
UUID ownerId = tameable.getOwnerUniqueId();
|
|
if (ownerId == null) return;
|
|
getPlayerData(ownerId);
|
|
}));
|
|
}), 5, 20 * 15);
|
|
|
|
Bukkit.getGlobalRegionScheduler().runAtFixedRate(plugin, (task) -> {
|
|
for (PlayerData playerData : playerList.values()) {
|
|
if (playerData == null) continue;
|
|
Player player = Bukkit.getPlayer(playerData.getPlayerUuid());
|
|
if (player == null || !player.isOnline()) continue;
|
|
playerData.refreshCacheTime(); // Refresh cache timer if player is online
|
|
// leaving combat logic
|
|
if (playerData.getLastCombatCheckState() && !playerData.isInCombat()) {
|
|
PlayerLeaveCombatEvent leaveCombatEvent = null;
|
|
if (PlayerLeaveCombatEvent.getHandlerList().getRegisteredListeners().length > 0) {
|
|
leaveCombatEvent = new PlayerLeaveCombatEvent(player);
|
|
Bukkit.getPluginManager().callEvent(leaveCombatEvent);
|
|
}
|
|
if (leaveCombatEvent != null && leaveCombatEvent.isCancelled()) {
|
|
playerData.markInCombat();
|
|
playerData.setLastCombatCheckState(playerData.isInCombat());
|
|
continue;
|
|
}
|
|
PluginMessages.sendActionBar(player, plugin.getConfigCache().leaving_combat);
|
|
playerData.setLastCombatCheckState(playerData.isInCombat());
|
|
continue;
|
|
}
|
|
// entering combat logic
|
|
if (!playerData.getLastCombatCheckState() && playerData.isInCombat()) {
|
|
PlayerEnterCombatEvent enterCombatEvent = null;
|
|
if (PlayerEnterCombatEvent.getHandlerList().getRegisteredListeners().length > 0) {
|
|
enterCombatEvent = new PlayerEnterCombatEvent(player);
|
|
Bukkit.getPluginManager().callEvent(enterCombatEvent);
|
|
}
|
|
if (enterCombatEvent != null && enterCombatEvent.isCancelled()) {
|
|
playerData.markNotInCombat();
|
|
playerData.setLastCombatCheckState(playerData.isInCombat());
|
|
continue;
|
|
}
|
|
PluginMessages.sendActionBar(player, plugin.getConfigCache().entering_combat);
|
|
playerData.setLastCombatCheckState(playerData.isInCombat());
|
|
continue;
|
|
}
|
|
}
|
|
}, 1, 1);
|
|
}
|
|
|
|
/**
|
|
* Gets player's PlayerData object. Returns null when player with provided UUID doesn't exist.
|
|
*
|
|
* @param uuid Player's UUID.
|
|
* @return Player's PlayerData object or null if player doesn't exist.
|
|
*/
|
|
public PlayerData getPlayer(UUID uuid) {
|
|
return playerList.get(uuid);
|
|
}
|
|
|
|
protected void addPlayer(UUID uuid, PlayerData data) {
|
|
playerList.put(uuid, data);
|
|
}
|
|
|
|
public void handleDamageCheck(@NotNull DamageCheckResult damageCheckResult) {
|
|
if (damageCheckResult.attackerId() == null) return;
|
|
if (damageCheckResult.victimId() == null) return;
|
|
PluginMessages.sendOutMessages(damageCheckResult);
|
|
PlayerData attacker = getPlayer(damageCheckResult.attackerId());
|
|
PlayerData victim = getPlayer(damageCheckResult.victimId());
|
|
if (attacker == null || victim == null) return;
|
|
if (!damageCheckResult.ableToDamage()) return;
|
|
attacker.markInCombat();
|
|
if (!damageCheckResult.shouldVictimBePutInCombat()) return;
|
|
victim.markInCombat();
|
|
}
|
|
|
|
|
|
/**
|
|
* Determines whether the given attacker can damage the victim.
|
|
*
|
|
* @param attacker The attacking entity.
|
|
* @param victim The victim entity.
|
|
* @return A {@link DamageCheckResult} object containing the result of the damage check.
|
|
*/
|
|
public DamageCheckResult canDamage(@NotNull Entity attacker, @NotNull Entity victim) {
|
|
Target attackerData = Target.getTarget(attacker);
|
|
Target victimData = Target.getTarget(victim);
|
|
if (attackerData == null || victimData == null) return DamageCheckResult.positive();
|
|
return canDamage(attackerData.playerUuid, victimData.playerUuid, victimData.classifier);
|
|
}
|
|
|
|
public DamageCheckResult canDamage(UUID attackerId, UUID victimId, Target.EntityClassifier victimClassifier) {
|
|
|
|
if (attackerId == null || victimId == null) return DamageCheckResult.positive();
|
|
|
|
PlayerData attackerPlayerData = getPlayer(attackerId);
|
|
PlayerData victimPlayerData = getPlayer(victimId);
|
|
|
|
if (attackerPlayerData == null || victimPlayerData == null) {
|
|
return DamageCheckResult.positive();
|
|
}
|
|
|
|
if (attackerPlayerData.getPlayerUuid().equals(victimPlayerData.getPlayerUuid())) {
|
|
return DamageCheckResult.positive(attackerId, victimId, false);
|
|
}
|
|
|
|
if (attackerPlayerData.isProtected()) {
|
|
String message = switch (victimClassifier) {
|
|
case PLAYER -> plugin.getConfigCache().cannot_attack_teleport_or_spawn_protection_attacker;
|
|
case PET -> plugin.getConfigCache().cannot_attack_pets_teleport_or_spawn_protection_attacker;
|
|
case MOUNT -> plugin.getConfigCache().cannot_attack_mounts_teleport_or_spawn_protection_attacker;
|
|
default -> null;
|
|
};
|
|
return new DamageCheckResult(false, attackerId, victimId, message, false);
|
|
}
|
|
if (victimPlayerData.isProtected()) {
|
|
String message = null;
|
|
if (victimClassifier == Target.EntityClassifier.PLAYER) {
|
|
message = plugin.getConfigCache().cannot_attack_teleport_or_spawn_protection_victim;
|
|
}
|
|
return new DamageCheckResult(false, attackerId, victimId, message, false);
|
|
}
|
|
|
|
switch (getForcedPvpState()) {
|
|
case DISABLED -> {
|
|
return new DamageCheckResult(false, attackerId, victimId, plugin.getConfigCache().cannot_attack_forced_pvp_off, false);
|
|
}
|
|
case ENABLED -> {
|
|
return DamageCheckResult.positive(attackerId, victimId, victimClassifier.equals(Target.EntityClassifier.PLAYER));
|
|
}
|
|
}
|
|
|
|
if (!attackerPlayerData.isPvpEnabled()) {
|
|
String message = switch (victimClassifier) {
|
|
case PLAYER -> plugin.getConfigCache().cannot_attack_attacker;
|
|
case PET -> plugin.getConfigCache().cannot_attack_pets_victim;
|
|
case MOUNT -> plugin.getConfigCache().cannot_attack_mounts_attacker;
|
|
default -> null;
|
|
};
|
|
return new DamageCheckResult(false, attackerId, victimId, message, victimClassifier.equals(Target.EntityClassifier.PLAYER));
|
|
}
|
|
|
|
if (!victimPlayerData.isPvpEnabled()) {
|
|
String message = switch (victimClassifier) {
|
|
case PLAYER -> plugin.getConfigCache().cannot_attack_victim;
|
|
case PET -> plugin.getConfigCache().cannot_attack_pets_attacker;
|
|
case MOUNT -> plugin.getConfigCache().cannot_attack_mounts_victim;
|
|
default -> null;
|
|
};
|
|
return new DamageCheckResult(false, attackerId, victimId, message, victimClassifier.equals(Target.EntityClassifier.PLAYER));
|
|
}
|
|
|
|
return new DamageCheckResult(
|
|
true,
|
|
attackerId,
|
|
victimId,
|
|
null,
|
|
victimClassifier.equals(Target.EntityClassifier.PLAYER)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Returns current forced pvp state.
|
|
* @return Current forced pvp state.
|
|
*/
|
|
public PvpState getForcedPvpState() {
|
|
return pvpForcedState;
|
|
}
|
|
|
|
/**
|
|
* Sets current forced pvp state.
|
|
* @param forcedPvpState New forced pvp state.
|
|
*/
|
|
public void setForcedPvpState(PvpState forcedPvpState) {
|
|
this.pvpForcedState = forcedPvpState;
|
|
}
|
|
|
|
/**
|
|
* Retrieves the PlayerData object for the player with the provided UUID. Returns new default if there isn't data.
|
|
*
|
|
* @param uuid The UUID of the player.
|
|
* @return The PlayerData object associated with the player.
|
|
*/
|
|
public CompletableFuture<PlayerData> getPlayerData(UUID uuid) {
|
|
// Try to get data from cache and refresh it
|
|
PlayerData data = getPlayer(uuid);
|
|
if (data != null) {
|
|
data.refreshCacheTime();
|
|
return CompletableFuture.completedFuture(data);
|
|
}
|
|
// Get data from database or provide default
|
|
return CompletableFuture.supplyAsync(() -> {
|
|
PlayerData playerData = plugin.getSqLite().getPlayerInfo(uuid);
|
|
if (playerData == null) {
|
|
playerData = new PlayerData(uuid, false);
|
|
}
|
|
plugin.getPlayerManager().addPlayer(uuid, playerData);
|
|
return playerData;
|
|
});
|
|
}
|
|
|
|
public void setPlayerPvpState(UUID uuid, boolean state) {
|
|
// If player is in cache update that
|
|
if (getPlayer(uuid) != null) {
|
|
getPlayer(uuid).setPvpEnabled(state);
|
|
}
|
|
// Update the database aswell
|
|
plugin.getSqLite().updatePlayerInfo(uuid, new PlayerData(uuid, state));
|
|
}
|
|
|
|
public CompletableFuture<Boolean> togglePlayerPvpState(UUID uuid) {
|
|
return getPlayerData(uuid).thenApply(playerData -> {
|
|
playerData.setPvpEnabled(!playerData.isPvpEnabled());
|
|
return playerData.isPvpEnabled();
|
|
});
|
|
}
|
|
}
|