OSDN Git Service

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