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.InBattle = false;\r
115                 _battleInfo.HasDamagedShip = false;\r
116                 _shipInfo.ClearEscapedShips();\r
117                 SaveState();\r
118                 return Update.All;\r
119             }\r
120             if (url.EndsWith("api_get_member/basic"))\r
121             {\r
122                 _itemInfo.InspectBasic(data);\r
123                 _logger.InspectBasic(data);\r
124                 return Update.None;\r
125             }\r
126             if (url.EndsWith("api_get_member/slot_item"))\r
127             {\r
128                 _itemInfo.InspectSlotItem(data, true);\r
129                 return Update.None;\r
130             }\r
131             if (url.EndsWith("api_get_member/kdock"))\r
132             {\r
133                 _dockInfo.InspectKDock(data);\r
134                 _logger.InspectKDock(data);\r
135                 return Update.Timer;\r
136             }\r
137             if (url.EndsWith("api_get_member/ndock"))\r
138             {\r
139                 _dockInfo.InspectNDock(data);\r
140                 _conditionTimer.CheckCond();\r
141                 _akashiTimer.SetTimer();\r
142                 return Update.NDock | Update.Timer | Update.Ship;\r
143             }\r
144             if (url.EndsWith("api_req_hensei/change"))\r
145             {\r
146                 _shipInfo.InspectChange(request);\r
147                 _akashiTimer.SetTimer();\r
148                 return Update.Ship;\r
149             }\r
150             if (url.EndsWith("api_get_member/questlist"))\r
151             {\r
152                 _questInfo.Inspect(data);\r
153                 return Update.QuestList;\r
154             }\r
155             if (url.EndsWith("api_get_member/deck"))\r
156             {\r
157                 _shipInfo.InspectDeck(data);\r
158                 _missionInfo.InspectDeck(data);\r
159                 _akashiTimer.SetTimer();\r
160                 return Update.Mission | Update.Timer;\r
161             }\r
162             if (url.EndsWith("api_get_member/ship2"))\r
163             {\r
164                 // ここだけjsonなので注意\r
165                 _shipInfo.InspectShip(json);\r
166                 _akashiTimer.SetTimer();\r
167                 _battleInfo.InBattle = false;\r
168                 return Update.Item | Update.Ship | Update.Battle;\r
169             }\r
170             if (url.EndsWith("api_get_member/ship3"))\r
171             {\r
172                 _shipInfo.InspectShip(data);\r
173                 _akashiTimer.SetTimer();\r
174                 _conditionTimer.CheckCond();\r
175                 return Update.Ship;\r
176             }\r
177             if (url.EndsWith("api_get_member/material"))\r
178             {\r
179                 _itemInfo.InspectMaterial(data);\r
180                 return Update.Item;\r
181             }\r
182             if (url.EndsWith("api_req_hokyu/charge"))\r
183             {\r
184                 _shipInfo.InspectCharge(data);\r
185                 return Update.Item | Update.Ship;\r
186             }\r
187             if (url.EndsWith("api_req_kousyou/createitem"))\r
188             {\r
189                 _itemInfo.InspectCreateItem(data);\r
190                 _logger.InspectCreateItem(request, data);\r
191                 return Update.Item;\r
192             }\r
193             if (url.EndsWith("api_req_kousyou/getship"))\r
194             {\r
195                 _itemInfo.InspectGetShip(data);\r
196                 _shipInfo.InspectShip(data);\r
197                 _dockInfo.InspectKDock(data.api_kdock);\r
198                 _conditionTimer.CheckCond();\r
199                 return Update.Item | Update.Timer;\r
200             }\r
201             if (url.EndsWith("api_req_kousyou/destroyship"))\r
202             {\r
203                 _shipInfo.InspectDestroyShip(request, data);\r
204                 _conditionTimer.CheckCond();\r
205                 _akashiTimer.SetTimer();\r
206                 return Update.Item | Update.Ship;\r
207             }\r
208             if (url.EndsWith("api_req_kousyou/destroyitem2"))\r
209             {\r
210                 _itemInfo.InspectDestroyItem(request, data);\r
211                 return Update.Item;\r
212             }\r
213             if (url.EndsWith("api_req_kousyou/remodel_slot"))\r
214             {\r
215                 _itemInfo.InspectRemodelSlot(data);\r
216                 return Update.Item;\r
217             }\r
218             if (url.EndsWith("api_req_kousyou/createship"))\r
219             {\r
220                 _logger.InspectCreateShip(request);\r
221                 return Update.None;\r
222             }\r
223             if (url.EndsWith("api_req_kaisou/powerup"))\r
224             {\r
225                 _shipInfo.InspectPowerup(request, data);\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/start"))\r
231             {\r
232                 _dockInfo.InspectNyukyo(request);\r
233                 _conditionTimer.CheckCond();\r
234                 _akashiTimer.SetTimer();\r
235                 return Update.Item | Update.Ship;\r
236             }\r
237             if (url.EndsWith("api_req_nyukyo/speedchange"))\r
238             {\r
239                 _dockInfo.InspectSpeedChange(request);\r
240                 _conditionTimer.CheckCond();\r
241                 return Update.NDock | Update.Timer | Update.Ship;\r
242             }\r
243             if (IsNormalBattleAPI(url))\r
244             {\r
245                 _battleInfo.InspectBattle(data);\r
246                 _logger.InspectBattle(data);\r
247                 return Update.Ship | Update.Battle;\r
248             }\r
249             if (url.EndsWith("api_req_practice/battle") || url.EndsWith("api_req_practice/midnight_battle"))\r
250             {\r
251                 if (url.EndsWith("/battle"))\r
252                 {\r
253                     _shipInfo.StartSortie(request); // 演習を出撃中とみなす\r
254                     _conditionTimer.InvalidateCond();\r
255                 }\r
256                 _battleInfo.InspectBattle(data);\r
257                 return Update.Ship | Update.Battle | Update.Timer;\r
258             }\r
259             if (url.EndsWith("api_req_sortie/battleresult"))\r
260             {\r
261                 _battleInfo.InspectBattleResult(json);\r
262                 _logger.InspectBattleResult(data);\r
263                 return Update.Ship;\r
264             }\r
265             if (url.EndsWith("api_req_practice/battle_result"))\r
266             {\r
267                 _battleInfo.InspectPracticeResult(json);\r
268                 return Update.Ship;\r
269             }\r
270             if (IsCombinedBattleAPI(url))\r
271             {\r
272                 _battleInfo.InspectCombinedBattle(data, url.EndsWith("battle_water"));\r
273                 _logger.InspectBattle(data);\r
274                 return Update.Ship | Update.Battle;\r
275             }\r
276             if (url.EndsWith("api_req_combined_battle/battleresult"))\r
277             {\r
278                 _battleInfo.InspectCombinedBattleResult(data);\r
279                 _logger.InspectBattleResult(data);\r
280                 return Update.Ship;\r
281             }\r
282             if (url.EndsWith("api_req_combined_battle/goback_port"))\r
283             {\r
284                 _battleInfo.CauseCombinedBattleEscape();\r
285                 return Update.Ship;\r
286             }\r
287             if (url.EndsWith("api_req_map/start"))\r
288             {\r
289                 _shipInfo.StartSortie(request);\r
290                 _conditionTimer.InvalidateCond();\r
291                 _logger.InspectMapStart(data);\r
292                 return Update.Timer;\r
293             }\r
294             if (url.EndsWith("api_req_map/next"))\r
295             {\r
296                 _logger.InspectMapNext(data);\r
297                 return Update.None;\r
298             }\r
299             if (url.EndsWith("api_req_mission/result"))\r
300             {\r
301                 _itemInfo.InspectMissionResult(data);\r
302                 _logger.InspectMissionResult(data);\r
303                 return Update.Item;\r
304             }\r
305             return Update.None;\r
306         }\r
307 \r
308         private bool IsNormalBattleAPI(string url)\r
309         {\r
310             return url.EndsWith("api_req_sortie/battle") ||\r
311                    url.EndsWith("api_req_sortie/airbattle") ||\r
312                    url.EndsWith("api_req_battle_midnight/battle") ||\r
313                    url.EndsWith("api_req_battle_midnight/sp_midnight");\r
314         }\r
315 \r
316         private bool IsCombinedBattleAPI(string url)\r
317         {\r
318             return url.EndsWith("api_req_combined_battle/battle") ||\r
319                    url.EndsWith("api_req_combined_battle/airbattle") ||\r
320                    url.EndsWith("api_req_combined_battle/battle_water") ||\r
321                    url.EndsWith("api_req_combined_battle/midnight_battle") ||\r
322                    url.EndsWith("api_req_combined_battle/sp_midnight");\r
323         }\r
324 \r
325         public NameAndTimer[] NDock\r
326         {\r
327             get { return _dockInfo.NDock; }\r
328         }\r
329 \r
330         public RingTimer[] KDock\r
331         {\r
332             get { return _dockInfo.KDock; }\r
333         }\r
334 \r
335         public ItemInfo Item\r
336         {\r
337             get { return _itemInfo; }\r
338         }\r
339 \r
340         public QuestStatus[] Quests\r
341         {\r
342             get { return _questInfo.Quests; }\r
343         }\r
344 \r
345         public NameAndTimer[] Missions\r
346         {\r
347             get { return _missionInfo.Missions; }\r
348         }\r
349 \r
350         public DateTime GetConditionTimer(int fleet)\r
351         {\r
352             return _conditionTimer.GetTimer(fleet);\r
353         }\r
354 \r
355         public int[] GetConditionNotice()\r
356         {\r
357             return _conditionTimer.GetNotice();\r
358         }\r
359 \r
360         public ShipStatus[] GetShipStatuses(int fleet)\r
361         {\r
362             return _shipInfo.GetShipStatuses(fleet);\r
363         }\r
364 \r
365         public int[] GetDeck(int fleet)\r
366         {\r
367             return _shipInfo.GetDeck(fleet);\r
368         }\r
369 \r
370         public ChargeStatus[] ChargeStatuses\r
371         {\r
372             get { return _shipInfo.ChargeStatuses; }\r
373         }\r
374 \r
375         public int GetFighterPower(int fleet)\r
376         {\r
377             return _shipInfo.GetFighterPower(fleet);\r
378         }\r
379 \r
380         public double GetFleetLineOfSights(int fleet)\r
381         {\r
382             return _shipInfo.GetLineOfSights(fleet);\r
383         }\r
384 \r
385         public ShipStatus[] DamagedShipList\r
386         {\r
387             get { return _shipInfo.GetDamagedShipList(_dockInfo); }\r
388         }\r
389 \r
390         public ShipStatus[] ShipList\r
391         {\r
392             get { return _shipInfo.ShipList; }\r
393         }\r
394 \r
395         public ItemStatus[] ItemList\r
396         {\r
397             get\r
398             {\r
399                 _itemInfo.SetItemOwner(ShipList);\r
400                 return (from e in _itemInfo.ItemDict where e.Key != -1 select e.Value).ToArray();\r
401             }\r
402         }\r
403 \r
404         public AkashiTimer.RepairSpan[] GetAkashiTimers(int fleet)\r
405         {\r
406             return _akashiTimer.GetTimers(fleet);\r
407         }\r
408 \r
409         public string[] GetAkashiTimerNotice()\r
410         {\r
411             return _akashiTimer.GetNotice();\r
412         }\r
413 \r
414         public Achievement Achievement\r
415         {\r
416             get { return _achievement; }\r
417         }\r
418 \r
419         public BattleInfo Battle\r
420         {\r
421             get { return _battleInfo; }\r
422         }\r
423 \r
424         public void SetLogWriter(Action<string, string, string> writer, Func<DateTime> nowFunc)\r
425         {\r
426             _logger.SetWriter(writer, nowFunc);\r
427         }\r
428 \r
429         public void SkipMaster()\r
430         {\r
431             _start = true;\r
432         }\r
433 \r
434         public void EnableLog(LogType type)\r
435         {\r
436             _logger.EnableLog(type);\r
437         }\r
438 \r
439         public int MaterialLogInterval\r
440         {\r
441             set { _logger.MaterialLogInterval = value; }\r
442         }\r
443 \r
444         public string LogOutputDir\r
445         {\r
446             set { _logger.OutputDir = value; }\r
447         }\r
448     }\r
449 \r
450     public class NameAndTimer\r
451     {\r
452         public string Name { get; set; }\r
453         public RingTimer Timer { get; set; }\r
454 \r
455         public NameAndTimer()\r
456         {\r
457             Timer = new RingTimer();\r
458         }\r
459     }\r
460 \r
461     public class RingTimer\r
462     {\r
463         private DateTime _endTime;\r
464         private readonly TimeSpan _spare;\r
465 \r
466         public TimeSpan Rest { get; private set; }\r
467 \r
468         public bool IsFinished\r
469         {\r
470             get { return _endTime != DateTime.MinValue && Rest <= _spare; }\r
471         }\r
472 \r
473         public bool NeedRing { get; set; }\r
474 \r
475         public RingTimer(int spare = 60)\r
476         {\r
477             _spare = TimeSpan.FromSeconds(spare);\r
478         }\r
479 \r
480         public void SetEndTime(double time)\r
481         {\r
482             SetEndTime((int)time == 0\r
483                 ? DateTime.MinValue\r
484                 : new DateTime(1970, 1, 1).ToLocalTime().AddSeconds(time / 1000));\r
485         }\r
486 \r
487         public void SetEndTime(DateTime time)\r
488         {\r
489             _endTime = time;\r
490         }\r
491 \r
492         public void Update()\r
493         {\r
494             if (_endTime == DateTime.MinValue)\r
495             {\r
496                 Rest = TimeSpan.Zero;\r
497                 return;\r
498             }\r
499             var prev = Rest;\r
500             Rest = _endTime - DateTime.Now;\r
501             if (Rest < TimeSpan.Zero)\r
502                 Rest = TimeSpan.Zero;\r
503             if (prev > _spare && _spare >= Rest)\r
504                 NeedRing = true;\r
505         }\r
506     }\r
507 }