OSDN Git Service

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