mirror of
https://github.com/YouHaveTrouble/PreventStabby.git
synced 2026-05-12 05:16:55 +00:00
47ade3e0c0
Reconfiguration of the PreventStabby plugin involved removal of PlayerDamageListener and the introduction of two new listeners: EnvironmentalListener and PvpListener. This restructuring allows more efficient management of entity damage and environmental interactions. EnvironmentalListener specifically caters for dangerous situations such as bucket spills and block fires. PvpListener effectively manages PvP related activities including damages, splash potion effects, cloud area effects, and fishing events ensuring a more streamlined control and response for better PvP gameplay.
257 lines
11 KiB
Java
257 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 (plugin.getConfigCache().combat_time <= 0) return; // disable combat entering when combat time is <0
|
|
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();
|
|
});
|
|
}
|
|
}
|