-using System.Linq;\r
+// Copyright (C) 2018 Kazuhiro Fujieda <fujieda@users.osdn.me>\r
+//\r
+// Licensed under the Apache License, Version 2.0 (the "License");\r
+// you may not use this file except in compliance with the License.\r
+// You may obtain a copy of the License at\r
+//\r
+// http://www.apache.org/licenses/LICENSE-2.0\r
+//\r
+// Unless required by applicable law or agreed to in writing, software\r
+// distributed under the License is distributed on an "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+// See the License for the specific language governing permissions and\r
+// limitations under the License.\r
+\r
+using System.Linq;\r
using ExpressionToCodeLib;\r
-using KancolleSniffer.Net;\r
+using KancolleSniffer.Log;\r
using Microsoft.VisualStudio.TestTools.UnitTesting;\r
\r
namespace KancolleSniffer.Test\r
input[15] = "綾波改二(Lv148)";\r
input[16] = "20/37";\r
input[37] = "制空権確保";\r
- var result = BattleLogProcessor.Process(input).ToArray();\r
+ var result = new BattleLogProcessor().Process(input);\r
PAssert.That(() => result[5] == "T字有利");\r
PAssert.That(() => result[23] == "龍鳳改(Lv97)・夕立改(Lv148)");\r
PAssert.That(() => result[38] == "確保");\r
input[11] = "龍鳳改(Lv97)・夕立改(Lv148)";\r
input[12] = "3/48・5/36";\r
input[37] = "航空劣勢";\r
- var result = BattleLogProcessor.Process(input).ToArray();\r
+ var result = new BattleLogProcessor().Process(input);\r
PAssert.That(() => result[6] == "第四警戒");\r
PAssert.That(() => result[23] == "龍鳳改(Lv97)・夕立改(Lv148)");\r
PAssert.That(() => result[38] == "劣勢");\r
input[12] = "3/48・";\r
input[13] = "・夕立改(Lv148)";\r
input[14] = "・5/36";\r
- var result = BattleLogProcessor.Process(input).ToArray();\r
+ var result = new BattleLogProcessor().Process(input);\r
PAssert.That(() => result[23] == "龍鳳改(Lv97)・夕立改(Lv148)");\r
}\r
\r
var input = Enumerable.Repeat("", 38).ToArray();\r
input[11] = "Luigi Torelli(ルイージ・トレッリ)(Lv7)";\r
input[12] = "2/11";\r
- var result = BattleLogProcessor.Process(input).ToArray();\r
+ var result = new BattleLogProcessor().Process(input);\r
PAssert.That(() => result[11] == "Luigi Torelli(Lv7)");\r
PAssert.That(() => result[23] == "Luigi Torelli(Lv7)");\r
}\r
"潜水カ級(flagship)", "0/37", "潜水カ級(elite)", "0/27", "潜水カ級(elite)", "0/27", "", "", "", "", "590", "0",\r
"制空権確保"\r
};\r
- var result = BattleLogProcessor.Process(input).ToArray();\r
+ var result = new BattleLogProcessor().Process(input);\r
PAssert.That(() => result[21] == "潮改二(Lv94)・龍驤改二(Lv99)" &&\r
result[22] == "33/33・50/50");\r
PAssert.That(() => result.Length == 39);\r
<Compile Include="ErrorLogTest.cs" />\r
<Compile Include="FleetPanelTest.cs" />\r
<Compile Include="JsonTest.cs" />\r
+ <Compile Include="LogProcessorTest.cs" />\r
<Compile Include="NotificationManagerTest.cs" />\r
<Compile Include="QuestInfoTest.cs" />\r
<Compile Include="ShipLabelTest.cs" />\r
--- /dev/null
+// Copyright (C) 2018 Kazuhiro Fujieda <fujieda@users.osdn.me>\r
+//\r
+// Licensed under the Apache License, Version 2.0 (the "License");\r
+// you may not use this file except in compliance with the License.\r
+// You may obtain a copy of the License at\r
+//\r
+// http://www.apache.org/licenses/LICENSE-2.0\r
+//\r
+// Unless required by applicable law or agreed to in writing, software\r
+// distributed under the License is distributed on an "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+// See the License for the specific language governing permissions and\r
+// limitations under the License.\r
+\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using ExpressionToCodeLib;\r
+using KancolleSniffer.Log;\r
+using KancolleSniffer.Model;\r
+using Microsoft.VisualStudio.TestTools.UnitTesting;\r
+\r
+namespace KancolleSniffer.Test\r
+{\r
+ [TestClass]\r
+ public class LogProcessorTest\r
+ {\r
+ [ClassInitialize]\r
+ public static void Initialize(TestContext context)\r
+ {\r
+ ExpressionToCodeConfiguration.GlobalAssertionConfiguration = ExpressionToCodeConfiguration\r
+ .GlobalAssertionConfiguration.WithPrintedListLengthLimit(200).WithMaximumValueLength(1000);\r
+ }\r
+\r
+ /// <summary>\r
+ /// 遠征報告書は普通にJSONに変換する\r
+ /// </summary>\r
+ [TestMethod]\r
+ public void EnseiLog()\r
+ {\r
+ var processor = new LogProcessor();\r
+ var log = new[]\r
+ {\r
+ "2018-09-10 17:45:09,大成功,北方鼠輸送作戦,589,498,0,0,0,0,0",\r
+ "2018-09-10 17:53:34,成功,長距離練習航海,0,117,34,0,0,1,0"\r
+ };\r
+ var result = processor.Process(log, "遠征報告書.csv", DateTime.MinValue, DateTime.MaxValue, false);\r
+ PAssert.That(() => result.SequenceEqual(new[]\r
+ {\r
+ "[\"2018-09-10 17:45:09\",\"大成功\",\"北方鼠輸送作戦\",\"589\",\"498\",\"0\",\"0\",\"0\",\"0\",\"0\"]",\r
+ ",\n[\"2018-09-10 17:53:34\",\"成功\",\"長距離練習航海\",\"0\",\"117\",\"34\",\"0\",\"0\",\"1\",\"0\"]"\r
+ }));\r
+ }\r
+\r
+ /// <summary>\r
+ /// 資材ログは最後に現在値を示すレコードを追加する\r
+ /// </summary>\r
+ [TestMethod]\r
+ public void MaterialLogWithCurrentRecord()\r
+ {\r
+ var processor = new LogProcessor(new[]\r
+ {\r
+ new MaterialCount {Now = 2001}, new MaterialCount {Now = 2002}, new MaterialCount {Now = 2003},\r
+ new MaterialCount {Now = 2004},\r
+ new MaterialCount {Now = 201}, new MaterialCount {Now = 202}, new MaterialCount {Now = 203},\r
+ new MaterialCount {Now = 100}\r
+ });\r
+ var now = new DateTime(2018, 1, 1);\r
+ var log = "2018-09-10 20:36:34,294892,296784,259518,294588,2484,2975,2550,3";\r
+\r
+ var result = processor.Process(new[] {log}, "資材ログ.csv", DateTime.MinValue, DateTime.MaxValue, false, now)\r
+ .ToArray();\r
+ PAssert.That(() =>\r
+ result[0] ==\r
+ "[\"2018-09-10 20:36:34\",\"294892\",\"296784\",\"259518\",\"294588\",\"2484\",\"2975\",\"2550\",\"3\"]");\r
+ var date = Logger.FormatDateTime(now);\r
+ PAssert.That(() =>\r
+ result[1] ==\r
+ $",\n[\"{date}\",\"2001\",\"2002\",\"2003\",\"2004\",\"201\",\"202\",\"203\",\"100\"]", "現在値");\r
+ }\r
+\r
+ /// <summary>\r
+ /// 資材グラフの描画を高速化するために値をすべて数値にする\r
+ /// </summary>\r
+ [TestMethod]\r
+ public void MaterialLogInNumberType()\r
+ {\r
+ var processor = new LogProcessor();\r
+ var log = "2018-09-10 20:36:34,294892,296784,259518,294588,2484,2975,2550,3";\r
+\r
+ var result = processor.Process(new[] {log}, "資材ログ.csv", DateTime.MinValue, DateTime.MaxValue, true)\r
+ .ToArray();\r
+ PAssert.That(() => result.Length == 1, "現在値の出力なし");\r
+ PAssert.That(() => result[0] == "[1536579394000,294892,296784,259518,294588,2484,2975,2550,3]");\r
+ }\r
+\r
+ /// <summary>\r
+ /// 指定された範囲のログを出力する\r
+ /// </summary>\r
+ [TestMethod]\r
+ public void Range()\r
+ {\r
+ var log = new[]\r
+ {\r
+ "2018-09-09 23:58:35,66023314,0",\r
+ "2018-09-10 08:08:31,66023314,0",\r
+ "2018-09-10 11:03:01,66024154,0"\r
+ };\r
+ var processor = new LogProcessor();\r
+ Func<DateTime, DateTime, IEnumerable<string>> rangeProcessor =\r
+ (from, to) => processor.Process(log, "戦果.csv", from, to, false);\r
+\r
+ PAssert.That(\r
+ () => rangeProcessor(DateTime.MinValue, DateTime.MaxValue).SequenceEqual(new[]\r
+ {\r
+ "[\"2018-09-09 23:58:35\",\"66023314\",\"0\"]",\r
+ ",\n[\"2018-09-10 08:08:31\",\"66023314\",\"0\"]",\r
+ ",\n[\"2018-09-10 11:03:01\",\"66024154\",\"0\"]"\r
+ }));\r
+ PAssert.That(\r
+ () => rangeProcessor(DateTime.MinValue, new DateTime(2018, 9, 10)).SequenceEqual(new[]\r
+ {"[\"2018-09-09 23:58:35\",\"66023314\",\"0\"]"}\r
+ ));\r
+ PAssert.That(\r
+ () => rangeProcessor(new DateTime(2018, 9, 10), DateTime.MaxValue).SequenceEqual(new[]\r
+ {\r
+ "[\"2018-09-10 08:08:31\",\"66023314\",\"0\"]",\r
+ ",\n[\"2018-09-10 11:03:01\",\"66024154\",\"0\"]"\r
+ }));\r
+ PAssert.That(\r
+ () => rangeProcessor(new DateTime(2018, 9, 10), new DateTime(2018, 9, 10, 11, 0, 0)).SequenceEqual(new[]\r
+ {\r
+ "[\"2018-09-10 08:08:31\",\"66023314\",\"0\"]"\r
+ }));\r
+ }\r
+\r
+ /// <summary>\r
+ /// 想定と異なる日付フォーマットに対応する。\r
+ /// </summary>\r
+ [TestMethod]\r
+ public void DateFormat()\r
+ {\r
+ var processor = new LogProcessor();\r
+\r
+ var body = ",大型艦建造,まるゆ,潜水艦,1500,1500,2000,1000,1,0,瑞鶴改二甲(163),120";\r
+ var expected =\r
+ ",\"大型艦建造\",\"まるゆ\",\"潜水艦\",\"1500\",\"1500\",\"2000\",\"1000\",\"1\",\"0\",\"瑞鶴改二甲(163)\",\"120\"]";\r
+\r
+ Func<string, string> dateProcessor =\r
+ date => processor.Process(new[] {date + body}, "建造報告書", DateTime.MinValue, DateTime.MaxValue, false)\r
+ .First();\r
+ var era = "30-09-10 20:13:39";\r
+ PAssert.That(() => "[\"2018-09-10 20:13:39\"" + expected == dateProcessor(era), "和暦を西暦に直す");\r
+ var excel = "2018/9/10 20:13";\r
+ PAssert.That(() => "[\"2018-09-10 20:13:00\"" + expected == dateProcessor(excel), "Excelの形式から変換する");\r
+ }\r
+ }\r
+}
\ No newline at end of file
using System.Collections.Generic;\r
using System.IO;\r
using ExpressionToCodeLib;\r
+using KancolleSniffer.Log;\r
using KancolleSniffer.Util;\r
using Microsoft.VisualStudio.TestTools.UnitTesting;\r
using Moq;\r
<Reference Include="System.Xml" />\r
</ItemGroup>\r
<ItemGroup>\r
+ <Compile Include="Log\LogProcessor.cs" />\r
<Compile Include="Model\Achievement.cs" />\r
<Compile Include="Model\AkashiTimer.cs" />\r
<Compile Include="Model\AlarmCounter.cs" />\r
<Compile Include="Model\ItemSpec.cs" />\r
<Compile Include="Model\ItemStatus.cs" />\r
<Compile Include="Model\ShipSpec.cs" />\r
+ <Compile Include="Log\BattleLogProcessor.cs" />\r
<Compile Include="View\AntiAirPanel.cs">\r
<SubType>Component</SubType>\r
</Compile>\r
<SubType>Component</SubType>\r
</Compile>\r
<Compile Include="Util\JsonParser.cs" />\r
- <Compile Include="Logger.cs" />\r
+ <Compile Include="Log\Logger.cs" />\r
<Compile Include="Net\LogServer.cs" />\r
<Compile Include="Model\MaterialInfo.cs" />\r
<Compile Include="Model\MiscTextInfo.cs" />\r
--- /dev/null
+// Copyright (C) 2018 Kazuhiro Fujieda <fujieda@users.osdn.me>\r
+//\r
+// Licensed under the Apache License, Version 2.0 (the "License");\r
+// you may not use this file except in compliance with the License.\r
+// You may obtain a copy of the License at\r
+//\r
+// http://www.apache.org/licenses/LICENSE-2.0\r
+//\r
+// Unless required by applicable law or agreed to in writing, software\r
+// distributed under the License is distributed on an "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+// See the License for the specific language governing permissions and\r
+// limitations under the License.\r
+\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text.RegularExpressions;\r
+using KancolleSniffer.Model;\r
+\r
+namespace KancolleSniffer.Log\r
+{\r
+ public class BattleLogProcessor\r
+ {\r
+ public string[] Process(string[] data)\r
+ {\r
+ if (data.Length == 35)\r
+ data = data.Concat(Enumerable.Repeat("", 3)).ToArray();\r
+ if (data.Length == 40)\r
+ {\r
+ data = data.Take(21).Concat(new[] {data[21] + "・" + data[23], data[22] + "・" + data[24]})\r
+ .Concat(data.Skip(25)).ToArray();\r
+ }\r
+ else if (data.Length != 38)\r
+ {\r
+ return data;\r
+ }\r
+ if (data[5] == "T字戦(有利)")\r
+ data[5] = "T字有利";\r
+ if (data[5] == "T字戦(不利)")\r
+ data[5] = "T字不利";\r
+ if (data[6].EndsWith("航行序列"))\r
+ data[6] = data[6].Substring(0, 4);\r
+ if (data[7].EndsWith("航行序列"))\r
+ data[7] = data[7].Substring(0, 4);\r
+ data[37] = ShortenAirBattleResult(data[37]);\r
+ return AddDamagedShip(data);\r
+ }\r
+\r
+ private static string ShortenAirBattleResult(string result)\r
+ {\r
+ switch (result)\r
+ {\r
+ case "制空均衡":\r
+ return "均衡";\r
+ case "制空権確保":\r
+ return "確保";\r
+ case "航空優勢":\r
+ return "優勢";\r
+ case "航空劣勢":\r
+ return "劣勢";\r
+ case "制空権喪失":\r
+ return "喪失";\r
+ default:\r
+ return "";\r
+ }\r
+ }\r
+\r
+ private static string[] AddDamagedShip(string[] data)\r
+ {\r
+ var damaged = new List<string>();\r
+ for (var i = 11; i < 11 + 12; i += 2)\r
+ {\r
+ if (data[i] == "")\r
+ continue;\r
+ var ship = data[i] = StripKana(data[i]);\r
+ var hp = data[i + 1];\r
+ try\r
+ {\r
+ damaged.AddRange(from entry in ship.Split('・').Zip(hp.Split('・'), (s, h) => new {s, h})\r
+ where entry.h.Contains("/")\r
+ let nm = entry.h.Split('/').Select(int.Parse).ToArray()\r
+ where ShipStatus.CalcDamage(nm[0], nm[1]) == ShipStatus.Damage.Badly\r
+ select entry.s);\r
+ }\r
+ catch (FormatException)\r
+ {\r
+ return data;\r
+ }\r
+ }\r
+ return data.Take(23).Concat(new[] {string.Join("・", damaged)}).Concat(data.Skip(23)).ToArray();\r
+ }\r
+\r
+ private static readonly Regex Kana = new Regex(@"\([^)]+\)\(", RegexOptions.Compiled);\r
+\r
+ private static string StripKana(string name)\r
+ {\r
+ return Kana.Replace(name, "(");\r
+ }\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+// Copyright (C) 2018 Kazuhiro Fujieda <fujieda@users.osdn.me>\r
+//\r
+// Licensed under the Apache License, Version 2.0 (the "License");\r
+// you may not use this file except in compliance with the License.\r
+// You may obtain a copy of the License at\r
+//\r
+// http://www.apache.org/licenses/LICENSE-2.0\r
+//\r
+// Unless required by applicable law or agreed to in writing, software\r
+// distributed under the License is distributed on an "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+// See the License for the specific language governing permissions and\r
+// limitations under the License.\r
+\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Globalization;\r
+using System.IO;\r
+using System.Linq;\r
+using KancolleSniffer.Model;\r
+\r
+namespace KancolleSniffer.Log\r
+{\r
+ public class LogProcessor\r
+ {\r
+ private readonly MaterialCount[] _materialCount;\r
+ private readonly BattleLogProcessor _battleLogProcessor;\r
+\r
+ public LogProcessor(MaterialCount[] materialCount = null)\r
+ {\r
+ _materialCount = materialCount ?? new MaterialCount[0];\r
+ _battleLogProcessor = new BattleLogProcessor();\r
+ }\r
+\r
+ public IEnumerable<string> Process(IEnumerable<string> lines, string path, DateTime from, DateTime to,\r
+ bool number, DateTime now = default)\r
+ {\r
+ var fields = 0;\r
+ var battle = false;\r
+ var material = false;\r
+ switch (Path.GetFileNameWithoutExtension(path))\r
+ {\r
+ case "遠征報告書":\r
+ fields = 10;\r
+ break;\r
+ case "改修報告書":\r
+ fields = 15;\r
+ break;\r
+ case "海戦・ドロップ報告書":\r
+ fields = 39;\r
+ battle = true;\r
+ break;\r
+ case "開発報告書":\r
+ fields = 9;\r
+ break;\r
+ case "建造報告書":\r
+ fields = 12;\r
+ break;\r
+ case "資材ログ":\r
+ fields = 9;\r
+ material = true;\r
+ break;\r
+ case "戦果":\r
+ fields = 3;\r
+ break;\r
+ }\r
+ var delimiter = "";\r
+ foreach (var line in lines)\r
+ {\r
+ var data = line.Split(',');\r
+ var date = ParseDateTime(data[0]);\r
+ if (date == default)\r
+ continue;\r
+ if (to < date)\r
+ yield break;\r
+ if (date < from)\r
+ continue;\r
+ data[0] = Logger.FormatDateTime(date);\r
+ var entries = data;\r
+ if (material)\r
+ entries = data.Take(fields).ToArray();\r
+ if (battle)\r
+ entries = _battleLogProcessor.Process(data);\r
+ if (entries.Length != fields)\r
+ continue;\r
+ var result =\r
+ number\r
+ ? delimiter + "[" + JavaScriptTicks(date) + "," + string.Join(",", entries.Skip(1)) + "]"\r
+ : delimiter + "[\"" + string.Join("\",\"", entries) + "\"]";\r
+ delimiter = ",\n";\r
+ yield return result;\r
+ }\r
+ if (material && !number) // 資材の現在値を出力する\r
+ yield return delimiter + "[\"" + Logger.FormatDateTime(now) + "\",\"" +\r
+ string.Join("\",\"", _materialCount.Select(c => c.Now)) + "\"]";\r
+ }\r
+\r
+ private DateTime ParseDateTime(string dateTime)\r
+ {\r
+ if (DateTime.TryParseExact(dateTime, Logger.DateTimeFormat, CultureInfo.InvariantCulture,\r
+ DateTimeStyles.AssumeLocal, out var date))\r
+ {\r
+ return date;\r
+ }\r
+ // システムが和暦に設定されていて和暦が出力されてしまったケースを救う\r
+ if (dateTime[2] == '-')\r
+ {\r
+ if (!int.TryParse(dateTime.Substring(0, 2), out var year))\r
+ return default;\r
+ dateTime = 1988 + year + dateTime.Substring(2);\r
+ return DateTime.TryParseExact(dateTime, Logger.DateTimeFormat, CultureInfo.InvariantCulture,\r
+ DateTimeStyles.AssumeLocal, out date)\r
+ ? date\r
+ : default;\r
+ }\r
+ return DateTime.TryParse(dateTime, CultureInfo.CurrentCulture, DateTimeStyles.AssumeLocal, out date)\r
+ ? date\r
+ : default;\r
+ }\r
+\r
+ private long JavaScriptTicks(DateTime date) =>\r
+ (date.ToUniversalTime().Ticks - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks) /\r
+ TimeSpan.TicksPerMillisecond;\r
+ }\r
+}
\ No newline at end of file
using KancolleSniffer.Model;\r
using KancolleSniffer.Util;\r
\r
-namespace KancolleSniffer\r
+namespace KancolleSniffer.Log\r
{\r
[Flags]\r
public enum LogType\r
using System.Text.RegularExpressions;\r
using System.Threading.Tasks;\r
using System.Windows.Forms;\r
+using KancolleSniffer.Log;\r
using KancolleSniffer.Model;\r
using KancolleSniffer.Net;\r
using KancolleSniffer.Util;\r
public void ApplyLogSetting()\r
{\r
LogServer.OutputDir = _config.Log.OutputDir;\r
- LogServer.MaterialHistory = _sniffer.Material.MaterialHistory;\r
+ LogServer.LogProcessor = new LogProcessor(_sniffer.Material.MaterialHistory);\r
_sniffer.EnableLog(_config.Log.On ? LogType.All : LogType.None);\r
_sniffer.MaterialLogInterval = _config.Log.MaterialLogInterval;\r
_sniffer.LogOutputDir = _config.Log.OutputDir;\r
// limitations under the License.\r
\r
using System;\r
-using System.Collections.Generic;\r
-using System.Globalization;\r
using System.IO;\r
using System.Linq;\r
using System.Net.Sockets;\r
using System.Text;\r
-using System.Text.RegularExpressions;\r
-using KancolleSniffer.Model;\r
+using KancolleSniffer.Log;\r
using KancolleSniffer.Util;\r
\r
namespace KancolleSniffer.Net\r
set => _outputDir = value;\r
}\r
\r
- public static MaterialCount[] MaterialHistory { private get; set; }\r
+ public static LogProcessor LogProcessor { private get; set; }\r
\r
public static void Process(Socket client, string requestLine)\r
{\r
client.Send(((MemoryStream)header.BaseStream).ToArray());\r
}\r
var csv = path.Replace(".json", ".csv");\r
+ if (!File.Exists(csv))\r
+ return;\r
var encoding = Encoding.GetEncoding("Shift_JIS");\r
client.Send(encoding.GetBytes("{ \"data\": [\n"));\r
- var battle = false;\r
- var material = false;\r
try\r
{\r
- if (!File.Exists(csv))\r
- return;\r
- var records = 0;\r
- if (path.EndsWith("遠征報告書.json"))\r
- {\r
- records = 10;\r
- }\r
- else if (path.EndsWith("改修報告書.json"))\r
- {\r
- records = 15;\r
- }\r
- else if (path.EndsWith("海戦・ドロップ報告書.json"))\r
- {\r
- records = 39;\r
- battle = true;\r
- }\r
- else if (path.EndsWith("開発報告書.json"))\r
- {\r
- records = 9;\r
- }\r
- else if (path.EndsWith("建造報告書.json"))\r
- {\r
- records = 12;\r
- }\r
- else if (path.EndsWith("資材ログ.json"))\r
- {\r
- records = 9;\r
- material = true;\r
- }\r
- else if (path.EndsWith("戦果.json"))\r
- {\r
- records = 3;\r
- }\r
- var delimiter = "";\r
- foreach (var line in File.ReadLines(csv, encoding).Skip(1))\r
- {\r
- var data = line.Split(',');\r
- if (!DateTime.TryParseExact(data[0], Logger.DateTimeFormat, CultureInfo.InvariantCulture,\r
- DateTimeStyles.AssumeLocal, out var date))\r
- {\r
- // システムが和暦に設定されていて和暦が出力されてしまったケースを救う\r
- if (data[0][2] == '-')\r
- {\r
- if (!int.TryParse(data[0].Substring(0, 2), out var year))\r
- continue;\r
- data[0] = 1988 + year + data[0].Substring(2);\r
- if (!DateTime.TryParseExact(data[0], Logger.DateTimeFormat, CultureInfo.InvariantCulture,\r
- DateTimeStyles.AssumeLocal, out date))\r
- continue;\r
- }\r
- else if (DateTime.TryParse(data[0], CultureInfo.CurrentCulture,\r
- DateTimeStyles.AssumeLocal, out date))\r
- {\r
- data[0] = Logger.FormatDateTime(date);\r
- }\r
- else\r
- {\r
- continue;\r
- }\r
- }\r
- if (date < from || to < date)\r
- continue;\r
- IEnumerable<string> entries = data;\r
- if (material)\r
- entries = data.Take(9);\r
- if (battle)\r
- entries = BattleLogProcessor.Process(data);\r
- if (entries.Count() != records)\r
- continue;\r
- if (number)\r
- {\r
- var stamp = ((date.ToUniversalTime().Ticks -\r
- new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks) /\r
- TimeSpan.TicksPerMillisecond).ToString();\r
- client.Send(encoding.GetBytes(delimiter + "[" + stamp + "," +\r
- string.Join(",", entries.Skip(1)) + "]"));\r
- }\r
- else\r
- {\r
- client.Send(encoding.GetBytes(delimiter + "[\"" +\r
- string.Join("\",\"", entries) + "\"]"));\r
- }\r
- delimiter = ",\n";\r
- }\r
- if (material && !number)\r
- {\r
- client.Send(encoding.GetBytes(delimiter + "[\"" +\r
- string.Join("\",\"", GetCurrentMaterialRecord()) + "\"]"));\r
- }\r
+ foreach (var record in LogProcessor.Process(File.ReadLines(csv, encoding).Skip(1), csv, from, to, number))\r
+ client.Send(encoding.GetBytes(record));\r
}\r
finally\r
{\r
}\r
}\r
\r
- private static IEnumerable<string> GetCurrentMaterialRecord()\r
- {\r
- return new[] {Logger.FormatDateTime(DateTime.Now)}.Concat(MaterialHistory.Select(c => c.Now.ToString()));\r
- }\r
-\r
private static void SendFile(Socket client, string path, string mime)\r
{\r
using (var header = new StreamWriter(new MemoryStream(), Encoding.ASCII))\r
client.Send(Encoding.ASCII.GetBytes(pacFile));\r
}\r
}\r
-\r
- public static class BattleLogProcessor\r
- {\r
- public static IEnumerable<string> Process(string[] data)\r
- {\r
- if (data.Length == 35)\r
- data = data.Concat(Enumerable.Repeat("", 3)).ToArray();\r
- if (data.Length == 40)\r
- {\r
- data = data.Take(21).Concat(new[] {data[21] + "・" + data[23], data[22] + "・" + data[24]})\r
- .Concat(data.Skip(25)).ToArray();\r
- }\r
- else if (data.Length != 38)\r
- {\r
- return data;\r
- }\r
- if (data[5] == "T字戦(有利)")\r
- data[5] = "T字有利";\r
- if (data[5] == "T字戦(不利)")\r
- data[5] = "T字不利";\r
- if (data[6].EndsWith("航行序列"))\r
- data[6] = data[6].Substring(0, 4);\r
- if (data[7].EndsWith("航行序列"))\r
- data[7] = data[7].Substring(0, 4);\r
- data[37] = ShortenAirBattleResult(data[37]);\r
- return AddDamagedShip(data);\r
- }\r
-\r
- private static string ShortenAirBattleResult(string result)\r
- {\r
- switch (result)\r
- {\r
- case "制空均衡":\r
- return "均衡";\r
- case "制空権確保":\r
- return "確保";\r
- case "航空優勢":\r
- return "優勢";\r
- case "航空劣勢":\r
- return "劣勢";\r
- case "制空権喪失":\r
- return "喪失";\r
- default:\r
- return "";\r
- }\r
- }\r
-\r
- private static IEnumerable<string> AddDamagedShip(string[] data)\r
- {\r
- var damaged = new List<string>();\r
- for (var i = 11; i < 11 + 12; i += 2)\r
- {\r
- if (data[i] == "")\r
- continue;\r
- var ship = data[i] = StripKana(data[i]);\r
- var hp = data[i + 1];\r
- try\r
- {\r
- damaged.AddRange(from entry in ship.Split('・').Zip(hp.Split('・'), (s, h) => new {s, h})\r
- where entry.h.Contains("/")\r
- let nm = entry.h.Split('/').Select(int.Parse).ToArray()\r
- where ShipStatus.CalcDamage(nm[0], nm[1]) == ShipStatus.Damage.Badly\r
- select entry.s);\r
- }\r
- catch (FormatException)\r
- {\r
- return data;\r
- }\r
- }\r
- return data.Take(23).Concat(new[] {string.Join("・", damaged)}).Concat(data.Skip(23));\r
- }\r
-\r
- private static readonly Regex Kana = new Regex(@"\([^)]+\)\(", RegexOptions.Compiled);\r
-\r
- private static string StripKana(string name)\r
- {\r
- return Kana.Replace(name, "(");\r
- }\r
- }\r
}
\ No newline at end of file
using KancolleSniffer.Util;\r
using System.Collections.Generic;\r
using System.Linq;\r
+using KancolleSniffer.Log;\r
using KancolleSniffer.Model;\r
\r
namespace KancolleSniffer\r