package com.nisovin.magicspells;
import java.io.File;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerChangedWorldEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import com.nisovin.magicspells.Spell.PostCastAction;
import com.nisovin.magicspells.Spell.SpellCastState;
import com.nisovin.magicspells.events.SpellCastedEvent;
import com.nisovin.magicspells.events.SpellLearnEvent;
import com.nisovin.magicspells.events.SpellLearnEvent.LearnSource;
import com.nisovin.magicspells.util.IntMap;
import com.nisovin.magicspells.util.MagicConfig;
import com.nisovin.magicspells.util.Util;
public class MagicXpHandler implements Listener {
MagicSpells plugin;
Map<String, String> schools = new HashMap<String, String>();
Map<String, IntMap<String>> xp = new HashMap<String, IntMap<String>>();
Set<String> dirty = new HashSet<String>();
Map<String, String> currentWorld = new HashMap<String, String>();
Map<String, List<Spell>> spellSchoolRequirements = new HashMap<String, List<Spell>>();
boolean autoLearn;
String strXpHeader;
String strNoXp;
public MagicXpHandler(MagicSpells plugin, MagicConfig config) {
this.plugin = plugin;
Set<String> keys = config.getKeys("general.magic-schools");
if (keys != null) {
for (String school : keys) {
String name = config.getString("general.magic-schools." + school, null);
if (name != null) {
schools.put(school.toLowerCase(), name);
}
}
}
autoLearn = config.getBoolean("general.magic-xp-auto-learn", false);
strXpHeader = config.getString("general.str-xp-header", null);
strNoXp = config.getString("general.str-no-xp", null);
for (Spell spell : MagicSpells.spells()) {
Map<String, Integer> xpRequired = spell.getXpRequired();
if (xpRequired != null) {
for (String school : xpRequired.keySet()) {
List<Spell> list = spellSchoolRequirements.get(school.toLowerCase());
if (list == null) {
list = new ArrayList<Spell>();
spellSchoolRequirements.put(school.toLowerCase(), list);
}
list.add(spell);
}
}
}
for (Player player : Bukkit.getOnlinePlayers()) {
load(player);
}
MagicSpells.scheduleRepeatingTask(new Runnable() {
public void run() {
saveAll();
}
}, 60 * 20, 60 * 20);
MagicSpells.registerEvents(this);
}
public void showXpInfo(Player player) {
MagicSpells.sendMessage(player, strXpHeader);
IntMap<String> playerXp = xp.get(player.getName());
if (playerXp != null) {
if (playerXp.size() > 0) {
for (String school : playerXp.keySet()) {
String schoolName = schools.get(school);
if (schoolName != null) {
String amt = NumberFormat.getInstance().format(playerXp.get(school));
MagicSpells.sendMessage(player, schoolName + ": " + amt);
}
}
} else {
MagicSpells.sendMessage(player, strNoXp);
}
} else {
MagicSpells.sendMessage(player, strNoXp);
}
}
public int getXp(Player player, String school) {
IntMap<String> playerXp = xp.get(player.getName());
if (playerXp != null) {
return playerXp.get(school.toLowerCase());
}
return 0;
}
@EventHandler
public void onCast(SpellCastedEvent event) {
if (event.getPostCastAction() == PostCastAction.ALREADY_HANDLED) return;
if (event.getSpellCastState() != SpellCastState.NORMAL) return;
final Map<String, Integer> xpGranted = event.getSpell().getXpGranted();
if (xpGranted == null) return;
// get player xp
IntMap<String> playerXp = xp.get(event.getCaster().getName());
if (playerXp == null) {
playerXp = new IntMap<String>();
xp.put(event.getCaster().getName(), playerXp);
}
// grant xp
for (String school : xpGranted.keySet()) {
playerXp.increment(school.toLowerCase(), xpGranted.get(school));
}
dirty.add(event.getCaster().getName());
if (autoLearn) {
final Player player = event.getCaster();
final Spell castedSpell = event.getSpell();
MagicSpells.scheduleDelayedTask(new Runnable() {
public void run() {
// get spells to check if learned
Set<Spell> toCheck = new HashSet<Spell>();
for (String school : xpGranted.keySet()) {
List<Spell> list = spellSchoolRequirements.get(school.toLowerCase());
if (list != null) {
for (Spell spell : list) {
toCheck.add(spell);
}
}
}
// check for new learned spells
if (toCheck.size() > 0) {
boolean learned = false;
Spellbook spellbook = MagicSpells.getSpellbook(player);
for (Spell spell : toCheck) {
if (!spellbook.hasSpell(spell, false) && spellbook.canLearn(spell)) {
SpellLearnEvent evt = new SpellLearnEvent(spell, player, LearnSource.MAGIC_XP, castedSpell);
Bukkit.getPluginManager().callEvent(evt);
if (!evt.isCancelled()) {
spellbook.addSpell(spell);
MagicSpells.sendMessage(player, spell.getStrXpLearned());
learned = true;
}
}
}
if (learned) {
spellbook.save();
}
}
}
}, 1);
}
}
@EventHandler
public void onJoin(PlayerJoinEvent event) {
currentWorld.put(event.getPlayer().getName(), event.getPlayer().getWorld().getName());
dirty.remove(event.getPlayer().getName());
load(event.getPlayer());
}
@EventHandler
public void onChangeWorld(PlayerChangedWorldEvent event) {
if (plugin.separatePlayerSpellsPerWorld) {
Player player = event.getPlayer();
if (dirty.contains(player.getName())) {
save(player);
}
currentWorld.put(player.getName(), player.getWorld().getName());
load(player);
dirty.remove(player.getName());
}
}
@EventHandler
public void onQuit(PlayerQuitEvent event) {
Player player = event.getPlayer();
if (dirty.contains(player.getName())) {
save(player);
}
xp.remove(player.getName());
dirty.remove(player.getName());
currentWorld.remove(player.getName());
}
public void load(Player player) {
File folder = new File(plugin.getDataFolder(), "xp");
if (!folder.exists()) folder.mkdirs();
if (plugin.separatePlayerSpellsPerWorld) {
String world = currentWorld.get(player.getName());
if (world == null) world = player.getWorld().getName();
folder = new File(folder, world);
if (!folder.exists()) folder.mkdirs();
}
String uuid = Util.getUniqueId(player);
File file = new File(folder, uuid + ".txt");
if (!file.exists()) {
File file2 = new File(folder, player.getName().toLowerCase());
if (file2.exists()) {
file2.renameTo(file);
}
}
if (file.exists()) {
YamlConfiguration conf = new YamlConfiguration();
try {
conf.load(file);
IntMap<String> playerXp = new IntMap<String>();
for (String school : conf.getKeys(false)) {
playerXp.put(school.toLowerCase(), conf.getInt(school, 0));
}
xp.put(player.getName(), playerXp);
} catch (Exception e) {
MagicSpells.error("Error while loading player XP for player " + player.getName());
MagicSpells.handleException(e);
}
}
}
public void saveAll() {
for (String playerName : dirty) {
Player player = Bukkit.getPlayerExact(playerName);
if (player != null) {
save(player);
}
}
dirty.clear();
}
public void save(Player player) {
String world = currentWorld.get(player.getName());
if (world == null) world = player.getWorld().getName();
File folder = new File(plugin.getDataFolder(), "xp");
if (!folder.exists()) folder.mkdirs();
if (plugin.separatePlayerSpellsPerWorld) {
if (world == null) return;
folder = new File(folder, world);
if (!folder.exists()) folder.mkdirs();
}
File file = new File(folder, Util.getUniqueId(player) + ".txt");
if (file.exists()) file.delete();
YamlConfiguration conf = new YamlConfiguration();
IntMap<String> playerXp = xp.get(player.getName());
if (playerXp != null) {
for (String school : playerXp.keySet()) {
conf.set(school.toLowerCase(), playerXp.get(school));
}
}
try {
conf.save(file);
} catch (Exception e) {
MagicSpells.error("Error while saving player XP for player " + player);
MagicSpells.handleException(e);
}
}
}