package jp.jias.bukkit.Goyoukiki; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.nio.channels.FileChannel; import java.util.Collection; import java.util.logging.Logger; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.potion.PotionEffect; /** * プレイヤーの状態を記憶する * 2014/07/26 */ public class PlayerState{ /** * プレイヤー */ private Player player; /** * 装備品とインベントリの中身 */ private ItemStack[] equipment,inventory; /** * 現在位置、ベッドスポーン位置 */ private Location loc,bed; /** * ポーション効果 */ private Collection potionEffects; /** * HP、最大HP */ private double maxhp,hp; /** * 空腹度、空気残量、延焼時間、経験値 */ private int food,air,fire,exp; /** * ユーザーデータファイルの元のフォルダ、退避先フォルダ */ static private File srcDir=null,reserveDir=null; /** * 退避しておくユーザーデータのファイルの名前 */ private String fileName; /** * ログ出力用 */ static private Logger log; /** * 準備完了したらtrue */ static private boolean ready=false; /** * 現在の状態を保存する * * @param _player * データを退避したいプレイヤー * @throws IOException * プレイヤーデータを退避フォルダに退避できなかった場合に発生 */ public PlayerState(Player player) throws IOException{ // 準備は済んでいるか if(!ready){ throw new IOException("[PlayerState] 準備が完了していないので情報を保存できません。"); } // データを取り出して保存しておく this.player=player; loc=player.getLocation(); bed=player.getBedSpawnLocation(); equipment=player.getInventory().getArmorContents(); inventory=player.getInventory().getContents(); potionEffects=player.getActivePotionEffects(); maxhp=player.getMaxHealth(); hp=player.getHealth(); food=player.getFoodLevel(); air=player.getRemainingAir(); fire=player.getFireTicks(); exp=player.getTotalExperience(); // 現在のプレイヤーデータをファイルに保存 player.saveData(); // データファイルを退避フォルダにコピー fileName=File.separator + player.getUniqueId() + ".dat"; fileCopy(srcDir.getAbsolutePath() + fileName,reserveDir + fileName); } /** * 保存した情報を書き戻す */ @SuppressWarnings("deprecation") public void update(){ // 状態を初期化する initialize(); // 取り出しておいたデータを適用する player.addPotionEffects(potionEffects); player.teleport(loc); player.setBedSpawnLocation(bed,true); player.getInventory().setArmorContents(equipment); player.getInventory().setContents(inventory); player.setMaxHealth(maxhp); player.setHealth(hp); player.setFoodLevel(food); player.setRemainingAir(air); player.setFireTicks(fire); player.setTotalExperience(exp); // データファイルを削除する if(!new File(reserveDir + fileName).delete()){ Bukkit.broadcastMessage("§Eプレイヤー[§6"+player.getName()+"§E]のデータを復元しましたが、退避したデータファイルを削除できませんでした。"); } // 状態を更新する player.updateInventory(); } /** * プレイヤーの状態を初期化する */ @SuppressWarnings("deprecation") public void initialize(){ // 現在のポーションエフェクトをすべて削除する Collection pes=player.getActivePotionEffects(); for(PotionEffect pe:pes){ player.removePotionEffect(pe.getType()); } // その他 player.getInventory().clear(); player.setHealth(player.getMaxHealth()); player.setFoodLevel(10); player.setRemainingAir(player.getRemainingAir()); player.setFireTicks(0); player.setTotalExperience(0); // 状態を更新する player.updateInventory(); } /** * データを退避する準備をする */ static public void init(JavaPlugin plugin){ // 既に準備されていたら何もしない if(ready){ return; } // ログ出力の準備 log=plugin.getLogger(); // 退避元・退避先のパスを作る srcDir=new File(Bukkit.getWorlds().get(0).getWorldFolder() .getAbsolutePath() + File.separator + "playerdata"); reserveDir=new File(plugin.getDataFolder() + File.separator + "reserve"); // フォルダはあるか if(reserveDir.exists() && reserveDir.isDirectory()){ // フォルダの中にファイルがあったら警告を出す File[] files=reserveDir.listFiles(); if(files.length != 0){ log.warning("[PlayerState] 退避したデータファイルのうち、復元できていないファイルが"+files.length+"つあります。"); return; } }else{ // フォルダがなければ作る if(!reserveDir.mkdirs()){ log.warning("[PlayerState] 退避データ用のフォルダが作れません。"); return; } } // 準備完了 ready=true; } /** * ファイルをコピーする * * @param src * コピー元のファイルパス * @param dest * コピー先のファイルパス * @throws IOException */ private void fileCopy(String src,String dest) throws IOException{ FileChannel srcChannel=null,destChannel=null; try{ // ファイルを開く srcChannel=new FileInputStream(src).getChannel(); destChannel=new FileOutputStream(dest).getChannel(); // 内容を移動 srcChannel.transferTo(0,srcChannel.size(),destChannel); }catch(IOException e){ log.warning("[PlayerState] データを退避することに失敗しました。"); throw e; }finally{ // ファイルを閉じる srcChannel.close(); destChannel.close(); } } }