OSDN Git Service

資材ログの出力を母港に戻ったときだけにする
[kancollesniffer/KancolleSniffer.git] / KancolleSniffer / Logger.cs
1 using System;\r
2 using System.Collections.Generic;\r
3 using System.IO;\r
4 using System.Text;\r
5 using System.Linq;\r
6 using System.Web;\r
7 using System.Windows.Forms;\r
8 \r
9 namespace KancolleSniffer\r
10 {\r
11     [Flags]\r
12     public enum LogType\r
13     {\r
14         None = 0,\r
15         Mission = 1,\r
16         Battle = 2,\r
17         Material = 4,\r
18         CreateItem = 8,\r
19         CreateShip = 16,\r
20         All = 31,\r
21     }\r
22 \r
23     public class Logger\r
24     {\r
25         private LogType _logType;\r
26         private readonly ShipMaster _shipMaster;\r
27         private readonly ShipInfo _shipInfo;\r
28         private readonly ItemInfo _itemInfo;\r
29         private Action<string, string, string> _writer;\r
30         private Func<DateTime> _nowFunc;\r
31         private const string DateTimeFormat = @"yyyy\-MM\-dd HH\:mm\:ss";\r
32         private dynamic _battle;\r
33         private dynamic _map;\r
34         private dynamic _basic;\r
35         private int _kdockId;\r
36 \r
37         public Logger(ShipMaster master, ShipInfo ship, ItemInfo item)\r
38         {\r
39             _shipMaster = master;\r
40             _shipInfo = ship;\r
41             _itemInfo = item;\r
42             _writer = new LogWriter().Write;\r
43             _nowFunc = () => DateTime.Now;\r
44         }\r
45 \r
46         public void EnableLog(LogType type)\r
47         {\r
48             _logType = type;\r
49         }\r
50 \r
51         public void SetWriter(Action<string, string, string> writer, Func<DateTime> nowFunc)\r
52         {\r
53             _writer = writer;\r
54             _nowFunc = nowFunc;\r
55         }\r
56 \r
57         public void InspectMissionResult(dynamic json)\r
58         {\r
59             var r = (int)json.api_clear_result;\r
60             var rstr = r == 2 ? "大成功" : r == 1 ? "成功" : "失敗";\r
61             var material = new int[7];\r
62             if (r != 0)\r
63                 ((int[])json.api_get_material).CopyTo(material, 0);\r
64             foreach (var i in new[] {1, 2})\r
65             {\r
66                 var attr = "api_get_item" + i;\r
67                 if (!json.IsDefined(attr) || json[attr].api_useitem_id != -1)\r
68                     continue;\r
69                 var count = (int)json[attr].api_useitem_count;\r
70                 var flag = ((int[])json.api_useitem_flag)[i - 1];\r
71                 if (flag == 1)\r
72                     material[(int)Material.Bucket] = count;\r
73                 else if (flag == 2)\r
74                     material[(int)Material.Burner] = count;\r
75                 else if (flag == 3)\r
76                     material[(int)Material.Development] = count;\r
77             }\r
78             if ((_logType & LogType.Mission) != 0)\r
79             {\r
80                 _writer("遠征報告書",\r
81                     string.Join(",", _nowFunc().ToString(DateTimeFormat),\r
82                         rstr, json.api_quest_name, string.Join(",", material)),\r
83                     "日付,結果,遠征,燃料,弾薬,鋼材,ボーキ,開発資材,高速修復材,高速建造材");\r
84             }\r
85         }\r
86 \r
87         public void InspectMap(dynamic json)\r
88         {\r
89             _map = json;\r
90         }\r
91 \r
92         public void InspectBattle(dynamic json)\r
93         {\r
94             if (!IsNightBattle(json))\r
95                 _battle = json;\r
96         }\r
97 \r
98         private bool IsNightBattle(dynamic json)\r
99         {\r
100             return json.api_hougeki();\r
101         }\r
102 \r
103         public void InspectBattleResult(dynamic result)\r
104         {\r
105             if ((_logType & LogType.Battle) == 0 || _map == null || _battle == null)\r
106             {\r
107                 _map = _battle = null;\r
108                 return;\r
109             }\r
110             var fships = new List<string>();\r
111             var deck = _shipInfo.GetDeck(_battle.api_dock_id() ? (int)_battle.api_dock_id - 1 : 0);\r
112             fships.AddRange(deck.Select(id =>\r
113             {\r
114                 if (id == -1)\r
115                     return ",";\r
116                 var s = _shipInfo[id];\r
117                 return string.Format("{0}(Lv{1}),{2}/{3}", s.Name, s.Level, s.NowHp, s.MaxHp);\r
118             }));\r
119             var edeck = ((int[])_battle.api_ship_ke).Skip(1).ToArray();\r
120             var enowhp = ((int[])_battle.api_nowhps).Skip(7).ToArray();\r
121             var emaxhp = ((int[])_battle.api_maxhps).Skip(7).ToArray();\r
122             var eships = new List<string>();\r
123             for (var i = 0; i < edeck.Count(); i++)\r
124             {\r
125                 eships.Add(edeck[i] == -1\r
126                     ? ","\r
127                     : string.Format("{0},{1}/{2}", _shipMaster[edeck[i]].Name, enowhp[i], emaxhp[i]));\r
128             }\r
129             var cell = (int)_map.api_no;\r
130             var boss = cell == (int)_map.api_bosscell_no || (int)_map.api_event_id == 5 ? "ボス" : "";\r
131             _writer("海戦・ドロップ報告書", string.Join(",", _nowFunc().ToString(DateTimeFormat),\r
132                 result.api_quest_name,\r
133                 cell, boss,\r
134                 result.api_win_rank,\r
135                 BattleFormationName((int)_battle.api_formation[2]),\r
136                 FormationName(_battle.api_formation[0]),\r
137                 FormationName(_battle.api_formation[1]),\r
138                 result.api_enemy_info.api_deck_name,\r
139                 result.api_get_ship() ? result.api_get_ship.api_ship_type : "",\r
140                 result.api_get_ship() ? result.api_get_ship.api_ship_name : "",\r
141                 string.Join(",", fships),\r
142                 string.Join(",", eships)),\r
143                 "日付,海域,マス,ボス,ランク,艦隊行動,味方陣形,敵陣形,敵艦隊,ドロップ艦種,ドロップ艦娘," +\r
144                 "味方艦1,味方艦1HP,味方艦2,味方艦2HP,味方艦3,味方艦3HP,味方艦4,味方艦4HP,味方艦5,味方艦5HP,味方艦6,味方艦6HP," +\r
145                 "敵艦1,敵艦1HP,敵艦2,敵艦2HP,敵艦3,敵艦3HP,敵艦4,敵艦4HP,敵艦5,敵艦5HP,敵艦6,敵艦6HP"\r
146                 );\r
147             _map = _battle = null;\r
148         }\r
149 \r
150         private string FormationName(dynamic f)\r
151         {\r
152             if (f is string) // 連合艦隊のときは文字列\r
153                 f = int.Parse(f);\r
154             switch ((int)f)\r
155             {\r
156                 case 1:\r
157                     return "単縦陣";\r
158                 case 2:\r
159                     return "複縦陣";\r
160                 case 3:\r
161                     return "輪形陣";\r
162                 case 4:\r
163                     return "梯形陣";\r
164                 case 5:\r
165                     return "単横陣";\r
166                 case 11:\r
167                     return "第一警戒航行序列";\r
168                 case 12:\r
169                     return "第二警戒航行序列";\r
170                 case 13:\r
171                     return "第三警戒航行序列";\r
172                 case 14:\r
173                     return "第四警戒航行序列";\r
174                 default:\r
175                     return "単縦陣";\r
176             }\r
177         }\r
178 \r
179         private static String BattleFormationName(int f)\r
180         {\r
181             switch (f)\r
182             {\r
183                 case 1:\r
184                     return "同航戦";\r
185                 case 2:\r
186                     return "反航戦";\r
187                 case 3:\r
188                     return "T字戦(有利)";\r
189                 case 4:\r
190                     return "T字戦(不利)";\r
191                 default:\r
192                     return "同航戦";\r
193             }\r
194         }\r
195 \r
196         public void InspectBasic(dynamic json)\r
197         {\r
198             _basic = json;\r
199         }\r
200 \r
201         public void InspectCreateItem(string request, dynamic json)\r
202         {\r
203             if ((_logType & LogType.CreateItem) == 0)\r
204                 return;\r
205             var values = HttpUtility.ParseQueryString(request);\r
206             var name = "失敗";\r
207             var type = "";\r
208             if (json.api_slot_item())\r
209             {\r
210                 var spec = _itemInfo.GetSpecByItemId((int)json.api_slot_item.api_slotitem_id);\r
211                 name = spec.Name;\r
212                 type = spec.TypeName;\r
213             }\r
214             _writer("開発報告書",\r
215                 _nowFunc().ToString(DateTimeFormat) + "," +\r
216                 string.Join(",", name, type,\r
217                     values["api_item1"], values["api_item2"], values["api_item3"], values["api_item4"],\r
218                     Secretary(), _basic.api_level),\r
219                 "日付,開発装備,種別,燃料,弾薬,鋼材,ボーキ,秘書艦,司令部Lv");\r
220         }\r
221 \r
222         public void InspectCreateShip(string request)\r
223         {\r
224             var values = HttpUtility.ParseQueryString(request);\r
225             _kdockId = int.Parse(values["api_kdock_id"]);\r
226         }\r
227 \r
228         public void InspectKDock(dynamic json)\r
229         {\r
230             if ((_logType & LogType.CreateShip) == 0 || _basic == null || _kdockId == 0)\r
231                 return;\r
232             var kdock = ((dynamic[])json).First(e => e.api_id == _kdockId);\r
233             var material = Enumerable.Range(1, 5).Select(i => (int)kdock["api_item" + i]).ToArray();\r
234             var ship = _shipMaster[(int)kdock.api_created_ship_id];\r
235             var avail = ((dynamic[])json).Count(e => (int)e.api_state == 0);\r
236             _writer("建造報告書",\r
237                 _nowFunc().ToString(DateTimeFormat) + "," +\r
238                 string.Join(",", material.First() >= 1500 ? "大型艦建造" : "通常艦建造",\r
239                     ship.Name, ship.ShipTypeName, string.Join(",", material), avail, Secretary(), _basic.api_level),\r
240                 "日付,種類,名前,艦種,燃料,弾薬,鋼材,ボーキ,開発資材,空きドック,秘書艦,司令部Lv");\r
241             _kdockId = 0;\r
242         }\r
243 \r
244         private string Secretary()\r
245         {\r
246             var ship = _shipInfo.GetShipStatuses(0)[0];\r
247             return ship.Name + "(" + ship.Level + ")";\r
248         }\r
249 \r
250         public void InspectMaterial(dynamic json)\r
251         {\r
252             if ((_logType & LogType.Material) == 0)\r
253                 return;\r
254             var material = new int[8];\r
255             foreach (var e in json)\r
256                 material[(int)e.api_id - 1] = (int)e.api_value;\r
257             _writer("資材ログ",\r
258                 _nowFunc().ToString(DateTimeFormat) + "," +\r
259                 string.Join(",", material) + ",",\r
260                 "日付,燃料,弾薬,鋼材,ボーキ,高速修復材,高速建造材,開発資材,改修資材");\r
261         }\r
262     }\r
263 \r
264     public class LogWriter\r
265     {\r
266         private readonly IFile _file;\r
267 \r
268         public interface IFile\r
269         {\r
270             string ReadAllText(string path);\r
271             void AppendAllText(string path, string text);\r
272             void Delete(string path);\r
273             bool Exists(string path);\r
274         }\r
275 \r
276         private class FileWrapper : IFile\r
277         {\r
278             // Shift_JISでないとExcelで文字化けする\r
279             private readonly Encoding _encoding = Encoding.GetEncoding("Shift_JIS");\r
280 \r
281             public string ReadAllText(string path)\r
282             {\r
283                 return File.ReadAllText(path, _encoding);\r
284             }\r
285 \r
286             public void AppendAllText(string path, string text)\r
287             {\r
288                 File.AppendAllText(path, text, _encoding);\r
289             }\r
290 \r
291             public void Delete(string path)\r
292             {\r
293                 File.Delete(path);\r
294             }\r
295 \r
296             public bool Exists(string path)\r
297             {\r
298                 return File.Exists(path);\r
299             }\r
300         }\r
301 \r
302         public LogWriter(IFile file = null)\r
303         {\r
304             _file = file ?? new FileWrapper();\r
305         }\r
306 \r
307         public void Write(string file, string s, string header)\r
308         {\r
309             // ReSharper disable once AssignNullToNotNullAttribute\r
310             var path = Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), file);\r
311             var csv = path + ".csv";\r
312             var tmp = path + ".tmp";\r
313             if (_file.Exists(tmp))\r
314             {\r
315                 try\r
316                 {\r
317                     _file.AppendAllText(csv, _file.ReadAllText(tmp));\r
318                     _file.Delete(tmp);\r
319                 }\r
320                 catch (IOException)\r
321                 {\r
322                 }\r
323             }\r
324             if (!_file.Exists(csv))\r
325                 s = header + "\r\n" + s;\r
326             foreach (var f in new[] {csv, tmp})\r
327             {\r
328                 try\r
329                 {\r
330                     _file.AppendAllText(f, s + "\r\n");\r
331                     break;\r
332                 }\r
333                 catch (IOException)\r
334                 {\r
335                 }\r
336             }\r
337         }\r
338     }\r
339 }