1 // Copyright (C) 2014, 2015 Kazuhiro Fujieda <fujieda@users.osdn.me>
\r
3 // This program is part of KancolleSniffer.
\r
5 // KancolleSniffer is free software: you can redistribute it and/or modify
\r
6 // it under the terms of the GNU General Public License as published by
\r
7 // the Free Software Foundation, either version 3 of the License, or
\r
8 // (at your option) any later version.
\r
10 // This program is distributed in the hope that it will be useful,
\r
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
13 // GNU General Public License for more details.
\r
15 // You should have received a copy of the GNU General Public License
\r
16 // along with this program; if not, see <http://www.gnu.org/licenses/>.
\r
19 using System.Collections.Generic;
\r
25 namespace KancolleSniffer
\r
42 private LogType _logType;
\r
43 private readonly ShipInfo _shipInfo;
\r
44 private readonly ItemInfo _itemInfo;
\r
45 private readonly BattleInfo _battleInfo;
\r
46 private Action<string, string, string> _writer;
\r
47 private Func<DateTime> _nowFunc;
\r
48 public const string DateTimeFormat = @"yyyy\-MM\-dd HH\:mm\:ss";
\r
49 private dynamic _battle;
\r
50 private dynamic _map;
\r
51 private dynamic _basic;
\r
52 private int _kdockId;
\r
53 private DateTime _prevTime;
\r
54 private int[] _currentMaterial;
\r
55 private int _materialLogInterval = 10;
\r
56 private bool _start;
\r
58 public int MaterialLogInterval
\r
60 set { _materialLogInterval = value; }
\r
63 public string OutputDir
\r
65 set { _writer = new LogWriter(value).Write; }
\r
68 public Logger(ShipInfo ship, ItemInfo item, BattleInfo battle)
\r
72 _battleInfo = battle;
\r
73 _writer = new LogWriter().Write;
\r
74 _nowFunc = () => DateTime.Now;
\r
77 public void EnableLog(LogType type)
\r
82 public void SetWriter(Action<string, string, string> writer, Func<DateTime> nowFunc)
\r
88 public void InspectMissionResult(dynamic json)
\r
90 var r = (int)json.api_clear_result;
\r
91 var rstr = r == 2 ? "大成功" : r == 1 ? "成功" : "失敗";
\r
92 var material = new int[7];
\r
94 ((int[])json.api_get_material).CopyTo(material, 0);
\r
95 foreach (var i in new[] {1, 2})
\r
97 var attr = "api_get_item" + i;
\r
98 if (!json.IsDefined(attr) || json[attr].api_useitem_id != -1)
\r
100 var count = (int)json[attr].api_useitem_count;
\r
101 var flag = ((int[])json.api_useitem_flag)[i - 1];
\r
103 material[(int)Material.Bucket] = count;
\r
104 else if (flag == 2)
\r
105 material[(int)Material.Burner + 2] = count; // 高速建造材と開発資材が反対なのでいつか直す
\r
106 else if (flag == 3)
\r
107 material[(int)Material.Development - 2] = count;
\r
109 if ((_logType & LogType.Mission) != 0)
\r
112 string.Join(",", _nowFunc().ToString(DateTimeFormat),
\r
113 rstr, json.api_quest_name, string.Join(",", material)),
\r
114 "日付,結果,遠征,燃料,弾薬,鋼材,ボーキ,開発資材,高速修復材,高速建造材");
\r
118 public void InspectMapStart(dynamic json)
\r
124 public void InspectMapNext(dynamic json)
\r
129 public void InspectBattle(dynamic json)
\r
131 if (_battle != null) // 通常の夜戦は無視する
\r
136 public void InspectBattleResult(dynamic result)
\r
138 if ((_logType & LogType.Battle) == 0 || _map == null || _battle == null)
\r
140 _map = _battle = null;
\r
143 var fships = new List<string>();
\r
144 var deck = _shipInfo.GetDeck(_battle.api_dock_id() ? (int)_battle.api_dock_id - 1 : 0);
\r
145 fships.AddRange(deck.Select(id =>
\r
149 var s = _shipInfo[id];
\r
150 return $"{s.Name}(Lv{s.Level}),{s.NowHp}/{s.MaxHp}";
\r
152 var estatus = _battleInfo.EnemyResultStatus;
\r
153 var edeck = ((int[])_battle.api_ship_ke).Skip(1).ToArray();
\r
154 var eships = new List<string>();
\r
155 for (var i = 0; i < edeck.Count(); i++)
\r
157 eships.Add(edeck[i] == -1
\r
159 : $"{estatus[i].Name},{estatus[i].NowHp}/{estatus[i].MaxHp}");
\r
161 var cell = (int)_map.api_no;
\r
165 if (cell == (int)_map.api_bosscell_no || (int)_map.api_event_id == 5)
\r
166 boss = _start ? "出撃&ボス" : "ボス";
\r
167 var dropType = result.api_get_ship() ? result.api_get_ship.api_ship_type : "";
\r
168 if (result.api_get_useitem())
\r
170 if (dropType == "")
\r
173 dropType += "+アイテム";
\r
175 var dropName = result.api_get_ship() ? result.api_get_ship.api_ship_name : "";
\r
176 if (result.api_get_useitem())
\r
178 var itemName = _itemInfo.GetUseItemName((int)result.api_get_useitem.api_useitem_id);
\r
179 if (dropName == "")
\r
180 dropName = itemName;
\r
182 dropName += "+" + itemName;
\r
184 _writer("海戦・ドロップ報告書", string.Join(",", _nowFunc().ToString(DateTimeFormat),
\r
185 result.api_quest_name,
\r
187 result.api_win_rank,
\r
188 BattleFormationName((int)_battle.api_formation[2]),
\r
189 FormationName(_battle.api_formation[0]),
\r
190 FormationName(_battle.api_formation[1]),
\r
191 result.api_enemy_info.api_deck_name,
\r
192 dropType, dropName,
\r
193 string.Join(",", fships),
\r
194 string.Join(",", eships)),
\r
195 "日付,海域,マス,ボス,ランク,艦隊行動,味方陣形,敵陣形,敵艦隊,ドロップ艦種,ドロップ艦娘," +
\r
196 "味方艦1,味方艦1HP,味方艦2,味方艦2HP,味方艦3,味方艦3HP,味方艦4,味方艦4HP,味方艦5,味方艦5HP,味方艦6,味方艦6HP," +
\r
197 "敵艦1,敵艦1HP,敵艦2,敵艦2HP,敵艦3,敵艦3HP,敵艦4,敵艦4HP,敵艦5,敵艦5HP,敵艦6,敵艦6HP"
\r
199 _map = _battle = null;
\r
203 private string FormationName(dynamic f)
\r
205 if (f is string) // 連合艦隊のときは文字列
\r
232 private static String BattleFormationName(int f)
\r
249 public void InspectBasic(dynamic json)
\r
254 public void InspectCreateItem(string request, dynamic json)
\r
256 if ((_logType & LogType.CreateItem) == 0)
\r
258 var values = HttpUtility.ParseQueryString(request);
\r
261 if (json.api_slot_item())
\r
263 var spec = _itemInfo.GetSpecByItemId((int)json.api_slot_item.api_slotitem_id);
\r
265 type = spec.TypeName;
\r
268 _nowFunc().ToString(DateTimeFormat) + "," +
\r
269 string.Join(",", name, type,
\r
270 values["api_item1"], values["api_item2"], values["api_item3"], values["api_item4"],
\r
271 Secretary(), _basic.api_level),
\r
272 "日付,開発装備,種別,燃料,弾薬,鋼材,ボーキ,秘書艦,司令部Lv");
\r
275 public void InspectCreateShip(string request)
\r
277 var values = HttpUtility.ParseQueryString(request);
\r
278 _kdockId = int.Parse(values["api_kdock_id"]);
\r
281 public void InspectKDock(dynamic json)
\r
283 if ((_logType & LogType.CreateShip) == 0 || _basic == null || _kdockId == 0)
\r
285 var kdock = ((dynamic[])json).First(e => e.api_id == _kdockId);
\r
286 var material = Enumerable.Range(1, 5).Select(i => (int)kdock["api_item" + i]).ToArray();
\r
287 var ship = _shipInfo.GetSpec((int)kdock.api_created_ship_id);
\r
288 var avail = ((dynamic[])json).Count(e => (int)e.api_state == 0);
\r
290 _nowFunc().ToString(DateTimeFormat) + "," +
\r
291 string.Join(",", material.First() >= 1500 ? "大型艦建造" : "通常艦建造",
\r
292 ship.Name, ship.ShipTypeName, string.Join(",", material), avail, Secretary(), _basic.api_level),
\r
293 "日付,種類,名前,艦種,燃料,弾薬,鋼材,ボーキ,開発資材,空きドック,秘書艦,司令部Lv");
\r
297 private string Secretary()
\r
299 var ship = _shipInfo.GetShipStatuses(0)[0];
\r
300 return ship.Name + "(" + ship.Level + ")";
\r
303 public void InspectMaterial(dynamic json)
\r
305 if ((_logType & LogType.Material) == 0)
\r
307 var now = _nowFunc();
\r
308 if (now - _prevTime < TimeSpan.FromMinutes(_materialLogInterval))
\r
311 var material = new int[8];
\r
312 foreach (var e in json)
\r
313 material[(int)e.api_id - 1] = (int)e.api_value;
\r
315 now.ToString(DateTimeFormat) + "," +
\r
316 string.Join(",", material),
\r
317 "日付,燃料,弾薬,鋼材,ボーキ,高速建造材,高速修復材,開発資材,改修資材");
\r
320 public void SetCurrentMaterial(int[] material)
\r
322 _currentMaterial = material;
\r
325 public void InspectRemodelSlot(string request, dynamic json)
\r
327 if ((_logType & LogType.RemodelSlot) == 0)
\r
329 var now = _nowFunc();
\r
330 var values = HttpUtility.ParseQueryString(request);
\r
331 var id = int.Parse(values["api_slot_id"]);
\r
332 var name = _itemInfo.GetName(id);
\r
333 var level = _itemInfo.GetStatus(id).Level;
\r
334 var success = (int)json.api_remodel_flag == 1 ? "○" : "×";
\r
335 var certain = int.Parse(values["api_certain_flag"]) == 1 ? "○" : "";
\r
338 if (json.api_use_slot_id())
\r
340 var use = (int[])json.api_use_slot_id;
\r
341 useName = _itemInfo.GetName(use[0]);
\r
342 useNum = use.Length.ToString();
\r
344 var after = (int[])json.api_after_material;
\r
345 var diff = new int[after.Length];
\r
346 for (var i = 0; i < after.Length; i++)
\r
347 diff[i] = _currentMaterial[i] - after[i];
\r
348 var ship1 = Secretary();
\r
350 var ships = _shipInfo.GetShipStatuses(0);
\r
351 if (ships.Length >= 2)
\r
352 ship2 = ships[1].Name + "(" + ships[1].Level + ")";
\r
354 now.ToString(DateTimeFormat) + "," +
\r
355 string.Join(",", name, level, success, certain, useName, useNum,
\r
356 diff[(int)Material.Fuel], diff[(int)Material.Bullet], diff[(int)Material.Steal],
\r
357 diff[(int)Material.Bouxite],
\r
358 diff[(int)Material.Development], diff[(int)Material.Screw],
\r
360 "日付,改修装備,レベル,成功,確実化,消費装備,消費数,燃料,弾薬,鋼材,ボーキ,開発資材,改修資材,秘書艦,二番艦");
\r
364 public class LogWriter
\r
366 private readonly IFile _file;
\r
367 private readonly string _outputDir;
\r
369 public interface IFile
\r
371 string ReadAllText(string path);
\r
372 void AppendAllText(string path, string text);
\r
373 void Delete(string path);
\r
374 bool Exists(string path);
\r
377 private class FileWrapper : IFile
\r
379 // Shift_JISでないとExcelで文字化けする
\r
380 private readonly Encoding _encoding = Encoding.GetEncoding("Shift_JIS");
\r
382 public string ReadAllText(string path) => File.ReadAllText(path, _encoding);
\r
384 public void AppendAllText(string path, string text)
\r
386 File.AppendAllText(path, text, _encoding);
\r
389 public void Delete(string path)
\r
394 public bool Exists(string path) => File.Exists(path);
\r
397 public LogWriter(string outputDir = null, IFile file = null)
\r
399 _outputDir = outputDir ?? AppDomain.CurrentDomain.BaseDirectory;
\r
400 _file = file ?? new FileWrapper();
\r
403 public void Write(string file, string s, string header)
\r
405 var path = Path.Combine(_outputDir, file);
\r
406 var csv = path + ".csv";
\r
407 var tmp = path + ".tmp";
\r
408 if (_file.Exists(tmp))
\r
412 _file.AppendAllText(csv, _file.ReadAllText(tmp));
\r
415 catch (IOException)
\r
419 if (!_file.Exists(csv))
\r
420 s = header + "\r\n" + s;
\r
421 foreach (var f in new[] {csv, tmp})
\r
425 _file.AppendAllText(f, s + "\r\n");
\r
428 catch (IOException)
\r