OSDN Git Service

75262db8e8d3638d21260179efdfeb7ef4e5db57
[kancollesniffer/KancolleSniffer.git] / KancolleSniffer / Sniffer.cs
1 // Copyright (C) 2013, 2014, 2015 Kazuhiro Fujieda <fujieda@users.sourceforge.jp>\r
2 // \r
3 // This program is part of KancolleSniffer.\r
4 //\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
9 //\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
14 //\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
17 \r
18 using System;\r
19 \r
20 namespace KancolleSniffer\r
21 {\r
22     public class Sniffer\r
23     {\r
24         private bool _start;\r
25         private readonly ShipMaster _shipMaster = new ShipMaster();\r
26         private readonly ItemInfo _itemInfo = new ItemInfo();\r
27         private readonly QuestInfo _questInfo = new QuestInfo();\r
28         private readonly MissionInfo _missionInfo = new MissionInfo();\r
29         private readonly ShipInfo _shipInfo;\r
30         private readonly ConditionTimer _conditionTimer;\r
31         private readonly DockInfo _dockInfo;\r
32         private readonly AkashiTimer _akashiTimer;\r
33         private readonly Achievement _achievement = new Achievement();\r
34         private readonly BattleInfo _battleInfo;\r
35         private readonly Logger _logger;\r
36         private readonly Status _status = new Status();\r
37         private bool _saveState;\r
38 \r
39         [Flags]\r
40         public enum Update\r
41         {\r
42             None = 0,\r
43             Start = 1,\r
44             Item = 2,\r
45             Ship = 4,\r
46             Timer = 8,\r
47             NDock = 16,\r
48             Mission = 32,\r
49             QuestList = 64,\r
50             Battle = 128,\r
51             All = 255\r
52         }\r
53 \r
54         public Sniffer()\r
55         {\r
56             _shipInfo = new ShipInfo(_shipMaster, _itemInfo);\r
57             _conditionTimer = new ConditionTimer(_shipInfo);\r
58             _dockInfo = new DockInfo(_shipInfo, _itemInfo);\r
59             _akashiTimer = new AkashiTimer(_shipInfo, _itemInfo, _dockInfo);\r
60             _battleInfo = new BattleInfo(_shipMaster, _shipInfo, _itemInfo);\r
61             _logger = new Logger(_shipMaster, _shipInfo, _itemInfo);\r
62         }\r
63 \r
64         private void SaveState()\r
65         {\r
66             if (!_saveState)\r
67                 return;\r
68             if (!_achievement.NeedSave && !_itemInfo.NeedSave && !_conditionTimer.NeedSave)\r
69                 return;\r
70             _achievement.SaveState(_status);\r
71             _itemInfo.SaveState(_status);\r
72             _conditionTimer.SaveState(_status);\r
73             _status.Save();\r
74         }\r
75 \r
76         public void LoadState()\r
77         {\r
78             _status.Load();\r
79             _achievement.LoadState(_status);\r
80             _itemInfo.LoadSate(_status);\r
81             _conditionTimer.LoadState(_status);\r
82             _saveState = true;\r
83         }\r
84 \r
85         public Update Sniff(string url, string request, dynamic json)\r
86         {\r
87             var data = json.IsDefined("api_data") ? json.api_data : new object();\r
88 \r
89             if (url.EndsWith("api_start2"))\r
90             {\r
91                 _start = true;\r
92                 _shipMaster.Inspect(data);\r
93                 _missionInfo.InspectMaster(data.api_mst_mission);\r
94                 _itemInfo.InspectMaster(data);\r
95                 return Update.Start;\r
96             }\r
97             if (!_start)\r
98                 return Update.None;\r
99             if (url.EndsWith("api_port/port"))\r
100             {\r
101                 _itemInfo.InspectBasic(data.api_basic);\r
102                 _itemInfo.InspectMaterial(data.api_material);\r
103                 _logger.InspectBasic(data.api_basic);\r
104                 _logger.InspectMaterial(data.api_material);\r
105                 _shipInfo.InspectShip(data);\r
106                 _conditionTimer.CalcRegenTime();\r
107                 _missionInfo.InspectDeck(data.api_deck_port);\r
108                 _dockInfo.InspectNDock(data.api_ndock);\r
109                 _akashiTimer.SetTimer(true);\r
110                 _achievement.InspectBasic(data.api_basic);\r
111                 if (data.api_parallel_quest_count()) // 昔のログにはないので\r
112                     _questInfo.QuestCount = (int)data.api_parallel_quest_count;\r
113                 _battleInfo.InBattle = false;\r
114                 _battleInfo.HasDamagedShip = false;\r
115                 _shipInfo.ClearEscapedShips();\r
116                 SaveState();\r
117                 return Update.All;\r
118             }\r
119             if (url.EndsWith("api_get_member/basic"))\r
120             {\r
121                 _itemInfo.InspectBasic(data);\r
122                 _logger.InspectBasic(data);\r
123                 return Update.None;\r
124             }\r
125             if (url.EndsWith("api_get_member/slot_item"))\r
126             {\r
127                 _itemInfo.InspectSlotItem(data, true);\r
128                 return Update.None;\r
129             }\r
130             if (url.EndsWith("api_get_member/kdock"))\r
131             {\r
132                 _dockInfo.InspectKDock(data);\r
133                 _logger.InspectKDock(data);\r
134                 return Update.Timer;\r
135             }\r
136             if (url.EndsWith("api_get_member/ndock"))\r
137             {\r
138                 _dockInfo.InspectNDock(data);\r
139                 _conditionTimer.CheckCond();\r
140                 _akashiTimer.SetTimer();\r
141                 return Update.NDock | Update.Timer | Update.Ship;\r
142             }\r
143             if (url.EndsWith("api_req_hensei/change"))\r
144             {\r
145                 _shipInfo.InspectChange(request);\r
146                 _akashiTimer.SetTimer();\r
147                 return Update.Ship;\r
148             }\r
149             if (url.EndsWith("api_get_member/questlist"))\r
150             {\r
151                 _questInfo.Inspect(data);\r
152                 return Update.QuestList;\r
153             }\r
154             if (url.EndsWith("api_get_member/deck"))\r
155             {\r
156                 _shipInfo.InspectDeck(data);\r
157                 _missionInfo.InspectDeck(data);\r
158                 _akashiTimer.SetTimer();\r
159                 return Update.Mission | Update.Timer;\r
160             }\r
161             if (url.EndsWith("api_get_member/ship2"))\r
162             {\r
163                 // ここだけjsonなので注意\r
164                 _shipInfo.InspectShip(json);\r
165                 _akashiTimer.SetTimer();\r
166                 _battleInfo.InBattle = false;\r
167                 return Update.Item | Update.Ship | Update.Battle;\r
168             }\r
169             if (url.EndsWith("api_get_member/ship3"))\r
170             {\r
171                 _shipInfo.InspectShip(data);\r
172                 _akashiTimer.SetTimer();\r
173                 _conditionTimer.CheckCond();\r
174                 return Update.Ship;\r
175             }\r
176             if (url.EndsWith("api_get_member/material"))\r
177             {\r
178                 _itemInfo.InspectMaterial(data);\r
179                 return Update.Item;\r
180             }\r
181             if (url.EndsWith("api_req_hokyu/charge"))\r
182             {\r
183                 _shipInfo.InspectCharge(data);\r
184                 return Update.Item | Update.Ship;\r
185             }\r
186             if (url.EndsWith("api_req_kousyou/createitem"))\r
187             {\r
188                 _itemInfo.InspectCreateItem(data);\r
189                 _logger.InspectCreateItem(request, data);\r
190                 return Update.Item;\r
191             }\r
192             if (url.EndsWith("api_req_kousyou/getship"))\r
193             {\r
194                 _itemInfo.InspectGetShip(data);\r
195                 _shipInfo.InspectShip(data);\r
196                 _dockInfo.InspectKDock(data.api_kdock);\r
197                 _conditionTimer.CheckCond();\r
198                 return Update.Item | Update.Timer;\r
199             }\r
200             if (url.EndsWith("api_req_kousyou/destroyship"))\r
201             {\r
202                 _shipInfo.InspectDestroyShip(request, data);\r
203                 _conditionTimer.CheckCond();\r
204                 _akashiTimer.SetTimer();\r
205                 return Update.Item | Update.Ship;\r
206             }\r
207             if (url.EndsWith("api_req_kousyou/destroyitem2"))\r
208             {\r
209                 _itemInfo.InspectDestroyItem(request, data);\r
210                 return Update.Item;\r
211             }\r
212             if (url.EndsWith("api_req_kousyou/remodel_slot"))\r
213             {\r
214                 _itemInfo.InspectRemodelSlot(data);\r
215                 return Update.Item;\r
216             }\r
217             if (url.EndsWith("api_req_kousyou/createship"))\r
218             {\r
219                 _logger.InspectCreateShip(request);\r
220                 return Update.None;\r
221             }\r
222             if (url.EndsWith("api_req_kaisou/powerup"))\r
223             {\r
224                 _shipInfo.InspectPowerup(request, data);\r
225                 _conditionTimer.CheckCond();\r
226                 _akashiTimer.SetTimer();\r
227                 return Update.Item | Update.Ship;\r
228             }\r
229             if (url.EndsWith("api_req_nyukyo/start"))\r
230             {\r
231                 _dockInfo.InspectNyukyo(request);\r
232                 _conditionTimer.CheckCond();\r
233                 _akashiTimer.SetTimer();\r
234                 return Update.Item | Update.Ship;\r
235             }\r
236             if (url.EndsWith("api_req_nyukyo/speedchange"))\r
237             {\r
238                 _dockInfo.InspectSpeedChange(request);\r
239                 _conditionTimer.CheckCond();\r
240                 return Update.NDock | Update.Timer | Update.Ship;\r
241             }\r
242             if (IsNormalBattleAPI(url))\r
243             {\r
244                 _battleInfo.InspectBattle(data);\r
245                 _logger.InspectBattle(data);\r
246                 return Update.Ship | Update.Battle;\r
247             }\r
248             if (url.EndsWith("api_req_practice/battle") || url.EndsWith("api_req_practice/midnight_battle"))\r
249             {\r
250                 if (url.EndsWith("/battle"))\r
251                 {\r
252                     _shipInfo.StartSortie(request); // 演習を出撃中とみなす\r
253                     _conditionTimer.InvalidateCond();\r
254                 }\r
255                 _battleInfo.InspectPracticeBattle(data);\r
256                 return Update.Ship | Update.Battle | Update.Timer;\r
257             }\r
258             if (url.EndsWith("api_req_sortie/battleresult"))\r
259             {\r
260                 _battleInfo.CauseDamage();\r
261                 _logger.InspectBattleResult(data);\r
262                 return Update.Ship;\r
263             }\r
264             if (url.EndsWith("api_req_practice/battle_result"))\r
265             {\r
266                 _battleInfo.CausePracticeDamage();\r
267                 return Update.Ship;\r
268             }\r
269             if (IsCombinedBattleAPI(url))\r
270             {\r
271                 _battleInfo.InspectCombinedBattle(data, url.EndsWith("battle_water"));\r
272                 _logger.InspectBattle(data);\r
273                 return Update.Ship | Update.Battle;\r
274             }\r
275             if (url.EndsWith("api_req_combined_battle/battleresult"))\r
276             {\r
277                 _battleInfo.InspectCombinedBattleResult(data);\r
278                 _logger.InspectBattleResult(data);\r
279                 return Update.Ship;\r
280             }\r
281             if (url.EndsWith("api_req_combined_battle/goback_port"))\r
282             {\r
283                 _battleInfo.CauseCombinedBattleEscape();\r
284                 return Update.Ship;\r
285             }\r
286             if (url.EndsWith("api_req_map/start"))\r
287             {\r
288                 _shipInfo.StartSortie(request);\r
289                 _conditionTimer.InvalidateCond();\r
290                 _logger.InspectMap(data);\r
291                 return Update.Timer;\r
292             }\r
293             if (url.EndsWith("api_req_map/next"))\r
294             {\r
295                 _logger.InspectMap(data);\r
296                 return Update.None;\r
297             }\r
298             if (url.EndsWith("api_req_mission/result"))\r
299             {\r
300                 _itemInfo.InspectMissionResult(data);\r
301                 _logger.InspectMissionResult(data);\r
302                 return Update.Item;\r
303             }\r
304             return Update.None;\r
305         }\r
306 \r
307         private bool IsNormalBattleAPI(string url)\r
308         {\r
309             return url.EndsWith("api_req_sortie/battle") ||\r
310                    url.EndsWith("api_req_battle_midnight/battle") ||\r
311                    url.EndsWith("api_req_battle_midnight/sp_midnight");\r
312         }\r
313 \r
314         private bool IsCombinedBattleAPI(string url)\r
315         {\r
316             return url.EndsWith("api_req_combined_battle/battle") ||\r
317                    url.EndsWith("api_req_combined_battle/airbattle") ||\r
318                    url.EndsWith("api_req_combined_battle/battle_water") ||\r
319                    url.EndsWith("api_req_combined_battle/midnight_battle") ||\r
320                    url.EndsWith("api_req_combined_battle/sp_midnight");\r
321         }\r
322 \r
323         public NameAndTimer[] NDock\r
324         {\r
325             get { return _dockInfo.NDock; }\r
326         }\r
327 \r
328         public RingTimer[] KDock\r
329         {\r
330             get { return _dockInfo.KDock; }\r
331         }\r
332 \r
333         public ItemInfo Item\r
334         {\r
335             get { return _itemInfo; }\r
336         }\r
337 \r
338         public QuestInfo.NameAndProgress[] Quests\r
339         {\r
340             get { return _questInfo.Quests; }\r
341         }\r
342 \r
343         public NameAndTimer[] Missions\r
344         {\r
345             get { return _missionInfo.Missions; }\r
346         }\r
347 \r
348         public DateTime GetConditionTimer(int fleet)\r
349         {\r
350             return _conditionTimer.GetTimer(fleet);\r
351         }\r
352 \r
353         public int[] GetConditionNotice()\r
354         {\r
355             return _conditionTimer.GetNotice();\r
356         }\r
357 \r
358         public ShipStatus[] GetShipStatuses(int fleet)\r
359         {\r
360             return _shipInfo.GetShipStatuses(fleet);\r
361         }\r
362 \r
363         public int[] GetDeck(int fleet)\r
364         {\r
365             return _shipInfo.GetDeck(fleet);\r
366         }\r
367 \r
368         public ChargeStatus[] ChargeStatuses\r
369         {\r
370             get { return _shipInfo.ChargeStatuses; }\r
371         }\r
372 \r
373         public int GetAirSuperiority(int fleet)\r
374         {\r
375             return _shipInfo.GetAirSuperiority(fleet);\r
376         }\r
377 \r
378         public double GetFleetLineOfSights(int fleet)\r
379         {\r
380             return _shipInfo.GetLineOfSights(fleet);\r
381         }\r
382 \r
383         public ShipStatus[] DamagedShipList\r
384         {\r
385             get { return _shipInfo.GetDamagedShipList(_dockInfo); }\r
386         }\r
387 \r
388         public ShipStatus[] ShipList\r
389         {\r
390             get { return _shipInfo.ShipList; }\r
391         }\r
392 \r
393         public ItemStatus[] ItemList\r
394         {\r
395             get { return _itemInfo.GetItemList(_shipInfo); }\r
396         }\r
397 \r
398         public AkashiTimer.RepairSpan[] GetAkashiTimers(int fleet)\r
399         {\r
400             return _akashiTimer.GetTimers(fleet);\r
401         }\r
402 \r
403         public string[] GetAkashiTimerNotice()\r
404         {\r
405             return _akashiTimer.GetNotice();\r
406         }\r
407 \r
408         public Achievement Achievement\r
409         {\r
410             get { return _achievement; }\r
411         }\r
412 \r
413         public BattleInfo Battle\r
414         {\r
415             get { return _battleInfo; }\r
416         }\r
417 \r
418         public void SetLogWriter(Action<string, string, string> writer, Func<DateTime> nowFunc)\r
419         {\r
420             _logger.SetWriter(writer, nowFunc);\r
421         }\r
422 \r
423         public void SkipMaster()\r
424         {\r
425             _start = true;\r
426         }\r
427 \r
428         public void EnableLog(LogType type)\r
429         {\r
430             _logger.EnableLog(type);\r
431         }\r
432 \r
433         public int MaterialLogInterval\r
434         {\r
435             set { _logger.MaterialLogInterval = value; }\r
436         }\r
437 \r
438         public string LogOutputDir\r
439         {\r
440             set { _logger.OutputDir = value; }\r
441         }\r
442     }\r
443 \r
444     public class NameAndTimer\r
445     {\r
446         public string Name { get; set; }\r
447         public RingTimer Timer { get; set; }\r
448 \r
449         public NameAndTimer()\r
450         {\r
451             Timer = new RingTimer();\r
452         }\r
453     }\r
454 \r
455     public class RingTimer\r
456     {\r
457         private DateTime _endTime;\r
458         private readonly TimeSpan _spare;\r
459 \r
460         public TimeSpan Rest { get; private set; }\r
461 \r
462         public bool IsFinished\r
463         {\r
464             get { return _endTime != DateTime.MinValue && Rest <= _spare; }\r
465         }\r
466 \r
467         public bool NeedRing { get; set; }\r
468 \r
469         public RingTimer(int spare = 60)\r
470         {\r
471             _spare = TimeSpan.FromSeconds(spare);\r
472         }\r
473 \r
474         public void SetEndTime(double time)\r
475         {\r
476             SetEndTime((int)time == 0\r
477                 ? DateTime.MinValue\r
478                 : new DateTime(1970, 1, 1).ToLocalTime().AddSeconds(time / 1000));\r
479         }\r
480 \r
481         public void SetEndTime(DateTime time)\r
482         {\r
483             _endTime = time;\r
484         }\r
485 \r
486         public void Update()\r
487         {\r
488             if (_endTime == DateTime.MinValue)\r
489             {\r
490                 Rest = TimeSpan.Zero;\r
491                 return;\r
492             }\r
493             var prev = Rest;\r
494             Rest = _endTime - DateTime.Now;\r
495             if (Rest < TimeSpan.Zero)\r
496                 Rest = TimeSpan.Zero;\r
497             if (prev > _spare && _spare >= Rest)\r
498                 NeedRing = true;\r
499         }\r
500     }\r
501 }