/** * */ package logbook.internal; import java.io.IOException; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.TreeMap; import javax.json.JsonArray; import javax.json.JsonNumber; import javax.json.JsonObject; import javax.json.JsonValue; import logbook.constants.AppConstants; import logbook.dto.ItemInfoDto; import logbook.dto.JsonData; import logbook.dto.ShipInfoDto; import logbook.dto.UseItemDto; import logbook.gui.ApplicationMain; import logbook.util.BeanUtils; import org.apache.commons.lang3.ArrayUtils; /** * @author Nekopanda * */ public class MasterData { /** ロガー */ private static final LoggerHolder LOG = new LoggerHolder(MasterData.class); private static class Holder { public static MasterData instance = null; } /** 変更があったか */ private static boolean modified = false; /** * * 設定ファイルに書き込みます */ public static void store() throws IOException { if (Holder.instance == null) { return; } // 最終更新日時がファイル更新日時より新しい時だけ書き込む if (modified) { ApplicationMain.sysPrint("マスターファイル更新"); BeanUtils.writeObject(AppConstants.MASTER_DATA_CONFIG, Holder.instance); modified = false; } } private static void load() { try { MasterData masterData = BeanUtils.readObject(AppConstants.MASTER_DATA_CONFIG, MasterData.class); if ((masterData != null) && (masterData.getVersion() >= 2)) { Holder.instance = masterData; Holder.instance.start2.loadCompleted(); } } catch (Exception e) { LOG.get().warn("艦娘のIDと名前の紐付けを設定ファイルから読み込みますに失敗しました", e); } if (Holder.instance == null) { Holder.instance = new MasterData(); } } public static final boolean INIT_COMPLETE; static { load(); INIT_COMPLETE = true; } /** バージョン * 0: 初期 * 1: 1.6.3以降 * 2: 1.8.7以降 */ private int version = 2; private Start2Dto start2 = new Start2Dto(); /** マップクリア情報 -1: 非表示 or 未更新 0: クリアしていない 1: クリア済み */ private Map<Integer, Integer> mapState = new TreeMap<Integer, Integer>(); /** 遠征クリア情報 -1: 非表示 or 未更新 0: NEW 1: 無印 2: 達成 */ private Map<Integer, Integer> missionState = new TreeMap<Integer, Integer>(); /** 最終更新日時 */ private Date lastUpdateTime = new Date(0); public MasterData() { } /** START2のマスターデータで更新 */ public static void updateMaster(JsonObject data) { Holder.instance.doMater(data); } /** 出撃マップを更新 */ public static void updateMapInfo(JsonArray json_mapinfo) { Holder.instance.doMapInfo(json_mapinfo); } /** 遠征データを更新 */ public static void updateMission(JsonArray json_mission) { Holder.instance.doMission(json_mission); } public static MasterData get() { return Holder.instance; } public static Start2Dto getMaster() { return Holder.instance.getStart2(); } private void doMater(JsonObject data) { this.start2 = new Start2Dto(data); this.lastUpdateTime = new Date(); modified = true; } /** 艦種情報を取得 */ public static ShipTypeDto getShipType(int stype) { return Holder.instance.start2.getShipType(stype); } /** (装備でない)アイテム情報を取得 */ public static UseItemInfoDto getUseItem(int id) { return Holder.instance.start2.getUseItem(id); } /** マップ情報を取得 */ public static MapInfoDto getMapInfo(int area, int no) { return Holder.instance.start2.getMapInfo(area, no); } private void doMapInfo(JsonArray json_mapinfo) { if (json_mapinfo != null) { Map<Integer, Integer> newState = new HashMap<Integer, Integer>(); for (JsonValue elem : json_mapinfo) { JsonObject obj = (JsonObject) elem; newState.put(obj.getInt("api_id"), obj.getInt("api_cleared")); } if (newState.equals(this.mapState) == false) { this.mapState = newState; this.lastUpdateTime = new Date(); modified = true; } } } private void doMission(JsonArray json_mission) { if (json_mission != null) { Map<Integer, Integer> newState = new HashMap<Integer, Integer>(); for (JsonValue elem : json_mission) { JsonObject obj = (JsonObject) elem; newState.put(obj.getInt("api_mission_id"), obj.getInt("api_state")); } if (newState.equals(this.missionState) == false) { this.missionState = newState; this.lastUpdateTime = new Date(); modified = true; } } } /** * @return mapState */ public Map<Integer, Integer> getMapState() { return this.mapState; } /** * @param mapState セットする mapState */ public void setMapState(Map<Integer, Integer> mapState) { this.mapState = mapState; } /** * @return missionState */ public Map<Integer, Integer> getMissionState() { return this.missionState; } /** * @param missionState セットする missionState */ public void setMissionState(Map<Integer, Integer> missionState) { this.missionState = missionState; } /** * @return masterUpdateTime */ public Date getMasterUpdateTime() { return this.start2.getTime(); } /** * @return lastUpdateTime */ public Date getLastUpdateTime() { return this.lastUpdateTime; } /** * @param lastUpdateTime セットする lastUpdateTime */ public void setLastUpdateTime(Date lastUpdateTime) { this.lastUpdateTime = lastUpdateTime; } /** * @return version */ public int getVersion() { return this.version; } /** * @param version セットする version */ public void setVersion(int version) { this.version = version; } /** * @return start2 */ public Start2Dto getStart2() { return this.start2; } /** * @param start2 セットする start2 */ public void setStart2(Start2Dto start2) { this.start2 = start2; } /** * api_start2 * @author Nekopanda */ public class Start2Dto extends JsonData { /** 最終更新日時 */ private Date time = new Date(0); /** 艦娘 */ private final Map<Integer, ShipInfoDto> ships = new TreeMap<>(); /** アイテム */ private final Map<Integer, ItemInfoDto> items = new TreeMap<>(); /** 1-, 2-, ... , イベント海域 */ private final ArrayList<MapAreaDto> maparea = new ArrayList<MapAreaDto>(); /** 1-1, 1-2, ... , 2-1, 2-2, ... */ private final Map<Integer, MapInfoDto> mapinfo = new TreeMap<Integer, MapInfoDto>(); /** 全ての遠征 */ private final Map<Integer, MissionDto> mission = new TreeMap<Integer, MissionDto>(); /** 艦種 */ private final List<ShipTypeDto> stype = new ArrayList<ShipTypeDto>(); /** UseItem (バケツとか、家具箱とか) */ private final Map<Integer, UseItemInfoDto> useItem = new TreeMap<Integer, UseItemInfoDto>(); public Start2Dto() { } public Start2Dto(JsonObject json) { super(json); this.readJson(); } public void loadCompleted() { this.readJson(); } private void readJson() { // 艦種 JsonArray json_stype = this.json.getJsonArray("api_mst_stype"); if (json_stype != null) { this.stype.clear(); for (JsonValue elem : json_stype) { this.stype.add(new ShipTypeDto((JsonObject) elem)); } } // 装備一覧 JsonArray apiMstSlotitem = this.json.getJsonArray("api_mst_slotitem"); if (apiMstSlotitem != null) { this.items.clear(); for (int i = 0; i < apiMstSlotitem.size(); i++) { JsonObject object = (JsonObject) apiMstSlotitem.get(i); ItemInfoDto item = new ItemInfoDto(object); int id = object.getJsonNumber("api_id").intValue(); this.items.put(id, item); } } // 艦娘一覧 JsonArray apiMstShip = this.json.getJsonArray("api_mst_ship"); if (apiMstShip != null) { this.ships.clear(); for (int i = 0; i < apiMstShip.size(); i++) { JsonObject object = (JsonObject) apiMstShip.get(i); int id = object.getInt("api_id"); this.ships.put(id, this.toShipInfoDto(object)); } } this.setCharId(); JsonArray json_maparea = this.json.getJsonArray("api_mst_maparea"); if (json_maparea != null) { this.maparea.clear(); for (JsonValue elem : json_maparea) { this.maparea.add(new MapAreaDto((JsonObject) elem)); } } JsonArray json_mapinfo = this.json.getJsonArray("api_mst_mapinfo"); if (json_mapinfo != null) { this.mapinfo.clear(); for (JsonValue elem : json_mapinfo) { MapInfoDto dto = new MapInfoDto((JsonObject) elem); this.mapinfo.put(dto.getId(), dto); } } JsonArray json_mission = this.json.getJsonArray("api_mst_mission"); if (json_mission != null) { this.mission.clear(); for (JsonValue elem : json_mission) { MissionDto dto = new MissionDto((JsonObject) elem); this.mission.put(dto.getId(), dto); } } JsonArray json_useitem = this.json.getJsonArray("api_mst_useitem"); if (json_useitem != null) { this.useItem.clear(); for (JsonValue elem : json_useitem) { UseItemInfoDto dto = new UseItemInfoDto((JsonObject) elem); this.useItem.put(dto.getId(), dto); } } this.time = new Date(); } private void visitShip(ShipInfoDto ship, int[] charId) { if ((ship != null) && (ship.getData() == null)) { ship.setData(charId); if (ship.getAftershipid() != 0) { this.visitShip(this.ships.get(ship.getAftershipid()), charId); } if (ship.getBeforeshpids() != null) { for (int shipid : ship.getBeforeshpids()) { this.visitShip(this.ships.get(shipid), charId); } } } } /** * 初期艦IDを計算します */ private void setCharId() { // リセット for (ShipInfoDto dto : this.ships.values()) { dto.setData(null); dto.setBeforeshpids(null); } // beforeshipidsを生成 for (ShipInfoDto dto : this.ships.values()) { if (dto.getAftershipid() != 0) { ShipInfoDto afterShip = this.ships.get(dto.getAftershipid()); if (afterShip != null) { afterShip.setBeforeshpids(ArrayUtils.add(afterShip.getBeforeshpids(), dto.getShipId())); } } } // 同じ島に同じint[]を配置 for (ShipInfoDto dto : this.ships.values()) { this.visitShip(dto, new int[] { -1 }); } // 初期艦のIDを探す for (ShipInfoDto dto : this.ships.values()) { if (dto.getBeforeshpids() == null) { int[] charId = (int[]) dto.getData(); // 複数見つかったら(普通はありえないが)小さい方にしておく if ((charId[0] == -1) || (charId[0] > dto.getShipId())) { charId[0] = dto.getShipId(); } } } // IDをセット for (ShipInfoDto dto : this.ships.values()) { int[] charId = (int[]) dto.getData(); dto.setCharId(charId[0]); dto.setData(null); } } /** * 艦娘を作成します * * @param object * @return */ private ShipInfoDto toShipInfoDto(JsonObject object) { String name = object.getString("api_name"); if ("なし".equals(name)) { return ShipInfoDto.EMPTY; } return new ShipInfoDto(object); } /** 艦種情報を取得 */ public ShipTypeDto getShipType(int stype) { if ((stype <= 0) || (stype > this.stype.size())) { return null; } return this.stype.get(stype - 1); } /** (装備でない)アイテム情報を取得 */ public UseItemInfoDto getUseItem(int id) { Integer key = id; return this.useItem.get(key); } /** マップ情報を取得 */ public MapInfoDto getMapInfo(int area, int no) { int id = (area * 10) + no; return this.mapinfo.get(id); } public String getMissionName(int missionId) { MissionDto dto = this.mission.get(missionId); if (dto != null) { return dto.getName(); } return null; } /** * @return maparea */ public ArrayList<MapAreaDto> getMaparea() { return this.maparea; } /** * @return mapinfo */ public Map<Integer, MapInfoDto> getMapinfo() { return this.mapinfo; } /** * @return mission */ public Map<Integer, MissionDto> getMission() { return this.mission; } /** * @return stype */ public List<ShipTypeDto> getStype() { return this.stype; } /** * @return useItem */ public Map<Integer, UseItemInfoDto> getUseItem() { return this.useItem; } /** * @return time */ public Date getTime() { return this.time; } /** * @param time セットする time */ public void setTime(Date time) { this.time = time; } /** * @return ships */ public Map<Integer, ShipInfoDto> getShips() { return this.ships; } /** * @return items */ public Map<Integer, ItemInfoDto> getItems() { return this.items; } } /** * api_mst_maparea * @author Nekopanda */ public static class MapAreaDto extends JsonData { public MapAreaDto() { } public MapAreaDto(JsonObject json) { super(json); } /** * @return id */ public int getId() { return this.json.getInt("api_id"); } /** * @return name */ public String getName() { return this.json.getString("api_name"); } } /** * api_mst_mapinfo * @author Nekopanda */ public static class MapInfoDto extends JsonData { public MapInfoDto() { } public MapInfoDto(JsonObject json) { super(json); } /** * @return id */ public int getId() { return this.json.getInt("api_id"); } /** * @return maparea_id */ public int getMaparea_id() { return this.json.getInt("api_maparea_id"); } /** * @return no */ public int getNo() { return this.json.getInt("api_no"); } /** * @return name */ public String getName() { return this.json.getString("api_name"); } } /** * api_mst_mission * @author Nekopanda */ public static class MissionDto extends JsonData { public MissionDto() { } public MissionDto(JsonObject json) { super(json); } /** * 遠征ID * @return id */ public int getId() { return this.json.getInt("api_id"); } /** * 遠征のマップエリアID * @return maparea_id */ public int getMapareaId() { return this.json.getInt("api_maparea_id"); } /** * 遠征名 * @return name */ public String getName() { return this.json.getString("api_name"); } /** * 遠征にかかる時間 * @return time */ public int getTime() { return this.json.getInt("api_time"); } /** * もらえるかもしれないアイテム * @return winItem */ public UseItemDto[] getWinItem() { return new UseItemDto[] { new UseItemDto(this.json.getJsonArray("api_win_item1")), new UseItemDto(this.json.getJsonArray("api_win_item2")) }; } } /** * api_mst_stype * @author Nekopanda */ public static class ShipTypeDto extends JsonData { public ShipTypeDto() { } public ShipTypeDto(JsonObject json) { super(json); } /** * @return name */ public String getName() { return this.json.getString("api_name"); } /** * @return id */ public int getId() { return this.json.getJsonNumber("api_id").intValue(); } /** * @return equipType */ public List<Boolean> getEquipType() { List<Boolean> equipType = new ArrayList<Boolean>(); JsonObject json_equip_type = this.json.getJsonObject("api_equip_type"); for (int i = 1;; ++i) { JsonNumber number = json_equip_type.getJsonNumber(String.valueOf(i)); if (number == null) break; equipType.add(number.intValue() != 0); } return equipType; } } /** * api_mst_useitem * @author Nekopanda */ public static class UseItemInfoDto extends JsonData { public UseItemInfoDto() { } public UseItemInfoDto(JsonObject json) { super(json); } /** * @return id */ public int getId() { return this.json.getJsonNumber("api_id").intValue(); } /** * @return usetype */ public int getUsetype() { return this.json.getJsonNumber("api_usetype").intValue(); } /** * @return name */ public String getName() { return this.json.getString("api_name"); } /** * @return description */ public String getDescription() { return this.json.getJsonArray("api_description").getString(0); } } }