--- /dev/null
+// Copyright (C) 2013 Kazuhiro Fujieda <fujieda@users.sourceforge.jp>\r
+// \r
+// This program is part of KancolleSniffer.\r
+//\r
+// KancolleSniffer is free software: you can redistribute it and/or modify\r
+// it under the terms of the GNU General Public License as published by\r
+// the Free Software Foundation, either version 3 of the License, or\r
+// (at your option) any later version.\r
+//\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+// GNU General Public License for more details.\r
+//\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, see <http://www.gnu.org/licenses/>.\r
+\r
+namespace KancolleSniffer\r
+{\r
+ public class ItemInfo\r
+ {\r
+ private int _nowShips;\r
+\r
+ public int NowShips\r
+ {\r
+ get { return _nowShips; }\r
+ set\r
+ {\r
+ if (MaxShips != 0)\r
+ {\r
+ var limit = MaxShips - MarginShips;\r
+ NeedRing = _nowShips < limit && value >= limit;\r
+ }\r
+ _nowShips = value;\r
+ }\r
+ }\r
+\r
+ public int MaxShips { get; set; }\r
+ public int MarginShips { get; set; }\r
+ public bool NeedRing { get; set; }\r
+ public int NowItems { get; set; }\r
+ public int MaxItems { get; set; }\r
+ public int NumBuckets { get; set; }\r
+\r
+ public bool TooManyShips\r
+ {\r
+ get { return MaxShips != 0 && NowShips >= MaxShips - MarginShips; }\r
+ }\r
+\r
+ public ItemInfo()\r
+ {\r
+ MarginShips = 4;\r
+ }\r
+\r
+ public void InspectBasic(dynamic json)\r
+ {\r
+ MaxShips = (int)json.api_max_chara;\r
+ MaxItems = (int)json.api_max_slotitem;\r
+ }\r
+ public void InspectRecord(dynamic json)\r
+ {\r
+ NowShips = (int)json.api_ship[0];\r
+ MaxShips = (int)json.api_ship[1];\r
+ NowItems = (int)json.api_slotitem[0];\r
+ MaxItems = (int)json.api_slotitem[1];\r
+ }\r
+\r
+ public void InspectMaterial(dynamic json)\r
+ {\r
+ foreach (var entry in json)\r
+ {\r
+ if ((int)entry.api_id != 6)\r
+ continue;\r
+ NumBuckets = (int)entry.api_value;\r
+ }\r
+ }\r
+\r
+ public void InspectSlotItem(dynamic json)\r
+ {\r
+ NowItems = ((object[])json).Length;\r
+ }\r
+ }\r
+}
\ No newline at end of file
<ErrorReport>prompt</ErrorReport>\r
<WarningLevel>4</WarningLevel>\r
<Prefer32Bit>false</Prefer32Bit>\r
+ <DocumentationFile>\r
+ </DocumentationFile>\r
</PropertyGroup>\r
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">\r
<PlatformTarget>AnyCPU</PlatformTarget>\r
<Compile Include="MainForm.Designer.cs">\r
<DependentUpon>MainForm.cs</DependentUpon>\r
</Compile>\r
+ <Compile Include="MissionInfo.cs" />\r
<Compile Include="Program.cs" />\r
<Compile Include="Properties\AssemblyInfo.cs" />\r
+ <Compile Include="QuestInfo.cs" />\r
+ <Compile Include="ShipInfo.cs" />\r
+ <Compile Include="Sniffer.cs" />\r
+ <Compile Include="ItemInfo.cs" />\r
<EmbeddedResource Include="MainForm.resx">\r
<DependentUpon>MainForm.cs</DependentUpon>\r
</EmbeddedResource>\r
// along with this program; if not, see <http://www.gnu.org/licenses/>.\r
\r
using System;\r
-using System.Collections.Generic;\r
using System.Drawing;\r
using System.Linq;\r
using System.Media;\r
using System.Runtime.InteropServices;\r
using System.Windows.Forms;\r
-using System.IO;\r
using Codeplex.Data;\r
using Fiddler;\r
\r
namespace KancolleSniffer\r
{\r
+ /// <summary>\r
+ /// メインフォーム\r
+ /// </summary>\r
public partial class MainForm : Form\r
{\r
- private readonly Dictionary<int, string> _missions = new Dictionary<int, string>();\r
- private readonly string[] _missionNames = new string[3];\r
- private readonly RingTimer[] _missionTimers = new RingTimer[3];\r
- private readonly RingTimer[] _ndocTimers = new RingTimer[4];\r
- private readonly int[] _ndocShips = new int[4];\r
- private readonly RingTimer[] _kdocTimers = new RingTimer[4];\r
- private int _maxShips;\r
- private int _nowShips;\r
- private int _maxItems;\r
- private int _nowItems;\r
- private readonly int[] _deckShips = new int[6];\r
- private readonly Dictionary<int, ShipState> _shipStatuses = new Dictionary<int, ShipState>();\r
- private readonly Dictionary<int, string> _shipNames = new Dictionary<int, string>();\r
- private readonly SortedDictionary<int, QuestState> _questList = new SortedDictionary<int, QuestState>();\r
- private DateTime _questLastUpdated;\r
- private bool _slotRinged;\r
- private bool _updateCond;\r
- private DateTime[] _condEndTime = new DateTime[3];\r
-\r
- private readonly string _shipNamesFile =\r
- Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), "shipnames.json");\r
-\r
- private readonly string _missionsFile =\r
- Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), "missions.json");\r
-\r
- private struct ShipState\r
- {\r
- public int ShipId { get; set; }\r
- public int Level { get; set; }\r
- public int ExpToNext { get; set; }\r
- public int MaxHp { get; set; }\r
- public int NowHp { get; set; }\r
- public int Cond { get; set; }\r
- }\r
-\r
- private struct QuestState\r
- {\r
- public string Name { get; set; }\r
- public int Progress { get; set; }\r
- }\r
+ private readonly Sniffer _sniffer = new Sniffer();\r
\r
public MainForm()\r
{\r
InitializeComponent();\r
FiddlerApplication.AfterSessionComplete += FiddlerApplication_AfterSessionComplete;\r
- for (var i = 0; i < _missionTimers.Length; i++)\r
- _missionTimers[i] = new RingTimer();\r
- for (var i = 0; i < _ndocTimers.Length; i++)\r
- _ndocTimers[i] = new RingTimer();\r
- for (var i = 0; i < _kdocTimers.Length; i++)\r
- _kdocTimers[i] = new RingTimer();\r
}\r
\r
private void FiddlerApplication_AfterSessionComplete(Session oSession)\r
if (!json.IsDefined("api_data"))\r
return;\r
json = json.api_data;\r
- if (oSession.url.EndsWith("api_get_member/ship"))\r
- {\r
- ParseShipData(json);\r
- }\r
- else if (oSession.uriContains("api_get_master/mission"))\r
- {\r
- ParseMission(json);\r
- }\r
- else if (oSession.uriContains("api_get_member/ndock"))\r
- {\r
- ParseNDock(json);\r
- Invoke(new Action(UpdateTimers));\r
- }\r
- else if (oSession.uriContains("api_get_member/kdock"))\r
- {\r
- ParseKDock(json);\r
- Invoke(new Action(UpdateTimers));\r
- }\r
- else if (oSession.uriContains("api_get_member/deck"))\r
- {\r
- if (!oSession.uriContains("deck_port"))\r
- _updateCond = true;\r
- ParseDeck(json);\r
- Invoke(new Action(UpdateShipInfo));\r
+ UpdateInfo update = _sniffer.Sniff(oSession.url, json);\r
+ if ((update & UpdateInfo.Item) != 0)\r
+ Invoke(new Action(UpdateItemInfo));\r
+ if ((update & UpdateInfo.Mission) != 0)\r
Invoke(new Action(UpdateMissionLabels));\r
- Invoke(new Action(UpdateTimers));\r
- }\r
- else if (oSession.uriContains("api_get_member/basic"))\r
- {\r
- _maxShips = (int)json.api_max_chara;\r
- _maxItems = (int)json.api_max_slotitem;\r
- Invoke(new Action(UpdateSlotCount));\r
- }\r
- else if (oSession.uriContains("api_get_member/record"))\r
- {\r
- _nowShips = (int)json.api_ship[0];\r
- _maxShips = (int)json.api_ship[1];\r
- _nowItems = (int)json.api_slotitem[0];\r
- _maxItems = (int)json.api_slotitem[1];\r
- Invoke(new Action(UpdateSlotCount));\r
- }\r
- else if (oSession.uriContains("api_get_member/material"))\r
- {\r
- foreach (var entry in json)\r
- {\r
- if ((int)entry.api_id != 6)\r
- continue;\r
- var backet = ((int)entry.api_value).ToString("D");\r
- Invoke(new Action<string>(text => labelNumOfBuckets.Text = text), backet);\r
- break;\r
- }\r
- }\r
- else if (oSession.uriContains("api_get_member/slotitem"))\r
- {\r
- ParseSlotItem(json);\r
- Invoke(new Action(UpdateSlotCount));\r
- }\r
- else if (oSession.uriContains("api_get_member/ship2"))\r
- {\r
- ParseShipStatus(json);\r
- Invoke(new Action(UpdateShipInfo));\r
- }\r
- else if (oSession.uriContains("api_get_member/ship3"))\r
- {\r
- var ship = json.api_ship_data;\r
- ParseShipStatus(ship);\r
+ if ((update & UpdateInfo.NDock) != 0)\r
+ Invoke(new Action(UpdateNDocLabels));\r
+ if ((update & UpdateInfo.Ship) != 0)\r
Invoke(new Action(UpdateShipInfo));\r
- }\r
- else if (oSession.uriContains("api_req_sortie/battleresult"))\r
- {\r
- if (!json.IsDefined("api_get_ship"))\r
- return;\r
- var entry = json.api_get_ship;\r
- _shipNames[(int)entry.api_ship_id] = (string)entry.api_ship_name;\r
- }\r
- else if (oSession.uriContains("api_get_member/questlist"))\r
- {\r
- ParseQuestList(json);\r
+ if ((update & UpdateInfo.Quest) != 0)\r
Invoke(new Action(UpdateQuestList));\r
- }\r
}\r
\r
private void Form1_Load(object sender, EventArgs e)\r
{\r
- LoadNames();\r
+ _sniffer.LoadNames();\r
FiddlerApplication.Startup(0, FiddlerCoreStartupFlags.RegisterAsSystemProxy);\r
}\r
\r
private void Form1_FormClosing(object sender, FormClosingEventArgs e)\r
{\r
FiddlerApplication.Shutdown();\r
- SaveNames();\r
+ _sniffer.SaveNames();\r
}\r
\r
private void timerMain_Tick(object sender, EventArgs e)\r
UpdateTimers();\r
}\r
\r
- private void ParseMission(dynamic json)\r
- {\r
- foreach (var entry in json)\r
- _missions[(int)entry.api_id] = (string)entry.api_name;\r
- }\r
-\r
- private void ParseShipData(dynamic json)\r
- {\r
- foreach (var entry in json)\r
- _shipNames[(int)entry.api_ship_id] = (string)entry.api_name;\r
- }\r
-\r
- private void LoadNames()\r
- {\r
- try\r
- {\r
- ParseMission(DynamicJson.Parse(File.ReadAllText(_missionsFile)));\r
- }\r
- catch (FileNotFoundException)\r
- {\r
- }\r
- try\r
- {\r
- ParseShipData(DynamicJson.Parse(File.ReadAllText(_shipNamesFile)));\r
- }\r
- catch (FileNotFoundException)\r
- {\r
- }\r
- }\r
-\r
- private void SaveNames()\r
- {\r
- var ship = from data in _shipNames select new {api_ship_id = data.Key, api_name = data.Value};\r
- File.WriteAllText(_shipNamesFile, DynamicJson.Serialize(ship));\r
-\r
- var mission = from data in _missions select new {api_id = data.Key, api_name = data.Value};\r
- File.WriteAllText(_missionsFile, DynamicJson.Serialize(mission));\r
- }\r
-\r
- private void ParseNDock(dynamic json)\r
- {\r
- foreach (var entry in json)\r
- {\r
- var id = (int)entry.api_id;\r
- _ndocTimers[id - 1].EndTime = (double)entry.api_complete_time;\r
- _ndocShips[id - 1] = (int)entry.api_ship_id;\r
- }\r
- Invoke(new Action(UpdateNDocLabels));\r
- }\r
-\r
- private void ParseKDock(dynamic json)\r
+ private void UpdateItemInfo()\r
{\r
- foreach (var entry in json)\r
+ var item = _sniffer.Item;\r
+ labelNumOfShips.Text = string.Format("{0:D}/{1:D}", item.NowShips, item.MaxShips);\r
+ labelNumOfShips.ForeColor = item.TooManyShips ? Color.Red : Color.Black;\r
+ if (item.NeedRing)\r
{\r
- var id = (int)entry.api_id;\r
- _kdocTimers[id - 1].EndTime = (double)entry.api_complete_time;\r
- }\r
- }\r
-\r
- private void ParseDeck(dynamic json)\r
- {\r
- foreach (var entry in json)\r
- {\r
- var id = (int)entry.api_id;\r
- if (id == 1)\r
- {\r
- Invoke((Action<string>)(text => labelFleet1.Text = text), (string)entry.api_name);\r
- for (var i = 0; i < _deckShips.Count(); i++)\r
- {\r
- var ship = (int)entry.api_ship[i];\r
- if (_deckShips[i] != ship)\r
- _updateCond = true;\r
- _deckShips[i] = ship;\r
- }\r
- continue;\r
- }\r
- id -= 2;\r
- var mission = entry.api_mission;\r
- if (mission[0] == 0)\r
- {\r
- _missionNames[id] = "";\r
- _missionTimers[id].EndTime = 0;\r
- continue;\r
- }\r
- string name;\r
- _missionNames[id] = _missions.TryGetValue((int)mission[1], out name) ? name : "不明";\r
- _missionTimers[id].EndTime = mission[2];\r
- }\r
- }\r
-\r
- private void ParseSlotItem(dynamic json)\r
- {\r
- _nowItems = ((object[])json).Count();\r
- }\r
-\r
- private void ParseShipStatus(dynamic json)\r
- {\r
- _shipStatuses.Clear();\r
- foreach (var entry in json)\r
- {\r
- var data = new ShipState\r
- {\r
- ShipId = (int)entry.api_ship_id,\r
- Level = (int)entry.api_lv,\r
- ExpToNext = (int)entry.api_exp[1],\r
- MaxHp = (int)entry.api_maxhp,\r
- NowHp = (int)entry.api_nowhp,\r
- Cond = (int)entry.api_cond\r
- };\r
- _shipStatuses[(int)entry.api_id] = data;\r
- }\r
- _nowShips = _shipStatuses.Count;\r
- if (!_updateCond)\r
- return;\r
- _updateCond = false;\r
- var cond = int.MaxValue;\r
- foreach (var id in _deckShips)\r
- {\r
- ShipState info;\r
- if (id == -1 || id == 0 || !_shipStatuses.TryGetValue(id, out info))\r
- continue;\r
- if (info.Cond < cond)\r
- cond = info.Cond;\r
- }\r
- if (cond != int.MaxValue)\r
- SetCondTimers(cond);\r
- }\r
-\r
- private void SetCondTimers(int cond)\r
- {\r
- _condEndTime[0] = CondTimerEndTime(cond, 30);\r
- _condEndTime[1] = CondTimerEndTime(cond, 40);\r
- _condEndTime[2] = CondTimerEndTime(cond, 49);\r
- }\r
-\r
- private DateTime CondTimerEndTime(int cond, int thresh)\r
- {\r
- return (cond < thresh) ? DateTime.Now.AddMinutes((thresh - cond + 2) / 3 * 3) : DateTime.MinValue;\r
- }\r
-\r
- private void ParseQuestList(dynamic json)\r
- {\r
- var resetTime = DateTime.Today.AddHours(5);\r
- if (DateTime.Now >= resetTime && _questLastUpdated < resetTime)\r
- {\r
- // 前日に未消化のデイリーを消す。\r
- _questList.Clear();\r
- _questLastUpdated = DateTime.Now;\r
- }\r
- foreach (var entry in json.api_list)\r
- {\r
- if (entry is double)\r
- continue;\r
- var id = (int)entry.api_no;\r
- var state = (int)entry.api_state;\r
- var progress = (int)entry.api_progress_flag;\r
- var name = (string)entry.api_title;\r
-\r
- switch (progress)\r
- {\r
- case 0:\r
- break;\r
- case 1:\r
- progress = 50;\r
- break;\r
- case 2:\r
- progress = 80;\r
- break;\r
- }\r
- switch (state)\r
- {\r
- case 2:\r
- _questList[id] = new QuestState {Name = name, Progress = progress};\r
- break;\r
- case 1:\r
- case 3:\r
- _questList.Remove(id);\r
- continue;\r
- }\r
- }\r
- }\r
-\r
- private void UpdateSlotCount()\r
- {\r
- labelNumOfShips.Text = string.Format("{0:D}/{1:D}", _nowShips, _maxShips);\r
- if (_maxShips == 0 || // recordよりship3の方が先なので0の場合がある。\r
- _nowShips < _maxShips - 4)\r
- {\r
- labelNumOfShips.ForeColor = Color.Black;\r
- _slotRinged = false;\r
- }\r
- else\r
- {\r
- labelNumOfShips.ForeColor = Color.Red;\r
- if (!_slotRinged)\r
- {\r
- Ring();\r
- _slotRinged = true;\r
- }\r
+ Ring();\r
+ item.NeedRing = false;\r
}\r
- labelNumOfEquips.Text = string.Format("{0:D}/{1:D}", _nowItems, _maxItems);\r
+ labelNumOfEquips.Text = string.Format("{0:D}/{1:D}", item.NowItems, item.MaxItems);\r
+ labelNumOfBuckets.Text = item.NumBuckets.ToString("D");\r
}\r
\r
private void UpdateMissionLabels()\r
{\r
var labels = new[] {labelMissionName1, labelMissionName2, labelMissionName3};\r
- for (var i = 0; i < 3; i++)\r
- labels[i].Text = _missionNames[i];\r
+ for (var i = 0; i < labels.Length; i++)\r
+ labels[i].Text = _sniffer.Missions[i].Name;\r
}\r
\r
private void UpdateNDocLabels()\r
{\r
var ship = new[] {labelRepairShip1, labelRepairShip2, labelRepairShip3, labelRepairShip4};\r
- var i = 0;\r
- foreach (var id in _ndocShips)\r
- {\r
- ShipState shipStatus;\r
- string text;\r
- ship[i++].Text = id == 0\r
- ? ""\r
- : _shipStatuses.TryGetValue(id, out shipStatus) &&\r
- _shipNames.TryGetValue(shipStatus.ShipId, out text)\r
- ? text\r
- : "不明";\r
- }\r
+ for (var i = 0; i < ship.Length; i++)\r
+ ship[i].Text = _sniffer.NDock[i].Name;\r
}\r
\r
private void UpdateShipInfo()\r
var cond = new[] {labelCond1, labelCond2, labelCond3, labelCond4, labelCond5, labelCond6};\r
var next = new[] {labelNextLv1, labelNextLv2, labelNextLv3, labelNextLv4, labelNextLv5, labelNextLv6};\r
\r
- if (_shipStatuses.Count == 0)\r
- return;\r
- for (var i = 0; i < _deckShips.Count(); i++)\r
+ var stats = _sniffer.ShipStatuses;\r
+ for (var i = 0; i < stats.Length; i++)\r
{\r
- var id = _deckShips[i];\r
- ShipState info;\r
- if (id == -1 || id == 0 || !_shipStatuses.TryGetValue(id, out info))\r
- {\r
- name[i].Text = "";\r
- lv[i].Text = "0";\r
- hp[i].Text = "0/0";\r
- hp[i].BackColor = DefaultBackColor;\r
- cond[i].Text = "0";\r
- cond[i].BackColor = DefaultBackColor;\r
- next[i].Text = "0";\r
- continue;\r
- }\r
- string text;\r
- name[i].Text = _shipNames.TryGetValue(info.ShipId, out text) ? text : "不明";\r
- lv[i].Text = info.Level.ToString("D");\r
- hp[i].Text = string.Format("{0:D}/{1:D}", info.NowHp, info.MaxHp);\r
- SetHpLavel(hp[i], info.NowHp, info.MaxHp);\r
- SetCondLabel(cond[i], info.Cond);\r
- next[i].Text = info.ExpToNext.ToString("D");\r
+ var stat = stats[i];\r
+ name[i].Text = stat.Name;\r
+ lv[i].Text = stat.Level.ToString("D");\r
+ hp[i].Text = string.Format("{0:D}/{1:D}", stat.NowHp, stat.MaxHp);\r
+ SetHpLavel(hp[i], stat.NowHp, stat.MaxHp);\r
+ SetCondLabel(cond[i], stat.Cond);\r
+ next[i].Text = stat.ExpToNext.ToString("D");\r
}\r
- UpdateSlotCount();\r
}\r
\r
private void SetHpLavel(Label label, int now, int max)\r
{\r
label.Text = string.Format("{0:D}/{1:D}", now, max);\r
- var damage = (double)now / max;\r
+ var damage = max == 0 ? 1 : (double)now / max;\r
label.BackColor = damage > 0.5 ? DefaultBackColor : damage > 0.25 ? Color.Orange : Color.Red;\r
}\r
\r
label.Text = cond.ToString("D");\r
label.BackColor = cond >= 50\r
? Color.Yellow\r
- : cond >= 30 ? DefaultBackColor : cond >= 20 ? Color.Orange : Color.Red;\r
+ : cond >= 30 || cond == 0\r
+ ? DefaultBackColor\r
+ : cond >= 20 ? Color.Orange : Color.Red;\r
}\r
\r
private void UpdateTimers()\r
{\r
var mission = new[] {labelMission1, labelMission2, labelMission3};\r
- var i = 0;\r
- foreach (var timer in _missionTimers)\r
+ for (var i = 0; i < mission.Length; i++)\r
{\r
+ var timer = _sniffer.Missions[i].Timer;\r
timer.Update();\r
- SetTimerLabel(timer, mission[i++]);\r
+ SetTimerLabel(timer, mission[i]);\r
if (!timer.NeedRing)\r
continue;\r
Ring();\r
timer.NeedRing = false;\r
}\r
var ndock = new[] {labelRepair1, labelRepair2, labelRepair3, labelRepair4};\r
- i = 0;\r
- foreach (var timer in _ndocTimers)\r
+ for (var i = 0; i < ndock.Length; i++)\r
{\r
+ var timer = _sniffer.NDock[i].Timer;\r
timer.Update();\r
- SetTimerLabel(timer, ndock[i++]);\r
+ SetTimerLabel(timer, ndock[i]);\r
if (!timer.NeedRing)\r
continue;\r
Ring();\r
timer.NeedRing = false;\r
}\r
var kdock = new[] {labelConstruct1, labelConstruct2, labelConstruct3, labelConstruct4};\r
- i = 0;\r
- foreach (var timer in _kdocTimers)\r
+ for (var i = 0; i < kdock.Length; i++)\r
{\r
+ var timer = _sniffer.KDock[i];\r
timer.Update();\r
- SetTimerLabel(timer, kdock[i++]);\r
+ SetTimerLabel(timer, kdock[i]);\r
if (!timer.NeedRing)\r
continue;\r
Ring();\r
{\r
var label = new[] {labelCondTimer1, labelCondTimer2, labelCondTimer3};\r
var now = DateTime.Now;\r
- for (var i = 0; i < label.Count(); i++)\r
+ for (var i = 0; i < label.Length; i++)\r
{\r
- var timer = _condEndTime[i];\r
+ var timer = _sniffer.RecoveryTimes[i];\r
label[i].Text = timer != DateTime.MinValue && timer > now ? (timer - now).ToString(@"mm\:ss") : "00:00";\r
}\r
}\r
var name = new[] {labelQuest1, labelQuest2, labelQuest3, labelQuest4, labelQuest5};\r
var progress = new[] {labelProgress1, labelProgress2, labelProgress3, labelProgress4, labelProgress5};\r
var i = 0;\r
- foreach (var quest in _questList.Values)\r
+ foreach (var quest in _sniffer.Quests)\r
{\r
- if (i == progress.Count())\r
+ if (i == progress.Length)\r
break;\r
name[i].Text = quest.Name;\r
progress[i++].Text = string.Format("{0:D}%", quest.Progress);\r
}\r
- for (; i < progress.Count(); i++)\r
+ for (; i < progress.Length; i++)\r
{\r
name[i].Text = "";\r
progress[i].Text = "";\r
\r
[DllImport("user32.dll")]\r
private static extern Int32 FlashWindowEx(ref FLASHWINFO pwfi);\r
-\r
- private class RingTimer\r
- {\r
- private bool _ringed;\r
- private DateTime _endTime;\r
- private TimeSpan _rest;\r
-\r
- public double EndTime\r
- {\r
- set\r
- {\r
-// ReSharper disable once CompareOfFloatsByEqualityOperator\r
- if (value != 0)\r
- _endTime = new DateTime(1970, 1, 1).ToLocalTime().AddSeconds(value / 1000);\r
- else\r
- {\r
- _endTime = DateTime.MinValue;\r
- _ringed = false;\r
- }\r
- }\r
- }\r
-\r
- public void Update()\r
- {\r
- if (_endTime == DateTime.MinValue)\r
- {\r
- _rest = TimeSpan.Zero;\r
- return;\r
- }\r
- _rest = _endTime - DateTime.Now;\r
- if (_rest < TimeSpan.Zero)\r
- _rest = TimeSpan.Zero;\r
- if (_rest >= TimeSpan.FromMinutes(1) || _ringed)\r
- return;\r
- _ringed = true;\r
- NeedRing = true;\r
- }\r
-\r
- public bool NeedRing { get; set; }\r
-\r
- public bool IsSet\r
- {\r
- get { return _endTime != DateTime.MinValue; }\r
- }\r
-\r
- public override string ToString()\r
- {\r
- return _rest.Days == 0 ? _rest.ToString(@"hh\:mm\:ss") : _rest.ToString(@"d\.hh\:mm");\r
- }\r
- }\r
}\r
}
\ No newline at end of file
--- /dev/null
+// Copyright (C) 2013 Kazuhiro Fujieda <fujieda@users.sourceforge.jp>\r
+// \r
+// This program is part of KancolleSniffer.\r
+//\r
+// KancolleSniffer is free software: you can redistribute it and/or modify\r
+// it under the terms of the GNU General Public License as published by\r
+// the Free Software Foundation, either version 3 of the License, or\r
+// (at your option) any later version.\r
+//\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+// GNU General Public License for more details.\r
+//\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, see <http://www.gnu.org/licenses/>.\r
+\r
+using System.Collections.Generic;\r
+using System.IO;\r
+using System.Linq;\r
+using System.Windows.Forms;\r
+using Codeplex.Data;\r
+\r
+namespace KancolleSniffer\r
+{\r
+ public class MissionInfo\r
+ {\r
+ private readonly Dictionary<int, string> _missionNames = new Dictionary<int, string>();\r
+ private readonly NameAndTimer[] _missions = new NameAndTimer[3];\r
+\r
+ private readonly string _missionNamesFile =\r
+ Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), "missions.json");\r
+\r
+ public MissionInfo()\r
+ {\r
+ for (var i = 0; i < _missions.Length; i++)\r
+ _missions[i] = new NameAndTimer();\r
+ }\r
+\r
+ public void InspectMission(dynamic json)\r
+ {\r
+ foreach (var entry in json)\r
+ _missionNames[(int)entry.api_id] = (string)entry.api_name;\r
+ }\r
+\r
+ public void LoadNames()\r
+ {\r
+ try\r
+ {\r
+ InspectMission(DynamicJson.Parse(File.ReadAllText(_missionNamesFile)));\r
+ }\r
+ catch (FileNotFoundException)\r
+ {\r
+ }\r
+ }\r
+\r
+ public void SaveNames()\r
+ {\r
+ var ship = from data in _missionNames select new {api_id = data.Key, api_name = data.Value};\r
+ File.WriteAllText(_missionNamesFile, DynamicJson.Serialize(ship));\r
+ }\r
+\r
+ public void InspectDeck(dynamic json)\r
+ {\r
+ foreach (var entry in json)\r
+ {\r
+ var id = (int)entry.api_id;\r
+ if (id == 1)\r
+ continue;\r
+ id -= 2;\r
+ var mission = entry.api_mission;\r
+ if (mission[0] == 0)\r
+ {\r
+ _missions[id].Name = "";\r
+ _missions[id].Timer.EndTime = 0;\r
+ continue;\r
+ }\r
+ string name;\r
+ _missions[id].Name = _missionNames.TryGetValue((int)mission[1], out name) ? name : "不明";\r
+ _missions[id].Timer.EndTime = mission[2];\r
+ }\r
+ }\r
+\r
+ public NameAndTimer[] Missions\r
+ {\r
+ get { return _missions; }\r
+ }\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+// Copyright (C) 2013 Kazuhiro Fujieda <fujieda@users.sourceforge.jp>\r
+// \r
+// This program is part of KancolleSniffer.\r
+//\r
+// KancolleSniffer is free software: you can redistribute it and/or modify\r
+// it under the terms of the GNU General Public License as published by\r
+// the Free Software Foundation, either version 3 of the License, or\r
+// (at your option) any later version.\r
+//\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+// GNU General Public License for more details.\r
+//\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, see <http://www.gnu.org/licenses/>.\r
+\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+\r
+namespace KancolleSniffer\r
+{\r
+ public class QuestInfo\r
+ {\r
+ private DateTime _lastCreared;\r
+ private readonly SortedDictionary<int, NameAndProgress> _quests = new SortedDictionary<int, NameAndProgress>();\r
+\r
+ public void Inspect(dynamic json)\r
+ {\r
+ var resetTime = DateTime.Today.AddHours(5);\r
+ if (DateTime.Now >= resetTime && _lastCreared < resetTime)\r
+ {\r
+ _quests.Clear(); // 前日に未消化のデイリーを消す。\r
+ _lastCreared = DateTime.Now;\r
+ }\r
+ foreach (var entry in json.api_list)\r
+ {\r
+ if (entry is double) // -1の場合がある。\r
+ continue;\r
+\r
+ var id = (int)entry.api_no;\r
+ var state = (int)entry.api_state;\r
+ var progress = (int)entry.api_progress_flag;\r
+ var name = (string)entry.api_title;\r
+\r
+ switch (progress)\r
+ {\r
+ case 0:\r
+ break;\r
+ case 1:\r
+ progress = 50;\r
+ break;\r
+ case 2:\r
+ progress = 80;\r
+ break;\r
+ }\r
+ switch (state)\r
+ {\r
+ case 2:\r
+ _quests[id] = new NameAndProgress {Name = name, Progress = progress};\r
+ break;\r
+ case 1:\r
+ case 3:\r
+ _quests.Remove(id);\r
+ continue;\r
+ }\r
+ }\r
+ }\r
+\r
+ public NameAndProgress[] Quests\r
+ {\r
+ get { return _quests.Values.ToArray(); }\r
+ }\r
+\r
+ public struct NameAndProgress\r
+ {\r
+ public string Name { get; set; }\r
+ public int Progress { get; set; }\r
+ }\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+// Copyright (C) 2013 Kazuhiro Fujieda <fujieda@users.sourceforge.jp>\r
+// \r
+// This program is part of KancolleSniffer.\r
+//\r
+// KancolleSniffer is free software: you can redistribute it and/or modify\r
+// it under the terms of the GNU General Public License as published by\r
+// the Free Software Foundation, either version 3 of the License, or\r
+// (at your option) any later version.\r
+//\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+// GNU General Public License for more details.\r
+//\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, see <http://www.gnu.org/licenses/>.\r
+\r
+using System;\r
+using System.Collections.Generic;\r
+using System.IO;\r
+using System.Linq;\r
+using System.Windows.Forms;\r
+using Codeplex.Data;\r
+\r
+namespace KancolleSniffer\r
+{\r
+ public class ShipInfo\r
+ {\r
+ private readonly Dictionary<int, string> _shipNames = new Dictionary<int, string>();\r
+ private readonly int[] _deck = {-1, -1, -1, -1, -1, -1};\r
+ private readonly Dictionary<int, ShipStatus> _shipInfo = new Dictionary<int, ShipStatus>();\r
+ private readonly DateTime[] _recoveryTimes = new DateTime[3];\r
+ private bool _updateRecoveryTimes;\r
+\r
+ private readonly string _shipNamesFile =\r
+ Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), "shipnames.json");\r
+\r
+ public string FleetName { get; set; }\r
+\r
+ public DateTime[] RecoveryTimes\r
+ {\r
+ get { return _recoveryTimes; }\r
+ }\r
+\r
+ public void InspectShip(dynamic json)\r
+ {\r
+ foreach (var entry in json)\r
+ _shipNames[(int)entry.api_ship_id] = (string)entry.api_name;\r
+ }\r
+\r
+ public void LoadNames()\r
+ {\r
+ try\r
+ {\r
+ InspectShip(DynamicJson.Parse(File.ReadAllText(_shipNamesFile)));\r
+ }\r
+ catch (FileNotFoundException)\r
+ {\r
+ }\r
+ }\r
+\r
+ public void SaveNames()\r
+ {\r
+ var ship = from data in _shipNames select new {api_ship_id = data.Key, api_name = data.Value};\r
+ File.WriteAllText(_shipNamesFile, DynamicJson.Serialize(ship));\r
+ }\r
+\r
+ public string GetNameByShipId(int shipId)\r
+ {\r
+ string name;\r
+ return _shipNames.TryGetValue(shipId, out name) ? name : "不明";\r
+ }\r
+\r
+ public string GetNameById(int id)\r
+ {\r
+ ShipStatus ship;\r
+ return _shipInfo.TryGetValue(id, out ship) ? GetNameByShipId(ship.ShipId) : "不明";\r
+ }\r
+\r
+ public void InspectBattleResult(dynamic json)\r
+ {\r
+ if (!json.IsDefined("api_get_ship")) // 艦娘がドロップしていない。\r
+ return;\r
+ var entry = json.api_get_ship;\r
+ _shipNames[(int)entry.api_ship_id] = (string)entry.api_ship_name;\r
+ }\r
+\r
+ public void InspectDeck(dynamic json, bool port)\r
+ {\r
+ if (!port)\r
+ _updateRecoveryTimes = true;\r
+\r
+ foreach (var entry in json)\r
+ {\r
+ var fleet = (int)entry.api_id;\r
+ if (fleet != 1)\r
+ continue;\r
+ FleetName = (string)entry.api_name;\r
+ for (var i = 0; i < _deck.Length; i++)\r
+ {\r
+ var id = (int)entry.api_ship[i];\r
+ if (_deck[i] == id)\r
+ continue;\r
+ _deck[i] = id;\r
+ _updateRecoveryTimes = true;\r
+ }\r
+ }\r
+ }\r
+\r
+ public int NumShips\r
+ {\r
+ get { return _shipInfo.Count; }\r
+ }\r
+\r
+ public void InspectShipInfo(dynamic json)\r
+ {\r
+ _shipInfo.Clear();\r
+ foreach (var entry in json)\r
+ {\r
+ _shipInfo[(int)entry.api_id] = new ShipStatus\r
+ {\r
+ ShipId = (int)entry.api_ship_id,\r
+ Level = (int)entry.api_lv,\r
+ ExpToNext = (int)entry.api_exp[1],\r
+ MaxHp = (int)entry.api_maxhp,\r
+ NowHp = (int)entry.api_nowhp,\r
+ Cond = (int)entry.api_cond\r
+ };\r
+ }\r
+ SetRecoveryTime();\r
+ }\r
+\r
+ private void SetRecoveryTime()\r
+ {\r
+ if (!_updateRecoveryTimes)\r
+ return;\r
+ var cond =\r
+ (from id in _deck where _shipInfo.ContainsKey(id) select _shipInfo[id].Cond).DefaultIfEmpty(49).Min();\r
+ var thresh = new[] { 30, 40, 49 };\r
+ for (var i = 0; i < thresh.Length; i++)\r
+ _recoveryTimes[i] = cond < thresh[i] ? DateTime.Now.AddMinutes((thresh[i] - cond + 2) / 3 * 3) : DateTime.MinValue; \r
+ }\r
+\r
+ public ShipStatus[] ShipStatuses\r
+ {\r
+ get\r
+ {\r
+ var result = new ShipStatus[_deck.Length];\r
+ for (var i = 0; i < _deck.Length; i++)\r
+ {\r
+ var id = _deck[i];\r
+ ShipStatus status;\r
+ if (id == -1 || !_shipInfo.TryGetValue(id, out status))\r
+ continue;\r
+ status.Name = GetNameByShipId(status.ShipId);\r
+ result[i] = status;\r
+ }\r
+ return result;\r
+ }\r
+ }\r
+ }\r
+\r
+ public struct ShipStatus\r
+ {\r
+ public int ShipId { get; set; }\r
+ public string Name { get; set; }\r
+ public int Level { get; set; }\r
+ public int ExpToNext { get; set; }\r
+ public int MaxHp { get; set; }\r
+ public int NowHp { get; set; }\r
+ public int Cond { get; set; }\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+// Copyright (C) 2013 Kazuhiro Fujieda <fujieda@users.sourceforge.jp>\r
+// \r
+// This program is part of KancolleSniffer.\r
+//\r
+// KancolleSniffer is free software: you can redistribute it and/or modify\r
+// it under the terms of the GNU General Public License as published by\r
+// the Free Software Foundation, either version 3 of the License, or\r
+// (at your option) any later version.\r
+//\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+// GNU General Public License for more details.\r
+//\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, see <http://www.gnu.org/licenses/>.\r
+\r
+using System;\r
+\r
+namespace KancolleSniffer\r
+{\r
+ [Flags]\r
+ public enum UpdateInfo\r
+ {\r
+ None = 0,\r
+ Item = 1,\r
+ Ship = 2,\r
+ Timer = 4,\r
+ Quest = 8,\r
+ NDock = 16,\r
+ Mission = 32\r
+ }\r
+\r
+ public class Sniffer\r
+ {\r
+ private readonly NameAndTimer[] _ndocInfo = new NameAndTimer[4];\r
+ private readonly RingTimer[] _kdocTimers = new RingTimer[4];\r
+ private readonly ItemInfo _itemInfo = new ItemInfo();\r
+ private readonly QuestInfo _questInfo = new QuestInfo();\r
+ private readonly MissionInfo _missionInfo = new MissionInfo();\r
+ private readonly ShipInfo _shipInfo = new ShipInfo();\r
+\r
+ public Sniffer()\r
+ {\r
+ for (var i = 0; i < _ndocInfo.Length; i++)\r
+ _ndocInfo[i] = new NameAndTimer();\r
+ for (var i = 0; i < _kdocTimers.Length; i++)\r
+ _kdocTimers[i] = new RingTimer();\r
+ }\r
+\r
+ public UpdateInfo Sniff(string uri, dynamic json)\r
+ {\r
+ if (uri.EndsWith("api_get_member/ship"))\r
+ {\r
+ _shipInfo.InspectShip(json);\r
+ return UpdateInfo.None;\r
+ }\r
+ if (uri.EndsWith("api_get_member/basic"))\r
+ {\r
+ _itemInfo.InspectBasic(json);\r
+ return UpdateInfo.Item;\r
+ }\r
+ if (uri.EndsWith("api_get_member/record"))\r
+ {\r
+ _itemInfo.InspectRecord(json);\r
+ return UpdateInfo.Item;\r
+ }\r
+ if (uri.EndsWith("api_get_member/material"))\r
+ {\r
+ _itemInfo.InspectMaterial(json);\r
+ return UpdateInfo.Item;\r
+ }\r
+ if (uri.EndsWith("api_get_member/slotitem"))\r
+ {\r
+ _itemInfo.InspectSlotItem(json);\r
+ return UpdateInfo.Item;\r
+ }\r
+ if (uri.EndsWith("api_get_member/questlist"))\r
+ {\r
+ _questInfo.Inspect(json);\r
+ return UpdateInfo.Quest;\r
+ }\r
+ if (uri.EndsWith("api_get_member/ndock"))\r
+ {\r
+ InspectNDock(json);\r
+ return UpdateInfo.NDock | UpdateInfo.Timer;\r
+ }\r
+ if (uri.EndsWith("api_get_member/kdock"))\r
+ {\r
+ InspectKDock(json);\r
+ return UpdateInfo.Timer;\r
+ }\r
+ if (uri.EndsWith("api_get_master/mission"))\r
+ {\r
+ _missionInfo.InspectMission(json);\r
+ return UpdateInfo.Mission;\r
+ }\r
+ if (uri.Contains("api_get_member/deck"))\r
+ {\r
+ _missionInfo.InspectDeck(json);\r
+ _shipInfo.InspectDeck(json, uri.EndsWith("deck_port"));\r
+ return UpdateInfo.Mission | UpdateInfo.Ship;\r
+ }\r
+ if (uri.EndsWith("api_req_sortie/battleresult"))\r
+ {\r
+ _shipInfo.InspectBattleResult(json);\r
+ return UpdateInfo.None;\r
+ }\r
+ if (uri.EndsWith("api_get_member/ship2") || uri.EndsWith("api_get_member/ship3"))\r
+ {\r
+ _shipInfo.InspectShipInfo(uri.EndsWith("ship3") ? json.api_ship_data : json);\r
+ _itemInfo.NowShips = _shipInfo.NumShips;\r
+ return UpdateInfo.Ship | UpdateInfo.Item | UpdateInfo.Timer;\r
+ }\r
+ return UpdateInfo.None;\r
+ }\r
+\r
+ public void SaveNames()\r
+ {\r
+ _missionInfo.SaveNames();\r
+ _shipInfo.SaveNames();\r
+ }\r
+\r
+ public void LoadNames()\r
+ {\r
+ _missionInfo.LoadNames();\r
+ _shipInfo.LoadNames();\r
+ }\r
+\r
+ private void InspectNDock(dynamic json)\r
+ {\r
+ foreach (var entry in json)\r
+ {\r
+ var id = (int)entry.api_id;\r
+ _ndocInfo[id - 1].Timer.EndTime = (double)entry.api_complete_time;\r
+ var ship = (int)entry.api_ship_id;\r
+ _ndocInfo[id - 1].Name = ship == 0 ? "" : _shipInfo.GetNameById(ship);\r
+ }\r
+ }\r
+\r
+ public NameAndTimer[] NDock\r
+ {\r
+ get { return _ndocInfo; }\r
+ }\r
+\r
+ private void InspectKDock(dynamic json)\r
+ {\r
+ foreach (var entry in json)\r
+ _kdocTimers[(int)entry.api_id - 1].EndTime = (double)entry.api_complete_time;\r
+ }\r
+\r
+ public RingTimer[] KDock\r
+ {\r
+ get { return _kdocTimers; }\r
+ }\r
+\r
+ public ItemInfo Item\r
+ {\r
+ get { return _itemInfo; }\r
+ }\r
+\r
+ public QuestInfo.NameAndProgress[] Quests\r
+ {\r
+ get { return _questInfo.Quests; }\r
+ }\r
+\r
+ public NameAndTimer[] Missions\r
+ {\r
+ get { return _missionInfo.Missions; }\r
+ }\r
+\r
+ public string FleetName\r
+ {\r
+ get { return _shipInfo.FleetName; }\r
+ }\r
+\r
+ public DateTime[] RecoveryTimes\r
+ {\r
+ get { return _shipInfo.RecoveryTimes; }\r
+ }\r
+\r
+ public ShipStatus[] ShipStatuses\r
+ {\r
+ get { return _shipInfo.ShipStatuses; }\r
+ }\r
+ }\r
+\r
+ public class NameAndTimer\r
+ {\r
+ public string Name { get; set; }\r
+\r
+ public RingTimer Timer { get; set; }\r
+\r
+ public NameAndTimer()\r
+ {\r
+ Timer = new RingTimer();\r
+ }\r
+ }\r
+\r
+ public class RingTimer\r
+ {\r
+ private bool _ringed;\r
+ private DateTime _endTime;\r
+ private TimeSpan _rest;\r
+\r
+ public double EndTime\r
+ {\r
+ set\r
+ {\r
+// ReSharper disable once CompareOfFloatsByEqualityOperator\r
+ if (value != 0)\r
+ _endTime = new DateTime(1970, 1, 1).ToLocalTime().AddSeconds(value / 1000);\r
+ else\r
+ {\r
+ _endTime = DateTime.MinValue;\r
+ _ringed = false;\r
+ }\r
+ }\r
+ }\r
+\r
+ public void Update()\r
+ {\r
+ if (_endTime == DateTime.MinValue)\r
+ {\r
+ _rest = TimeSpan.Zero;\r
+ return;\r
+ }\r
+ _rest = _endTime - DateTime.Now;\r
+ if (_rest < TimeSpan.Zero)\r
+ _rest = TimeSpan.Zero;\r
+ if (_rest >= TimeSpan.FromMinutes(1) || _ringed)\r
+ return;\r
+ _ringed = true;\r
+ NeedRing = true;\r
+ }\r
+\r
+ public bool NeedRing { get; set; }\r
+\r
+ public bool IsSet\r
+ {\r
+ get { return _endTime != DateTime.MinValue; }\r
+ }\r
+\r
+ public override string ToString()\r
+ {\r
+ return _rest.Days == 0 ? _rest.ToString(@"hh\:mm\:ss") : _rest.ToString(@"d\.hh\:mm");\r
+ }\r
+ }\r
+}
\ No newline at end of file