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