using System; using System.Collections.Generic; using System.Diagnostics; using System.Drawing; using System.IO; using System.Net; using System.Net.Sockets; using System.Runtime.InteropServices; using System.Text; namespace DutyContent { class DcConfig { public static int PluginTag => 34; public static Version PluginVersion => System.Reflection.Assembly.GetExecutingAssembly().GetName().Version; public static bool PluginEnable { get; set; } public static string PluginPath { get; set; } public static string DataPath { get; set; } // public static string ActConfigPath { get; set; } public static string PluginConfigPath { get; set; } // public static PacketConfig Packet = new PacketConfig(); public static DutyConfig Duty = new DutyConfig(); // public static ConnectionList Connections = new ConnectionList(); // public static string Language { get; set; } = ""; public static bool DataRemoteUpdate { get; set; } = true; // true = use remote update public static int LastUpdatedPlugin { get; set; } = 0; public static string UiFontFamily { get; set; } = "Microsoft Sans Serif"; public static bool StatusBar { get; set; } = false; public static bool DebugEnable { get; set; } = false; // public static int GameRegion { get; set; } = 0; // 0=SQ, 1=ACTOZ // public static string BuildDataFileName(string header, string context, string ext) { return Path.Combine(DataPath, $"{header}-{context}.{ext}"); } // public static string BuildDutyFileName(string language) { return BuildDataFileName("DcDuty", language, "json"); } // public static string BuildLangFileName(string language) { return BuildDataFileName("DcLang", language, "txt"); } // public static string BuildPacketFileName(string set) { return BuildDataFileName("DcPacket", set, "config"); } // public static void SaveConfig(string filename = null) { if (filename == null) filename = ActConfigPath; using (var sw = new StreamWriter(filename, false, Encoding.UTF8)) { sw.WriteLine("# DutyContent configuration: {0}", DateTime.Now.ToString()); sw.WriteLine(); sw.WriteLine("# config"); sw.WriteLine("Language={0}", Language); sw.WriteLine("DataRemoteUpdate={0}", DataRemoteUpdate); sw.WriteLine("LastUpdatedPlugin={0}", LastUpdatedPlugin); sw.WriteLine("UiFontFamily={0}", UiFontFamily); sw.WriteLine("StatusBar={0}", StatusBar); sw.WriteLine("DebugEnable={0}", DebugEnable); sw.WriteLine(); Duty.InternalSaveStream(sw); } } // public static void LoadConfig(string filename = null) { if (string.IsNullOrEmpty(filename)) { if (File.Exists(ActConfigPath)) filename = ActConfigPath; else { if (File.Exists(PluginConfigPath)) filename = PluginConfigPath; else { filename = ActConfigPath; SaveConfig(filename); } } } else if (!File.Exists(filename)) SaveConfig(filename); var db = new ThirdParty.LineDb(filename, Encoding.UTF8, false); Language = db["Language"]; DataRemoteUpdate = ThirdParty.Converter.ToBool(db["DataRemoteUpdate"], DataRemoteUpdate); LastUpdatedPlugin = ThirdParty.Converter.ToInt(db["LastUpdatedPlugin"]); UiFontFamily = db.Get("UiFontFamily", UiFontFamily); StatusBar = ThirdParty.Converter.ToBool(db["StatusBar"], StatusBar); DebugEnable = ThirdParty.Converter.ToBool(db["DebugEnable"], DebugEnable); Duty.InternalReadFromDb(db); } // public static void ReadLanguage(bool isInInit = false) { if (string.IsNullOrWhiteSpace(Language)) { if (!isInInit) Locale.Initialize(Properties.Resources.DefaultMessage); } else { string filename = BuildLangFileName(Language); if (File.Exists(filename)) Locale.LoadFile(filename); else Locale.Initialize(Properties.Resources.DefaultMessage); } } public static bool ReadPacket(string set = null) { if (set == null) set = Duty.PacketSet; else if (!Duty.PacketSet.Equals(set)) Duty.PacketSet = set; var filename = BuildPacketFileName(set); if (!File.Exists(filename)) { filename = BuildPacketFileName(set = PacketConfig.DefaultSetNameGlobal); if (!File.Exists(filename)) { filename = BuildPacketFileName(set = PacketConfig.DefaultSetNameCustom); if (!File.Exists(filename)) { Logger.E(27, " "); return false; } } if (!Duty.PacketSet.Equals(set)) Duty.PacketSet = set; } // load. if file not exist, create new one with default value Packet.Load(filename); Logger.Write(Packet.GetInformation()); return true; } // public class PacketConfig { // Packet public long Version { get; set; } = 2005580; public string Description { get; set; } = "5.58 (JP/NA/EU/OC)"; public ushort OpFate { get; set; } = 788; public ushort OpDuty { get; set; } = 676; public ushort OpMatch { get; set; } = 428; public ushort OpInstance { get; set; } = 234; public ushort OpZone { get; set; } = 369; public ushort OpCe { get; set; } = 269; // packet version structure // 0 - Service area (1:Custom, 2:Global, 3:Korea) // 1 - Reserved. Must be 0 // 2 - Expansion version // 3 // 4 - Update version // 5 // 6 - HotFix or packet version public static readonly string DefaultSetNameCustom = "Custom"; public static readonly string DefaultSetNameGlobal = "Global"; public PacketConfig() { // nothing to do } public PacketConfig(DateTime dt, PacketConfig right = null) { // for custom Version = ThirdParty.Converter.ToLong($"1{dt:yyMMdd}"); Description = $"Custom ({dt:d})"; if (right != null) { OpFate = right.OpFate; OpDuty = right.OpDuty; OpMatch = right.OpMatch; OpInstance = right.OpInstance; OpZone = right.OpZone; OpCe = right.OpCe; } else { OpFate = 0; OpDuty = 0; OpMatch = 0; OpInstance = 0; OpZone = 0; OpCe = 0; } } // public string GetInformation() { return Locale.Text(29, Version, Description); } // public override string ToString() { return GetInformation(); } // public bool Save(string filename) { if (filename == null) return false; using (var sw = new StreamWriter(filename, false, Encoding.UTF8)) { sw.WriteLine("# DutyPacket configuration: {0}", DateTime.Now.ToString()); sw.WriteLine(); sw.WriteLine("# packet"); sw.WriteLine("Version={0}", Version); sw.WriteLine("Description={0}", Description); sw.WriteLine("OpFate={0}", OpFate); sw.WriteLine("OpDuty={0}", OpDuty); sw.WriteLine("OpMatch={0}", OpMatch); sw.WriteLine("OpInstance={0}", OpInstance); sw.WriteLine("OpZone={0}", OpZone); sw.WriteLine("OpSouthernBozja={0}", OpCe); sw.WriteLine(); } return true; } private void InternalParseString(ThirdParty.LineDb db) { Version = ThirdParty.Converter.ToLong(db["Version"]); Description = db["Description"]; OpFate = ThirdParty.Converter.ToUshort(db["OpFate"], OpFate); OpDuty = ThirdParty.Converter.ToUshort(db["OpDuty"], OpDuty); OpMatch = ThirdParty.Converter.ToUshort(db["OpMatch"], OpMatch); OpInstance = ThirdParty.Converter.ToUshort(db["OpInstance"], OpInstance); OpZone = ThirdParty.Converter.ToUshort(db["OpZone"], OpZone); OpCe = ThirdParty.Converter.ToUshort(db["OpSouthernBozja"], OpCe); } // public void Load(string filename = null) { if (!File.Exists(filename)) Save(filename); var db = new ThirdParty.LineDb(filename, Encoding.UTF8, false); InternalParseString(db); } // public static PacketConfig ParseString(string ctx) { var pk = new PacketConfig(); var db = new ThirdParty.LineDb(ctx, false); pk.InternalParseString(db); return pk; } } // public class DutyConfig { public string Language { get; set; } = "English"; public int ActiveFate { get; set; } = 0; public string PacketSet { get; set; } = "Global"; public string LogFontFamily { get; set; } = "Microsoft Sans Serif"; public float LogFontSize { get; set; } = 12.0f; public bool EnableOverlay { get; set; } public Point OverlayLocation { get; set; } = new Point(0, 0); public bool OverlayClickThru { get; set; } public bool OverlayAutoHide { get; set; } public int OverlayAutoElapse { get; set; } = 20000; // 20x1000 public bool EnableSound { get; set; } public string SoundInstanceFile { get; set; } public int SoundInstanceVolume { get; set; } = 100; public string SoundFateFile { get; set; } public int SoundFateVolume { get; set; } = 100; public bool UseNotifyLine { get; set; } public string NotifyLineToken { get; set; } public bool UseNotifyTelegram { get; set; } public string NotifyTelegramId { get; set; } public string NotifyTelegramToken { get; set; } public bool UseNotifyDiscordWebhook { get; set; } public string NotifyDiscordWebhookUrl { get; set; } public bool NotifyDiscordWebhookTts { get; set; } public bool UsePing { get; set; } public Color[] PingColors { get; set; } = new Color[4] { Color.FromArgb(0xFF, 0x00, 0x00, 0x40), Color.FromArgb(0xFF, 0x40, 0x00, 0x80), Color.FromArgb(0xFF, 0x80, 0x40, 0x00), Color.FromArgb(0xFF, 0xDD, 0xA0, 0xDD), }; public bool PingGraph { get; set; } public bool PingShowLoss { get; set; } public string PingDefAddr { get; set; } public int PingGraphType { get; set; } public bool PacketForLocal { get; set; } // public bool EnableNotify => UseNotifyLine || UseNotifyTelegram || UseNotifyDiscordWebhook; // public FateSelection[] Fates { get; set; } = new FateSelection[4] { new FateSelection(0), new FateSelection(1), new FateSelection(2), new FateSelection(3), }; // internal void InternalSaveStream(StreamWriter sw) { sw.WriteLine("# duty"); sw.WriteLine("DutyLanguage={0}", Language); sw.WriteLine("DutyActiveFate={0}", ActiveFate); sw.WriteLine("DutyFate0={0}", Fates[0].Line); sw.WriteLine("DutyFate1={0}", Fates[1].Line); sw.WriteLine("DutyFate2={0}", Fates[2].Line); sw.WriteLine("DutyFate3={0}", Fates[3].Line); sw.WriteLine("DutypPacketSet={0}", PacketSet); sw.WriteLine("DutyLogFontFamily={0}", LogFontFamily); sw.WriteLine("DutyLogFontSize={0}", LogFontSize); sw.WriteLine("DutyEnableOverlay={0}", EnableOverlay); sw.WriteLine("DutyOverlayLocationX={0}", OverlayLocation.X); sw.WriteLine("DutyOverlayLocationY={0}", OverlayLocation.Y); sw.WriteLine("DutyOverlayClickThru={0}", OverlayClickThru); sw.WriteLine("DutyOverlayAutoHide={0}", OverlayAutoHide); sw.WriteLine("DutyEnableSound={0}", EnableSound); sw.WriteLine("DutySoundInstanceFile={0}", SoundInstanceFile); sw.WriteLine("DutySoundInstanceVolume={0}", SoundInstanceVolume); sw.WriteLine("DutySoundFateFile={0}", SoundFateFile); sw.WriteLine("DutySoundFateVolume={0}", SoundFateVolume); sw.WriteLine("DutyUseNotifyLine={0}", UseNotifyLine); sw.WriteLine("DutyNotifyLineToken={0}", NotifyLineToken); sw.WriteLine("DutyUseNotifyTelegram={0}", UseNotifyTelegram); sw.WriteLine("DutyNotifyTelegramId={0}", NotifyTelegramId); sw.WriteLine("DutyNotifyTelegramToken={0}", NotifyTelegramToken); sw.WriteLine("DutyUseNotifyDiscordWebhook={0}", UseNotifyDiscordWebhook); sw.WriteLine("DutyNotifyDiscordWebhookUrl={0}", NotifyDiscordWebhookUrl); sw.WriteLine("DutyNotifyDiscordWebhookTts={0}", NotifyDiscordWebhookTts); sw.WriteLine("DutyUsePing={0}", UsePing); sw.WriteLine("DutyPingColor0={0:X}", PingColors[0].ToArgb()); sw.WriteLine("DutyPingColor1={0:X}", PingColors[1].ToArgb()); sw.WriteLine("DutyPingColor2={0:X}", PingColors[2].ToArgb()); sw.WriteLine("DutyPingColor3={0:X}", PingColors[3].ToArgb()); sw.WriteLine("DutyPingShowLoss={0}", PingShowLoss); sw.WriteLine("DutyPingGraph={0}", PingGraph); sw.WriteLine("DutyPingDefAddr={0}", PingDefAddr); sw.WriteLine("DutyPingGraphType={0}", PingGraphType); sw.WriteLine("PacketForLocal={0}", PacketForLocal); sw.WriteLine(); } // internal void InternalReadFromDb(ThirdParty.LineDb db) { Language = db["DutyLanguage"]; ActiveFate = ThirdParty.Converter.ToInt(db["DutyActiveFate"]); Fates[0].Line = db["DutyFate0"]; Fates[1].Line = db["DutyFate1"]; Fates[2].Line = db["DutyFate2"]; Fates[3].Line = db["DutyFate3"]; PacketSet = db.Get("DutypPacketSet", PacketSet); LogFontFamily = db.Get("DutyLogFontFamily", LogFontFamily); LogFontSize = ThirdParty.Converter.ToFloat(db["DutyLogFontSize"], LogFontSize); EnableOverlay = ThirdParty.Converter.ToBool(db["DutyEnableOverlay"]); OverlayLocation = new Point( ThirdParty.Converter.ToInt(db["DutyOverlayLocationX"]), ThirdParty.Converter.ToInt(db["DutyOverlayLocationY"])); OverlayClickThru = ThirdParty.Converter.ToBool(db["DutyOverlayClickThru"]); OverlayAutoHide = ThirdParty.Converter.ToBool(db["DutyOverlayAutoHide"]); EnableSound = ThirdParty.Converter.ToBool(db["DutyEnableSound"]); SoundInstanceFile = db["DutySoundInstanceFile"]; SoundFateFile = db["DutySoundFateFile"]; SoundInstanceVolume = ThirdParty.Converter.ToInt(db["DutySoundInstanceVolume"], 100); SoundFateVolume = ThirdParty.Converter.ToInt(db["DutySoundFateVolume"], 100); UseNotifyLine = ThirdParty.Converter.ToBool(db["DutyUseNotifyLine"]); NotifyLineToken = db["DutyNotifyLineToken"]; UseNotifyTelegram = ThirdParty.Converter.ToBool(db["DutyUseNotifyTelegram"]); NotifyTelegramId = db["DutyNotifyTelegramId"]; NotifyTelegramToken = db["DutyNotifyTelegramToken"]; UseNotifyDiscordWebhook = ThirdParty.Converter.ToBool(db["DutyUseNotifyDiscordWebhook"]); NotifyDiscordWebhookUrl = db["DutyNotifyDiscordWebhookUrl"]; NotifyDiscordWebhookTts = ThirdParty.Converter.ToBool(db["DutyNotifyDiscordWebhookTts"]); UsePing = ThirdParty.Converter.ToBool(db["DutyUsePing"]); PingColors[0] = ThirdParty.Converter.ToColorArgb(db["DutyPingColor0"], PingColors[0]); PingColors[1] = ThirdParty.Converter.ToColorArgb(db["DutyPingColor1"], PingColors[1]); PingColors[2] = ThirdParty.Converter.ToColorArgb(db["DutyPingColor2"], PingColors[2]); PingColors[3] = ThirdParty.Converter.ToColorArgb(db["DutyPingColor3"], PingColors[3]); PingShowLoss = ThirdParty.Converter.ToBool(db["DutyPingShowLoss"]); PingGraph = ThirdParty.Converter.ToBool(db["DutyPingGraph"]); PingDefAddr = db.Get("DutyPingDefAddr", string.Empty); PingGraphType = ThirdParty.Converter.ToInt(db["PingGraphType"]); //PacketForLocal = ThirdParty.Converter.ToBool(db["PacketForLocal"]); } } // public class FateSelection { public HashSet Selected { get; } = new HashSet(); public string Line { get; set; } public int Index { get; set; } public FateSelection(int index) { Index = index; } public void MakeSelects(bool clear = false) { if (clear) Selected.Clear(); var ss = Line.Split('|'); foreach (var s in ss) { if (!string.IsNullOrWhiteSpace(s) && ThirdParty.Converter.TryInt(s, out int i)) Selected.Add(i); } } public void MakeLine() { Line = string.Join("|", Selected); } } // public class ConnectionList { public SortedSet Conns = new SortedSet(); public int Count => Conns.Count; public ThirdParty.NativeMethods.TcpRow[] CopyConnection() { ThirdParty.NativeMethods.TcpRow[] ret; lock (Conns) { ret = new ThirdParty.NativeMethods.TcpRow[Conns.Count]; Conns.CopyTo(ret); } return ret; } public void BuildConnections(Process process, out IPAddress retaddr) { var size = 0; ThirdParty.NativeMethods.GetExtendedTcpTable(IntPtr.Zero, ref size, true, AddressFamily.InterNetwork, 4); var buff = Marshal.AllocHGlobal(size); try { var ret = ThirdParty.NativeMethods.GetExtendedTcpTable(buff, ref size, true, AddressFamily.InterNetwork, 4); if (ret == 0) { var tbl = Marshal.PtrToStructure(buff); var ptr = (IntPtr)((long)buff + Marshal.SizeOf(tbl.entries)); var rows = new ThirdParty.NativeMethods.TcpRow[tbl.entries]; var rcnt = 0; for (var i = 0; i < tbl.entries; i++) { var row = Marshal.PtrToStructure(ptr); if (!IPAddress.IsLoopback(row.RemoteAddress) && process.Id == row.owningPid) rows[rcnt++] = row; ptr = (IntPtr)((long)ptr + Marshal.SizeOf(row)); } lock (Conns) { Conns.Clear(); if (rcnt == 0) retaddr = IPAddress.None; else { for (var i = 0; i < rcnt; i++) Conns.Add(rows[i]); retaddr = rows[0].RemoteAddress; } } } else { lock (Conns) Conns.Clear(); retaddr = IPAddress.None; } } finally { if (buff != null) Marshal.FreeHGlobal(buff); } } } } }