1
This commit is contained in:
@@ -0,0 +1,630 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace BarrageGrab.Forms
|
||||
{
|
||||
/// <summary>
|
||||
/// 完整设置界面 —— 可视化编辑 AppConfig.json + 游戏集成
|
||||
/// 配置项分8个Tab: 常规/网络/弹幕过滤/轮询/进程域名/直播伴侣/串口/游戏启动项
|
||||
/// 游戏启动项 Tab 管理启动项 + 5个配置表路径
|
||||
/// </summary>
|
||||
public class SettingsForm : Form
|
||||
{
|
||||
private TabControl tabMain;
|
||||
private Label lblStatus;
|
||||
|
||||
private string ConfigPath => Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "appConfig.json");
|
||||
private string GameSettingsPath => Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "game_settings.json");
|
||||
|
||||
// 常规
|
||||
private ComboBox cmbPlatform;
|
||||
private CheckBox cbHideConsole, cbShowWindow;
|
||||
// 网络
|
||||
private NumericUpDown nudWsPort, nudProxyPort;
|
||||
private CheckBox cbListenAny, cbProxyEnabled;
|
||||
private TextBox txtUpstreamProxy;
|
||||
// 弹幕过滤
|
||||
private CheckBox cbPrintBarrage, cbBarrageLog;
|
||||
private CheckedListBox clbPrintFilter, clbPushFilter, clbLogFilter;
|
||||
// 轮询
|
||||
private CheckBox cbForcePolling;
|
||||
private NumericUpDown nudPollingInterval;
|
||||
// 进程/域名
|
||||
private TextBox txtProcessFilter, txtHostNameList, txtWebRoomIds;
|
||||
private CheckBox cbFilterHostName;
|
||||
// 直播伴侣
|
||||
private TextBox txtLiveCompanPath;
|
||||
private CheckBox cbLiveCompanHook, cbAutoPause;
|
||||
// 串口
|
||||
private TextBox txtComPort, txtComBaud;
|
||||
// 游戏启动项
|
||||
private TextBox txtGameExePath, txtGameWorkDir;
|
||||
private CheckBox cbAutoLaunchGame;
|
||||
// 游戏配置表路径
|
||||
private TextBox txtConfigDir;
|
||||
private TextBox txtEffectFile, txtMacroFile, txtGiftFile, txtCmdFile, txtFkeyFile;
|
||||
|
||||
private readonly Tuple<int, string>[] MsgTypeOptions = {
|
||||
Tuple.Create(1, "1-弹幕消息"),
|
||||
Tuple.Create(2, "2-点赞消息"),
|
||||
Tuple.Create(3, "3-进入直播间"),
|
||||
Tuple.Create(4, "4-关注消息"),
|
||||
Tuple.Create(5, "5-礼物消息"),
|
||||
Tuple.Create(6, "6-统计消息"),
|
||||
Tuple.Create(7, "7-粉丝团消息"),
|
||||
Tuple.Create(8, "8-直播间分享"),
|
||||
Tuple.Create(9, "9-下播"),
|
||||
};
|
||||
|
||||
// 默认值
|
||||
private const string DefaultGameExe = @"..\Fantasy.Map.Simulator\FantasyMapSimulator.exe";
|
||||
private const string DefaultGameDir = @"..\Fantasy.Map.Simulator";
|
||||
private const string DefaultConfigDir = @"..\Fantasy.Map.Simulator\BepInEx\config";
|
||||
|
||||
public SettingsForm()
|
||||
{
|
||||
this.Text = "弹幕插件设置";
|
||||
this.ClientSize = new Size(620, 620);
|
||||
this.StartPosition = FormStartPosition.CenterParent;
|
||||
this.FormBorderStyle = FormBorderStyle.FixedDialog;
|
||||
this.MaximizeBox = false;
|
||||
BuildUI();
|
||||
LoadAll();
|
||||
}
|
||||
|
||||
void BuildUI()
|
||||
{
|
||||
tabMain = new TabControl { Dock = DockStyle.Top, Height = 540, Name = "tabMain" };
|
||||
this.Controls.Add(tabMain);
|
||||
|
||||
var pnlBottom = new Panel { Dock = DockStyle.Bottom, Height = 50 };
|
||||
this.Controls.Add(pnlBottom);
|
||||
|
||||
var btnSave = new Button { Text = "保存并应用", Width = 110, Height = 30, Left = 140, Top = 10, BackColor = Color.LightGreen };
|
||||
btnSave.Click += (s, e) => SaveAll();
|
||||
pnlBottom.Controls.Add(btnSave);
|
||||
|
||||
var btnCancel = new Button { Text = "取消", Width = 80, Height = 30, Left = 260, Top = 10 };
|
||||
btnCancel.Click += (s, e) => this.Close();
|
||||
pnlBottom.Controls.Add(btnCancel);
|
||||
|
||||
var btnReload = new Button { Text = "重新加载", Width = 90, Height = 30, Left = 350, Top = 10 };
|
||||
btnReload.Click += (s, e) => LoadAll();
|
||||
pnlBottom.Controls.Add(btnReload);
|
||||
|
||||
lblStatus = new Label { AutoSize = true, Left = 450, Top = 18, ForeColor = Color.DimGray, Text = "" };
|
||||
pnlBottom.Controls.Add(lblStatus);
|
||||
|
||||
BuildGeneralTab();
|
||||
BuildNetworkTab();
|
||||
BuildBarrageFilterTab();
|
||||
BuildPollingTab();
|
||||
BuildProcessDomainTab();
|
||||
BuildLiveCompanionTab();
|
||||
BuildComPortTab();
|
||||
BuildGameTab();
|
||||
}
|
||||
|
||||
void BuildGeneralTab()
|
||||
{
|
||||
var page = new TabPage("常规");
|
||||
page.Controls.Add(new Label { Text = "直播平台:", Left = 20, Top = 20, AutoSize = true });
|
||||
cmbPlatform = new ComboBox { Left = 120, Top = 17, Width = 150, DropDownStyle = ComboBoxStyle.DropDownList };
|
||||
cmbPlatform.Items.AddRange(new object[] { "douyin", "kuaishou" });
|
||||
page.Controls.Add(cmbPlatform);
|
||||
|
||||
cbHideConsole = new CheckBox { Text = "隐藏控制台", Left = 20, Top = 60, AutoSize = true };
|
||||
page.Controls.Add(cbHideConsole);
|
||||
|
||||
cbShowWindow = new CheckBox { Text = "显示主窗体", Left = 20, Top = 90, AutoSize = true };
|
||||
page.Controls.Add(cbShowWindow);
|
||||
|
||||
page.Controls.Add(new Label { Text = "提示: 平台切换需重启程序生效", Left = 20, Top = 150, AutoSize = true, ForeColor = Color.Gray });
|
||||
tabMain.TabPages.Add(page);
|
||||
}
|
||||
|
||||
void BuildNetworkTab()
|
||||
{
|
||||
var page = new TabPage("网络");
|
||||
page.Controls.Add(new Label { Text = "WebSocket 端口:", Left = 20, Top = 20, AutoSize = true });
|
||||
nudWsPort = new NumericUpDown { Left = 150, Top = 17, Width = 80, Minimum = 1, Maximum = 65535 };
|
||||
page.Controls.Add(nudWsPort);
|
||||
|
||||
cbListenAny = new CheckBox { Text = "监听任意IP(0.0.0.0)", Left = 20, Top = 55, AutoSize = true };
|
||||
page.Controls.Add(cbListenAny);
|
||||
|
||||
page.Controls.Add(new Label { Text = "系统代理端口:", Left = 20, Top = 90, AutoSize = true });
|
||||
nudProxyPort = new NumericUpDown { Left = 150, Top = 87, Width = 80, Minimum = 1, Maximum = 65535 };
|
||||
page.Controls.Add(nudProxyPort);
|
||||
|
||||
cbProxyEnabled = new CheckBox { Text = "启用系统代理", Left = 20, Top = 125, AutoSize = true };
|
||||
page.Controls.Add(cbProxyEnabled);
|
||||
|
||||
page.Controls.Add(new Label { Text = "上游代理地址:", Left = 20, Top = 160, AutoSize = true });
|
||||
txtUpstreamProxy = new TextBox { Left = 150, Top = 157, Width = 250 };
|
||||
page.Controls.Add(txtUpstreamProxy);
|
||||
page.Controls.Add(new Label { Text = "(例如: 127.0.0.1:11223, 不要带http://)", Left = 150, Top = 183, AutoSize = true, ForeColor = Color.Gray });
|
||||
tabMain.TabPages.Add(page);
|
||||
}
|
||||
|
||||
void BuildBarrageFilterTab()
|
||||
{
|
||||
var page = new TabPage("弹幕过滤");
|
||||
cbPrintBarrage = new CheckBox { Text = "控制台打印弹幕", Left = 10, Top = 10, AutoSize = true };
|
||||
page.Controls.Add(cbPrintBarrage);
|
||||
cbBarrageLog = new CheckBox { Text = "弹幕写入日志文件", Left = 200, Top = 10, AutoSize = true };
|
||||
page.Controls.Add(cbBarrageLog);
|
||||
|
||||
page.Controls.Add(new Label { Text = "打印过滤器:", Left = 10, Top = 40, AutoSize = true });
|
||||
clbPrintFilter = CreateFilterListBox();
|
||||
clbPrintFilter.Location = new Point(10, 60);
|
||||
page.Controls.Add(clbPrintFilter);
|
||||
|
||||
page.Controls.Add(new Label { Text = "推送过滤器:", Left = 220, Top = 40, AutoSize = true });
|
||||
clbPushFilter = CreateFilterListBox();
|
||||
clbPushFilter.Location = new Point(220, 60);
|
||||
page.Controls.Add(clbPushFilter);
|
||||
|
||||
page.Controls.Add(new Label { Text = "日志过滤器:", Left = 430, Top = 40, AutoSize = true });
|
||||
clbLogFilter = CreateFilterListBox();
|
||||
clbLogFilter.Location = new Point(430, 60);
|
||||
page.Controls.Add(clbLogFilter);
|
||||
tabMain.TabPages.Add(page);
|
||||
}
|
||||
|
||||
CheckedListBox CreateFilterListBox()
|
||||
{
|
||||
var clb = new CheckedListBox { Width = 200, Height = 200 };
|
||||
foreach (var opt in MsgTypeOptions) clb.Items.Add(opt.Item2, false);
|
||||
return clb;
|
||||
}
|
||||
|
||||
void BuildPollingTab()
|
||||
{
|
||||
var page = new TabPage("轮询");
|
||||
cbForcePolling = new CheckBox { Text = "强制启用轮询模式获取弹幕", Left = 20, Top = 20, AutoSize = true };
|
||||
page.Controls.Add(cbForcePolling);
|
||||
page.Controls.Add(new Label { Text = "轮询间隔(ms):", Left = 20, Top = 60, AutoSize = true });
|
||||
nudPollingInterval = new NumericUpDown { Left = 150, Top = 57, Width = 80, Minimum = 500, Maximum = 60000, Increment = 500 };
|
||||
page.Controls.Add(nudPollingInterval);
|
||||
page.Controls.Add(new Label { Text = "轮询模式更稳定但响应较慢", Left = 20, Top = 100, AutoSize = true, ForeColor = Color.Gray });
|
||||
page.Controls.Add(new Label { Text = "不建议小于1000ms", Left = 20, Top = 120, AutoSize = true, ForeColor = Color.Gray });
|
||||
tabMain.TabPages.Add(page);
|
||||
}
|
||||
|
||||
void BuildProcessDomainTab()
|
||||
{
|
||||
var page = new TabPage("进程/域名");
|
||||
page.Controls.Add(new Label { Text = "进程过滤器(逗号分隔):", Left = 20, Top = 20, AutoSize = true });
|
||||
txtProcessFilter = new TextBox { Left = 20, Top = 40, Width = 550, Multiline = true, Height = 40 };
|
||||
page.Controls.Add(txtProcessFilter);
|
||||
page.Controls.Add(new Label { Text = "只监听这些进程的弹幕数据", Left = 20, Top = 85, AutoSize = true, ForeColor = Color.Gray });
|
||||
|
||||
cbFilterHostName = new CheckBox { Text = "启用域名过滤(降低CPU占用)", Left = 20, Top = 115, AutoSize = true };
|
||||
page.Controls.Add(cbFilterHostName);
|
||||
|
||||
page.Controls.Add(new Label { Text = "域名白名单(逗号分隔):", Left = 20, Top = 145, AutoSize = true });
|
||||
txtHostNameList = new TextBox { Left = 20, Top = 165, Width = 550 };
|
||||
page.Controls.Add(txtHostNameList);
|
||||
|
||||
page.Controls.Add(new Label { Text = "Web房间ID过滤(逗号分隔):", Left = 20, Top = 195, AutoSize = true });
|
||||
txtWebRoomIds = new TextBox { Left = 20, Top = 215, Width = 550 };
|
||||
page.Controls.Add(txtWebRoomIds);
|
||||
page.Controls.Add(new Label { Text = "只监听指定房间,直播伴侣不支持", Left = 20, Top = 240, AutoSize = true, ForeColor = Color.Gray });
|
||||
tabMain.TabPages.Add(page);
|
||||
}
|
||||
|
||||
void BuildLiveCompanionTab()
|
||||
{
|
||||
var page = new TabPage("直播伴侣");
|
||||
page.Controls.Add(new Label { Text = "直播伴侣exe路径:", Left = 20, Top = 20, AutoSize = true });
|
||||
txtLiveCompanPath = new TextBox { Left = 20, Top = 40, Width = 450 };
|
||||
page.Controls.Add(txtLiveCompanPath);
|
||||
var btnBrowse = new Button { Text = "浏览...", Left = 480, Top = 39, Width = 70 };
|
||||
btnBrowse.Click += (s, e) =>
|
||||
{
|
||||
using (var dlg = new OpenFileDialog { Filter = "EXE文件|*.exe|所有文件|*.*" })
|
||||
if (dlg.ShowDialog() == DialogResult.OK) txtLiveCompanPath.Text = dlg.FileName;
|
||||
};
|
||||
page.Controls.Add(btnBrowse);
|
||||
page.Controls.Add(new Label { Text = "(留空则程序自动查找)", Left = 20, Top = 65, AutoSize = true, ForeColor = Color.Gray });
|
||||
|
||||
cbLiveCompanHook = new CheckBox { Text = "Hook直播伴侣代理", Left = 20, Top = 95, AutoSize = true };
|
||||
page.Controls.Add(cbLiveCompanHook);
|
||||
cbAutoPause = new CheckBox { Text = "进入直播间自动暂停", Left = 20, Top = 125, AutoSize = true };
|
||||
page.Controls.Add(cbAutoPause);
|
||||
tabMain.TabPages.Add(page);
|
||||
}
|
||||
|
||||
void BuildComPortTab()
|
||||
{
|
||||
var page = new TabPage("串口");
|
||||
page.Controls.Add(new Label { Text = "COM端口:", Left = 20, Top = 20, AutoSize = true });
|
||||
txtComPort = new TextBox { Left = 120, Top = 17, Width = 100 };
|
||||
page.Controls.Add(txtComPort);
|
||||
page.Controls.Add(new Label { Text = "例如: COM1", Left = 230, Top = 20, AutoSize = true, ForeColor = Color.Gray });
|
||||
page.Controls.Add(new Label { Text = "波特率:", Left = 20, Top = 55, AutoSize = true });
|
||||
txtComBaud = new TextBox { Left = 120, Top = 52, Width = 100 };
|
||||
page.Controls.Add(txtComBaud);
|
||||
page.Controls.Add(new Label { Text = "例如: 9600", Left = 230, Top = 55, AutoSize = true, ForeColor = Color.Gray });
|
||||
page.Controls.Add(new Label { Text = "留空则不启用串口抄送服务", Left = 20, Top = 95, AutoSize = true, ForeColor = Color.Gray });
|
||||
tabMain.TabPages.Add(page);
|
||||
}
|
||||
|
||||
void BuildGameTab()
|
||||
{
|
||||
var page = new TabPage("游戏启动项");
|
||||
int y = 15;
|
||||
|
||||
// === 启动项 ===
|
||||
page.Controls.Add(new Label { Text = "── 启动项 ──", Left = 20, Top = y, AutoSize = true, ForeColor = Color.SteelBlue, Font = new Font(Font, FontStyle.Bold) });
|
||||
y += 25;
|
||||
|
||||
page.Controls.Add(new Label { Text = "游戏exe路径:", Left = 20, Top = y, AutoSize = true });
|
||||
txtGameExePath = new TextBox { Left = 120, Top = y - 3, Width = 380 };
|
||||
page.Controls.Add(txtGameExePath);
|
||||
var btnBrowse1 = new Button { Text = "浏览...", Left = 510, Top = y - 4, Width = 70 };
|
||||
btnBrowse1.Click += (s, e) =>
|
||||
{
|
||||
using (var dlg = new OpenFileDialog { Filter = "EXE文件|*.exe|所有文件|*.*" })
|
||||
if (dlg.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
txtGameExePath.Text = ToRelativePath(dlg.FileName);
|
||||
var dir = Path.GetDirectoryName(dlg.FileName);
|
||||
if (!string.IsNullOrEmpty(dir)) txtGameWorkDir.Text = ToRelativePath(dir);
|
||||
}
|
||||
};
|
||||
page.Controls.Add(btnBrowse1);
|
||||
y += 27;
|
||||
|
||||
page.Controls.Add(new Label { Text = "工作目录:", Left = 20, Top = y, AutoSize = true });
|
||||
txtGameWorkDir = new TextBox { Left = 120, Top = y - 3, Width = 380 };
|
||||
page.Controls.Add(txtGameWorkDir);
|
||||
y += 27;
|
||||
|
||||
cbAutoLaunchGame = new CheckBox { Text = "启动时自动打开游戏", Left = 20, Top = y, AutoSize = true };
|
||||
page.Controls.Add(cbAutoLaunchGame);
|
||||
y += 30;
|
||||
|
||||
// === 配置表路径 ===
|
||||
page.Controls.Add(new Label { Text = "── 配置表路径 ──", Left = 20, Top = y, AutoSize = true, ForeColor = Color.SteelBlue, Font = new Font(Font, FontStyle.Bold) });
|
||||
y += 25;
|
||||
|
||||
page.Controls.Add(new Label { Text = "配置表目录:", Left = 20, Top = y, AutoSize = true });
|
||||
txtConfigDir = new TextBox { Left = 120, Top = y - 3, Width = 380 };
|
||||
page.Controls.Add(txtConfigDir);
|
||||
var btnBrowse2 = new Button { Text = "浏览...", Left = 510, Top = y - 4, Width = 70 };
|
||||
btnBrowse2.Click += (s, e) =>
|
||||
{
|
||||
using (var dlg = new FolderBrowserDialog())
|
||||
if (dlg.ShowDialog() == DialogResult.OK) txtConfigDir.Text = ToRelativePath(dlg.SelectedPath);
|
||||
};
|
||||
page.Controls.Add(btnBrowse2);
|
||||
y += 30;
|
||||
|
||||
// 5个配置表文件名
|
||||
txtEffectFile = AddConfigFileRow(page, ref y, "基础效果(effect):", "effect_config.txt");
|
||||
txtMacroFile = AddConfigFileRow(page, ref y, "组合宏(macro):", "macro_config.txt");
|
||||
txtGiftFile = AddConfigFileRow(page, ref y, "礼物事件(gift):", "gift_config.txt");
|
||||
txtCmdFile = AddConfigFileRow(page, ref y, "弹幕指令(command):", "command_config.txt");
|
||||
txtFkeyFile = AddConfigFileRow(page, ref y, "F键映射(fkey):", "fkey_config.txt");
|
||||
y += 5;
|
||||
|
||||
// === 功能按钮 ===
|
||||
var btnOpenGameConfig = new Button { Text = "打开配置编辑器", Left = 20, Top = y, Width = 130, Height = 30 };
|
||||
btnOpenGameConfig.Click += (s, e) => { using (var f = new ConfigEditorForm()) f.ShowDialog(this); };
|
||||
page.Controls.Add(btnOpenGameConfig);
|
||||
|
||||
var btnOpenConfigDir = new Button { Text = "打开配置目录", Left = 160, Top = y, Width = 110 };
|
||||
btnOpenConfigDir.Click += (s, e) =>
|
||||
{
|
||||
var dir = Program.ResolveFullPath(txtConfigDir.Text.Trim());
|
||||
if (!string.IsNullOrEmpty(dir) && Directory.Exists(dir))
|
||||
System.Diagnostics.Process.Start("explorer.exe", dir);
|
||||
else
|
||||
MessageBox.Show($"配置目录不存在:\n{dir}", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
};
|
||||
page.Controls.Add(btnOpenConfigDir);
|
||||
|
||||
var btnResetDefaults = new Button { Text = "恢复默认", Left = 280, Top = y, Width = 80 };
|
||||
btnResetDefaults.Click += (s, e) => ResetGameDefaults();
|
||||
page.Controls.Add(btnResetDefaults);
|
||||
|
||||
tabMain.TabPages.Add(page);
|
||||
}
|
||||
|
||||
TextBox AddConfigFileRow(TabPage page, ref int y, string label, string defaultName)
|
||||
{
|
||||
page.Controls.Add(new Label { Text = label, Left = 30, Top = y, AutoSize = true });
|
||||
var txt = new TextBox { Left = 180, Top = y - 3, Width = 200, Text = defaultName };
|
||||
page.Controls.Add(txt);
|
||||
y += 24;
|
||||
return txt;
|
||||
}
|
||||
|
||||
/// <summary>将绝对路径转为相对插件目录的相对路径;若转换失败或已是相对路径则原样返回。</summary>
|
||||
static string ToRelativePath(string absPath)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(absPath)) return absPath;
|
||||
if (!Path.IsPathRooted(absPath)) return absPath; // 已是相对路径
|
||||
try
|
||||
{
|
||||
var baseDir = AppDomain.CurrentDomain.BaseDirectory;
|
||||
var fullBase = Path.GetFullPath(baseDir.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar));
|
||||
var fullAbs = Path.GetFullPath(absPath);
|
||||
var baseUri = new Uri(fullBase + Path.DirectorySeparatorChar);
|
||||
var absUri = new Uri(fullAbs);
|
||||
var rel = baseUri.MakeRelativeUri(absUri).ToString();
|
||||
// Uri 返回的是用 / 分隔的相对路径,统一为 Windows 分隔符
|
||||
rel = Uri.UnescapeDataString(rel).Replace('/', Path.DirectorySeparatorChar);
|
||||
return rel;
|
||||
}
|
||||
catch { return absPath; }
|
||||
}
|
||||
|
||||
void ResetGameDefaults()
|
||||
{
|
||||
txtGameExePath.Text = DefaultGameExe;
|
||||
txtGameWorkDir.Text = DefaultGameDir;
|
||||
txtConfigDir.Text = DefaultConfigDir;
|
||||
txtEffectFile.Text = "effect_config.txt";
|
||||
txtMacroFile.Text = "macro_config.txt";
|
||||
txtGiftFile.Text = "gift_config.txt";
|
||||
txtCmdFile.Text = "command_config.txt";
|
||||
txtFkeyFile.Text = "fkey_config.txt";
|
||||
cbAutoLaunchGame.Checked = true;
|
||||
}
|
||||
|
||||
// ═══════════════ 加载 ═══════════════
|
||||
|
||||
void LoadAll()
|
||||
{
|
||||
try
|
||||
{
|
||||
LoadAppConfig();
|
||||
LoadGameSettings();
|
||||
lblStatus.Text = "已加载";
|
||||
lblStatus.ForeColor = Color.DimGray;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
lblStatus.Text = $"加载失败: {ex.Message}";
|
||||
lblStatus.ForeColor = Color.Red;
|
||||
}
|
||||
}
|
||||
|
||||
void LoadAppConfig()
|
||||
{
|
||||
if (!File.Exists(ConfigPath)) return;
|
||||
var config = JObject.Parse(File.ReadAllText(ConfigPath), new JsonLoadSettings { CommentHandling = CommentHandling.Ignore });
|
||||
var app = config["app"];
|
||||
|
||||
var general = app["general"];
|
||||
cmbPlatform.SelectedItem = general["platform"]?.Value<string>() ?? "douyin";
|
||||
cbHideConsole.Checked = general["hideConsole"]?.Value<bool>() ?? false;
|
||||
cbShowWindow.Checked = general["showWindow"]?.Value<bool>() ?? false;
|
||||
|
||||
var proxy = app["network"]["proxy"];
|
||||
nudProxyPort.Value = proxy["port"]?.Value<int>() ?? 8827;
|
||||
cbProxyEnabled.Checked = proxy["enabled"]?.Value<bool>() ?? true;
|
||||
txtUpstreamProxy.Text = proxy["upstreamAddress"]?.Value<string>() ?? "";
|
||||
var ws = app["network"]["websocket"];
|
||||
nudWsPort.Value = ws["listenPort"]?.Value<int>() ?? 8888;
|
||||
cbListenAny.Checked = ws["listenAny"]?.Value<bool>() ?? true;
|
||||
|
||||
var barrage = app["barrage"];
|
||||
cbPrintBarrage.Checked = barrage["printEnabled"]?.Value<bool>() ?? true;
|
||||
cbBarrageLog.Checked = barrage["barrageFileLog"]?.Value<bool>() ?? false;
|
||||
SetFilterChecks(clbPrintFilter, barrage["printFilter"]?.Value<string>() ?? "");
|
||||
SetFilterChecks(clbPushFilter, barrage["pushFilter"]?.Value<string>() ?? "");
|
||||
SetFilterChecks(clbLogFilter, barrage["logFilter"]?.Value<string>() ?? "1,2,4,5,6,7,8");
|
||||
|
||||
var polling = barrage["polling"];
|
||||
cbForcePolling.Checked = polling["enabled"]?.Value<bool>() ?? false;
|
||||
nudPollingInterval.Value = polling["interval"]?.Value<int>() ?? 3000;
|
||||
|
||||
var filtering = app["filtering"];
|
||||
txtProcessFilter.Text = filtering["processFilter"]?.Value<string>() ?? "";
|
||||
cbFilterHostName.Checked = filtering["hostNameEnabled"]?.Value<bool>() ?? true;
|
||||
txtHostNameList.Text = filtering["hostNameList"]?.Value<string>() ?? "";
|
||||
txtWebRoomIds.Text = filtering["webRoomIds"]?.Value<string>() ?? "";
|
||||
|
||||
var liveCompanion = app["liveCompanion"];
|
||||
txtLiveCompanPath.Text = liveCompanion["path"]?.Value<string>() ?? "";
|
||||
cbLiveCompanHook.Checked = liveCompanion["hookEnabled"]?.Value<bool>() ?? false;
|
||||
cbAutoPause.Checked = liveCompanion["autoPause"]?.Value<bool>() ?? true;
|
||||
|
||||
var comPortStr = app["comPort"]["config"]?.Value<string>() ?? "";
|
||||
if (!string.IsNullOrWhiteSpace(comPortStr))
|
||||
{
|
||||
var parts = comPortStr.Split(':');
|
||||
if (parts.Length >= 2) { txtComPort.Text = parts[0].Trim(); txtComBaud.Text = parts[1].Trim(); }
|
||||
}
|
||||
}
|
||||
|
||||
void LoadGameSettings()
|
||||
{
|
||||
// 默认值
|
||||
txtGameExePath.Text = DefaultGameExe;
|
||||
txtGameWorkDir.Text = DefaultGameDir;
|
||||
cbAutoLaunchGame.Checked = true;
|
||||
txtConfigDir.Text = DefaultConfigDir;
|
||||
txtEffectFile.Text = "effect_config.txt";
|
||||
txtMacroFile.Text = "macro_config.txt";
|
||||
txtGiftFile.Text = "gift_config.txt";
|
||||
txtCmdFile.Text = "command_config.txt";
|
||||
txtFkeyFile.Text = "fkey_config.txt";
|
||||
|
||||
if (File.Exists(GameSettingsPath))
|
||||
{
|
||||
try
|
||||
{
|
||||
var json = JObject.Parse(File.ReadAllText(GameSettingsPath));
|
||||
txtGameExePath.Text = json["gameExePath"]?.Value<string>() ?? txtGameExePath.Text;
|
||||
txtGameWorkDir.Text = json["gameWorkDir"]?.Value<string>() ?? txtGameWorkDir.Text;
|
||||
cbAutoLaunchGame.Checked = json["autoLaunchGame"]?.Value<bool>() ?? true;
|
||||
txtConfigDir.Text = json["configDir"]?.Value<string>() ?? txtConfigDir.Text;
|
||||
|
||||
var cfg = json["configFiles"];
|
||||
if (cfg != null)
|
||||
{
|
||||
txtEffectFile.Text = cfg["effect"]?.Value<string>() ?? txtEffectFile.Text;
|
||||
txtMacroFile.Text = cfg["macro"]?.Value<string>() ?? txtMacroFile.Text;
|
||||
txtGiftFile.Text = cfg["gift"]?.Value<string>() ?? txtGiftFile.Text;
|
||||
txtCmdFile.Text = cfg["command"]?.Value<string>() ?? txtCmdFile.Text;
|
||||
txtFkeyFile.Text = cfg["fkey"]?.Value<string>() ?? txtFkeyFile.Text;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
Program.AutoLaunchGame = cbAutoLaunchGame.Checked;
|
||||
}
|
||||
|
||||
void SetFilterChecks(CheckedListBox clb, string filterStr)
|
||||
{
|
||||
for (int i = 0; i < clb.Items.Count; i++) clb.SetItemChecked(i, false);
|
||||
if (string.IsNullOrWhiteSpace(filterStr)) return;
|
||||
var ids = filterStr.Split(',').Select(s => s.Trim()).Where(s => !string.IsNullOrEmpty(s)).ToList();
|
||||
for (int i = 0; i < clb.Items.Count; i++)
|
||||
{
|
||||
if (ids.Contains(MsgTypeOptions[i].Item1.ToString()))
|
||||
clb.SetItemChecked(i, true);
|
||||
}
|
||||
}
|
||||
|
||||
string GetFilterString(CheckedListBox clb)
|
||||
{
|
||||
var ids = new List<string>();
|
||||
for (int i = 0; i < clb.Items.Count; i++)
|
||||
if (clb.GetItemChecked(i)) ids.Add(MsgTypeOptions[i].Item1.ToString());
|
||||
return string.Join(",", ids);
|
||||
}
|
||||
|
||||
// ═══════════════ 保存 ═══════════════
|
||||
|
||||
void SaveAll()
|
||||
{
|
||||
try
|
||||
{
|
||||
SaveAppConfig();
|
||||
SaveGameSettings();
|
||||
AppSetting.Current.LoadFromJson(ConfigPath);
|
||||
lblStatus.Text = "已保存(部分设置需重启生效)";
|
||||
lblStatus.ForeColor = Color.Green;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
lblStatus.Text = $"保存失败: {ex.Message}";
|
||||
lblStatus.ForeColor = Color.Red;
|
||||
}
|
||||
}
|
||||
|
||||
void SaveAppConfig()
|
||||
{
|
||||
if (!File.Exists(ConfigPath))
|
||||
{
|
||||
var json = new JObject(new JProperty("app", new JObject(
|
||||
new JProperty("general", new JObject(
|
||||
new JProperty("hideConsole", cbHideConsole.Checked),
|
||||
new JProperty("showWindow", cbShowWindow.Checked),
|
||||
new JProperty("platform", cmbPlatform.SelectedItem?.ToString() ?? "douyin"))),
|
||||
new JProperty("network", new JObject(
|
||||
new JProperty("proxy", new JObject(
|
||||
new JProperty("port", (int)nudProxyPort.Value),
|
||||
new JProperty("enabled", cbProxyEnabled.Checked),
|
||||
new JProperty("upstreamAddress", txtUpstreamProxy.Text.Trim()))),
|
||||
new JProperty("websocket", new JObject(
|
||||
new JProperty("listenPort", (int)nudWsPort.Value),
|
||||
new JProperty("listenAny", cbListenAny.Checked))))),
|
||||
new JProperty("filtering", new JObject(
|
||||
new JProperty("processFilter", txtProcessFilter.Text.Trim()),
|
||||
new JProperty("hostNameEnabled", cbFilterHostName.Checked),
|
||||
new JProperty("hostNameList", txtHostNameList.Text.Trim()),
|
||||
new JProperty("webRoomIds", txtWebRoomIds.Text.Trim()))),
|
||||
new JProperty("barrage", new JObject(
|
||||
new JProperty("printEnabled", cbPrintBarrage.Checked),
|
||||
new JProperty("printFilter", GetFilterString(clbPrintFilter)),
|
||||
new JProperty("pushFilter", GetFilterString(clbPushFilter)),
|
||||
new JProperty("barrageFileLog", cbBarrageLog.Checked),
|
||||
new JProperty("logFilter", GetFilterString(clbLogFilter)),
|
||||
new JProperty("polling", new JObject(
|
||||
new JProperty("enabled", cbForcePolling.Checked),
|
||||
new JProperty("interval", (int)nudPollingInterval.Value))))),
|
||||
new JProperty("liveCompanion", new JObject(
|
||||
new JProperty("path", txtLiveCompanPath.Text.Trim()),
|
||||
new JProperty("hookEnabled", cbLiveCompanHook.Checked),
|
||||
new JProperty("autoPause", cbAutoPause.Checked))),
|
||||
new JProperty("comPort", new JObject(
|
||||
new JProperty("config", BuildComPortConfig()))))));
|
||||
File.WriteAllText(ConfigPath, json.ToString(), Encoding.UTF8);
|
||||
return;
|
||||
}
|
||||
|
||||
var config = JObject.Parse(File.ReadAllText(ConfigPath), new JsonLoadSettings { CommentHandling = CommentHandling.Ignore });
|
||||
var app = config["app"];
|
||||
app["general"]["platform"] = cmbPlatform.SelectedItem?.ToString() ?? "douyin";
|
||||
app["general"]["hideConsole"] = cbHideConsole.Checked;
|
||||
app["general"]["showWindow"] = cbShowWindow.Checked;
|
||||
app["network"]["proxy"]["port"] = (int)nudProxyPort.Value;
|
||||
app["network"]["proxy"]["enabled"] = cbProxyEnabled.Checked;
|
||||
app["network"]["proxy"]["upstreamAddress"] = txtUpstreamProxy.Text.Trim();
|
||||
app["network"]["websocket"]["listenPort"] = (int)nudWsPort.Value;
|
||||
app["network"]["websocket"]["listenAny"] = cbListenAny.Checked;
|
||||
app["filtering"]["processFilter"] = txtProcessFilter.Text.Trim();
|
||||
app["filtering"]["hostNameEnabled"] = cbFilterHostName.Checked;
|
||||
app["filtering"]["hostNameList"] = txtHostNameList.Text.Trim();
|
||||
app["filtering"]["webRoomIds"] = txtWebRoomIds.Text.Trim();
|
||||
app["barrage"]["printEnabled"] = cbPrintBarrage.Checked;
|
||||
app["barrage"]["printFilter"] = GetFilterString(clbPrintFilter);
|
||||
app["barrage"]["pushFilter"] = GetFilterString(clbPushFilter);
|
||||
app["barrage"]["barrageFileLog"] = cbBarrageLog.Checked;
|
||||
app["barrage"]["logFilter"] = GetFilterString(clbLogFilter);
|
||||
app["barrage"]["polling"]["enabled"] = cbForcePolling.Checked;
|
||||
app["barrage"]["polling"]["interval"] = (int)nudPollingInterval.Value;
|
||||
app["liveCompanion"]["path"] = txtLiveCompanPath.Text.Trim();
|
||||
app["liveCompanion"]["hookEnabled"] = cbLiveCompanHook.Checked;
|
||||
app["liveCompanion"]["autoPause"] = cbAutoPause.Checked;
|
||||
app["comPort"]["config"] = BuildComPortConfig();
|
||||
File.WriteAllText(ConfigPath, config.ToString(), Encoding.UTF8);
|
||||
}
|
||||
|
||||
string BuildComPortConfig()
|
||||
{
|
||||
var port = txtComPort.Text.Trim();
|
||||
var baud = txtComBaud.Text.Trim();
|
||||
if (string.IsNullOrEmpty(port)) return "";
|
||||
if (string.IsNullOrEmpty(baud)) baud = "9600";
|
||||
return $"{port}:{baud}";
|
||||
}
|
||||
|
||||
void SaveGameSettings()
|
||||
{
|
||||
var json = new JObject(
|
||||
new JProperty("gameExePath", txtGameExePath.Text.Trim()),
|
||||
new JProperty("gameWorkDir", txtGameWorkDir.Text.Trim()),
|
||||
new JProperty("autoLaunchGame", cbAutoLaunchGame.Checked),
|
||||
new JProperty("configDir", txtConfigDir.Text.Trim()),
|
||||
new JProperty("configFiles", new JObject(
|
||||
new JProperty("effect", txtEffectFile.Text.Trim()),
|
||||
new JProperty("macro", txtMacroFile.Text.Trim()),
|
||||
new JProperty("gift", txtGiftFile.Text.Trim()),
|
||||
new JProperty("command", txtCmdFile.Text.Trim()),
|
||||
new JProperty("fkey", txtFkeyFile.Text.Trim()))));
|
||||
File.WriteAllText(GameSettingsPath, json.ToString(), Encoding.UTF8);
|
||||
|
||||
// 同步到 Program
|
||||
Program.AutoLaunchGame = cbAutoLaunchGame.Checked;
|
||||
Program.SetGamePaths(txtGameExePath.Text.Trim(), txtGameWorkDir.Text.Trim());
|
||||
Program.SetConfigPaths(txtConfigDir.Text.Trim(),
|
||||
txtEffectFile.Text.Trim(), txtMacroFile.Text.Trim(),
|
||||
txtGiftFile.Text.Trim(), txtCmdFile.Text.Trim(),
|
||||
txtFkeyFile.Text.Trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user