package com.nisovin.magicspells.variables;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.scoreboard.DisplaySlot;
import org.bukkit.scoreboard.Objective;
import com.nisovin.magicspells.MagicSpells;
import com.nisovin.magicspells.Spell.PostCastAction;
import com.nisovin.magicspells.Spell.SpellCastState;
import com.nisovin.magicspells.events.SpellCastEvent;
import com.nisovin.magicspells.events.SpellCastedEvent;
import com.nisovin.magicspells.events.SpellTargetEvent;
import com.nisovin.magicspells.util.Util;
public class VariableManager implements Listener {
Map<String, Variable> variables = new HashMap<String, Variable>();
Set<String> dirtyPlayerVars = new HashSet<String>();
boolean dirtyGlobalVars = false;
File folder;
public VariableManager(MagicSpells plugin, ConfigurationSection section) {
if (section != null) {
for (String var : section.getKeys(false)) {
String type = section.getString(var + ".type", "global");
double def = section.getDouble(var + ".default", 0);
double min = section.getDouble(var + ".min", 0);
double max = section.getDouble(var + ".max", Double.MAX_VALUE);
boolean perm = section.getBoolean(var + ".permanent", true);
Variable variable;
if (type.equalsIgnoreCase("player")) {
variable = new PlayerVariable();
} else {
variable = new GlobalVariable();
}
String scoreName = section.getString(var + ".scoreboard-title", null);
String scorePos = section.getString(var + ".scoreboard-position", null);
Objective objective = null;
if (scoreName != null && scorePos != null) {
String objName = "MSV_" + var;
if (objName.length() > 16) objName = objName.substring(0, 16);
objective = Bukkit.getScoreboardManager().getMainScoreboard().getObjective(objName);
if (objective != null) {
objective.unregister();
objective = null;
}
objective = Bukkit.getScoreboardManager().getMainScoreboard().registerNewObjective(objName, objName);
objective.setDisplayName(ChatColor.translateAlternateColorCodes('&', scoreName));
if (scorePos.equalsIgnoreCase("nameplate")) {
objective.setDisplaySlot(DisplaySlot.BELOW_NAME);
} else if (scorePos.equalsIgnoreCase("playerlist")) {
objective.setDisplaySlot(DisplaySlot.PLAYER_LIST);
} else {
objective.setDisplaySlot(DisplaySlot.SIDEBAR);
}
}
String bossBar = section.getString(var + ".boss-bar", null);
boolean expBar = section.getBoolean(var + ".exp-bar", false);
variable.init(def, min, max, perm, objective, bossBar, expBar);
variables.put(var, variable);
MagicSpells.debug(2, "Loaded variable " + var);
}
MagicSpells.debug(1, variables.size() + " variables loaded!");
}
if (variables.size() > 0) {
MagicSpells.registerEvents(this);
}
// load vars
folder = new File(plugin.getDataFolder(), "vars");
if (!folder.exists()) {
folder.mkdir();
}
loadGlobalVars();
for (Player player : Bukkit.getOnlinePlayers()) {
loadPlayerVars(player.getName(), Util.getUniqueId(player));
loadBossBar(player);
loadExpBar(player);
}
// start save task
MagicSpells.scheduleRepeatingTask(new Runnable() {
public void run() {
if (dirtyGlobalVars) {
saveGlobalVars();
}
if (dirtyPlayerVars.size() > 0) {
saveAllPlayerVars();
}
}
}, 60 * 20, 60 * 20);
}
public int count() {
return variables.size();
}
public void modify(String variable, Player player, double amount) {
modify(variable, player.getName(), amount);
}
public void modify(String variable, String player, double amount) {
Variable var = variables.get(variable);
if (var != null) {
boolean changed = var.modify(player, amount);
if (changed) {
updateBossBar(var, player);
updateExpBar(var, player);
if (var.permanent) {
if (var instanceof PlayerVariable) {
dirtyPlayerVars.add(player);
} else if (var instanceof GlobalVariable) {
dirtyGlobalVars = true;
}
}
}
}
}
public void set(String variable, Player player, double amount) {
set(variable, player.getName(), amount);
}
public void set(String variable, String player, double amount) {
Variable var = variables.get(variable);
if (var != null) {
var.set(player, amount);
updateBossBar(var, player);
updateExpBar(var, player);
if (var.permanent) {
if (var instanceof PlayerVariable) {
dirtyPlayerVars.add(player);
} else if (var instanceof GlobalVariable) {
dirtyGlobalVars = true;
}
}
}
}
public double getValue(String variable, Player player) {
Variable var = variables.get(variable);
if (var != null) {
return var.getValue(player);
} else {
return 0;
}
}
public void reset(String variable, Player player) {
Variable var = variables.get(variable);
if (var != null) {
var.reset(player);
updateBossBar(var, player != null ? player.getName() : "");
updateExpBar(var, player != null ? player.getName() : "");
if (var.permanent) {
if (var instanceof PlayerVariable) {
dirtyPlayerVars.add(player.getName());
} else if (var instanceof GlobalVariable) {
dirtyGlobalVars = true;
}
}
}
}
private void updateBossBar(Variable var, String player) {
if (var.bossBar != null) {
if (var instanceof GlobalVariable) {
double pct = var.getValue("") / var.maxValue;
for (Player p : Bukkit.getOnlinePlayers()) {
MagicSpells.getBossBarManager().setPlayerBar(p, var.bossBar, pct);
}
} else if (var instanceof PlayerVariable) {
Player p = Bukkit.getPlayerExact(player);
if (p != null) {
MagicSpells.getBossBarManager().setPlayerBar(p, var.bossBar, var.getValue(p) / var.maxValue);
}
}
}
}
private void updateExpBar(Variable var, String player) {
if (var.expBar) {
if (var instanceof GlobalVariable) {
double pct = var.getValue("") / var.maxValue;
for (Player p : Bukkit.getOnlinePlayers()) {
MagicSpells.getVolatileCodeHandler().setExperienceBar(p, (int)var.getValue(""), (float)pct);
}
} else if (var instanceof PlayerVariable) {
Player p = Bukkit.getPlayerExact(player);
if (p != null) {
MagicSpells.getVolatileCodeHandler().setExperienceBar(p, (int)var.getValue(p), (float)(var.getValue(p) / var.maxValue));
}
}
}
}
private void loadGlobalVars() {
File file = new File(folder, "GLOBAL.txt");
if (file.exists()) {
try {
Scanner scanner = new Scanner(file);
while (scanner.hasNext()) {
String line = scanner.nextLine().trim();
if (!line.isEmpty()) {
String[] s = line.split("=");
Variable variable = variables.get(s[0]);
if (variable != null && variable instanceof GlobalVariable && variable.permanent) {
variable.set("", Double.parseDouble(s[1]));
}
}
}
scanner.close();
} catch (Exception e) {
MagicSpells.error("ERROR LOADING GLOBAL VARIABLES");
MagicSpells.handleException(e);
}
}
dirtyGlobalVars = false;
}
private void saveGlobalVars() {
File file = new File(folder, "GLOBAL.txt");
if (file.exists()) file.delete();
List<String> lines = new ArrayList<String>();
for (String variableName : variables.keySet()) {
Variable variable = variables.get(variableName);
if (variable instanceof GlobalVariable && variable.permanent) {
double val = variable.getValue("");
if (val != variable.defaultValue) {
lines.add(variableName + "=" + val);
}
}
}
if (lines.size() > 0) {
BufferedWriter writer = null;
try {
writer = new BufferedWriter(new FileWriter(file, false));
for (String line : lines) {
writer.write(line);
writer.newLine();
}
writer.flush();
} catch (Exception e) {
MagicSpells.error("ERROR SAVING GLOBAL VARIABLES");
MagicSpells.handleException(e);
} finally {
if (writer != null) {
try {
writer.close();
} catch (Exception e) {}
}
}
}
dirtyGlobalVars = false;
}
private void loadPlayerVars(String player, String uniqueId) {
File file = new File(folder, "PLAYER_" + uniqueId + ".txt");
if (!file.exists()) {
File file2 = new File(folder, "PLAYER_" + player + ".txt");
if (file2.exists()) {
file2.renameTo(file);
}
}
if (file.exists()) {
try {
Scanner scanner = new Scanner(file);
while (scanner.hasNext()) {
String line = scanner.nextLine().trim();
if (!line.isEmpty()) {
String[] s = line.split("=");
Variable variable = variables.get(s[0]);
if (variable != null && variable instanceof PlayerVariable && variable.permanent) {
variable.set(player, Double.parseDouble(s[1]));
}
}
}
scanner.close();
} catch (Exception e) {
MagicSpells.error("ERROR LOADING PLAYER VARIABLES FOR " + player);
MagicSpells.handleException(e);
}
}
dirtyPlayerVars.remove(player);
}
private void savePlayerVars(String player, String uniqueId) {
File file = new File(folder, "PLAYER_" + player + ".txt");
if (file.exists()) file.delete();
file = new File(folder, "PLAYER_" + uniqueId + ".txt");
if (file.exists()) file.delete();
List<String> lines = new ArrayList<String>();
for (String variableName : variables.keySet()) {
Variable variable = variables.get(variableName);
if (variable instanceof PlayerVariable && variable.permanent) {
double val = variable.getValue(player);
if (val != variable.defaultValue) {
lines.add(variableName + "=" + val);
}
}
}
if (lines.size() > 0) {
BufferedWriter writer = null;
try {
writer = new BufferedWriter(new FileWriter(file, false));
for (String line : lines) {
writer.write(line);
writer.newLine();
}
writer.flush();
} catch (Exception e) {
MagicSpells.error("ERROR SAVING PLAYER VARIABLES FOR " + player);
MagicSpells.handleException(e);
} finally {
if (writer != null) {
try {
writer.close();
} catch (Exception e) {}
}
}
}
dirtyPlayerVars.remove(player);
}
private void saveAllPlayerVars() {
for (String playerName : new HashSet<String>(dirtyPlayerVars)) {
String uid = Util.getUniqueId(playerName);
if (uid != null) {
savePlayerVars(playerName, uid);
}
}
}
private void loadBossBar(Player player) {
for (Variable var : variables.values()) {
if (var.bossBar != null) {
MagicSpells.getBossBarManager().setPlayerBar(player, var.bossBar, var.getValue(player) / var.maxValue);
break;
}
}
}
private void loadExpBar(Player player) {
for (Variable var : variables.values()) {
if (var.expBar) {
MagicSpells.getVolatileCodeHandler().setExperienceBar(player, (int)var.getValue(player), (float)(var.getValue(player) / var.maxValue));
break;
}
}
}
public void disable() {
if (dirtyGlobalVars) {
saveGlobalVars();
}
if (dirtyPlayerVars.size() > 0) {
saveAllPlayerVars();
}
variables.clear();
}
@EventHandler
public void onJoin(PlayerJoinEvent event) {
final Player player = event.getPlayer();
loadPlayerVars(player.getName(), Util.getUniqueId(player));
loadBossBar(player);
MagicSpells.scheduleDelayedTask(new Runnable() {
public void run() {
loadExpBar(player);
}
}, 10);
}
@EventHandler
public void onQuit(PlayerQuitEvent event) {
if (dirtyPlayerVars.contains(event.getPlayer().getName())) {
savePlayerVars(event.getPlayer().getName(), Util.getUniqueId(event.getPlayer()));
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onSpellCast(SpellCastEvent event) {
if (event.getSpellCastState() == SpellCastState.NORMAL) {
Map<String, Double> varMods = event.getSpell().getVariableModsCast();
if (varMods != null && varMods.size() > 0) {
Player player = event.getCaster();
for (String var : varMods.keySet()) {
double val = varMods.get(var);
if (val == 0) {
reset(var, player);
} else {
modify(var, player, val);
}
MagicSpells.debug(3, "Variable '" + var + "' for player '" + player.getName() + "' modified by " + val + " as a result of spell cast '" + event.getSpell().getName() + "'");
}
}
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onSpellCasted(SpellCastedEvent event) {
if (event.getSpellCastState() == SpellCastState.NORMAL && event.getPostCastAction() != PostCastAction.ALREADY_HANDLED) {
Map<String, Double> varMods = event.getSpell().getVariableModsCasted();
if (varMods != null && varMods.size() > 0) {
Player player = event.getCaster();
for (String var : varMods.keySet()) {
double val = varMods.get(var);
if (val == 0) {
reset(var, player);
} else {
modify(var, player, val);
}
MagicSpells.debug(3, "Variable '" + var + "' for player '" + player.getName() + "' modified by " + val + " as a result of spell casted '" + event.getSpell().getName() + "'");
}
}
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onSpellTarget(SpellTargetEvent event) {
Map<String, Double> varMods = event.getSpell().getVariableModsTarget();
if (varMods != null && varMods.size() > 0) {
Player player = event.getCaster();
if (player != null) {
for (String var : varMods.keySet()) {
double val = varMods.get(var);
if (val == 0) {
reset(var, player);
} else {
modify(var, player, val);
}
MagicSpells.debug(3, "Variable '" + var + "' for player '" + player.getName() + "' modified by " + val + " as a result of spell target from '" + event.getSpell().getName() + "'");
}
}
}
}
}