OSDN Git Service

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