1
This commit is contained in:
+245
-94
@@ -1,14 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using BarrageGrab.Modles.JsonEntity;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Jint.Runtime;
|
||||
|
||||
namespace BarrageGrab
|
||||
@@ -21,16 +19,225 @@ namespace BarrageGrab
|
||||
static WinApi.ControlCtrlDelegate controlCtr = ControlCtrlHandle;
|
||||
static Mutex mutex = new Mutex(false, "DyBarrageGrab");
|
||||
|
||||
// 插件所在目录(用于解析相对路径)
|
||||
public static string BaseDir => AppDomain.CurrentDomain.BaseDirectory;
|
||||
|
||||
// === 启动项 (支持相对路径,相对于插件所在目录) ===
|
||||
public static bool AutoLaunchGame = true;
|
||||
public static string GameExePath = @"..\Fantasy.Map.Simulator\FantasyMapSimulator.exe";
|
||||
public static string GameWorkDir = @"..\Fantasy.Map.Simulator";
|
||||
|
||||
// === 配置表路径 (支持相对路径) ===
|
||||
public static string ConfigDir = @"..\Fantasy.Map.Simulator\BepInEx\config";
|
||||
public static string EffectFile = "effect_config.txt";
|
||||
public static string MacroFile = "macro_config.txt";
|
||||
public static string GiftFile = "gift_config.txt";
|
||||
public static string CommandFile = "command_config.txt";
|
||||
public static string FkeyFile = "fkey_config.txt";
|
||||
|
||||
/// <summary>将相对路径解析为绝对路径(基于插件所在目录)。已是绝对路径则原样返回。</summary>
|
||||
public static string ResolveFullPath(string path)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(path)) return path;
|
||||
return Path.IsPathRooted(path) ? path : Path.GetFullPath(Path.Combine(BaseDir, path));
|
||||
}
|
||||
|
||||
// 解析后的绝对路径(只读)
|
||||
public static string GameExeFullPath => ResolveFullPath(GameExePath);
|
||||
public static string GameWorkFullPath => ResolveFullPath(GameWorkDir);
|
||||
public static string ConfigDirFullPath => ResolveFullPath(ConfigDir);
|
||||
|
||||
// 配置表完整路径(只读,基于 ConfigDirFullPath)
|
||||
public static string EffectPath => Path.Combine(ConfigDirFullPath, EffectFile);
|
||||
public static string MacroPath => Path.Combine(ConfigDirFullPath, MacroFile);
|
||||
public static string GiftPath => Path.Combine(ConfigDirFullPath, GiftFile);
|
||||
public static string CommandPath => Path.Combine(ConfigDirFullPath, CommandFile);
|
||||
public static string FkeyPath => Path.Combine(ConfigDirFullPath, FkeyFile);
|
||||
|
||||
public static void SetGamePaths(string exePath, string workDir)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(exePath)) GameExePath = exePath;
|
||||
if (!string.IsNullOrWhiteSpace(workDir)) GameWorkDir = workDir;
|
||||
}
|
||||
|
||||
public static void SetConfigPaths(string configDir,
|
||||
string effectFile, string macroFile, string giftFile, string cmdFile, string fkeyFile)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(configDir)) ConfigDir = configDir;
|
||||
if (!string.IsNullOrWhiteSpace(effectFile)) EffectFile = effectFile;
|
||||
if (!string.IsNullOrWhiteSpace(macroFile)) MacroFile = macroFile;
|
||||
if (!string.IsNullOrWhiteSpace(giftFile)) GiftFile = giftFile;
|
||||
if (!string.IsNullOrWhiteSpace(cmdFile)) CommandFile = cmdFile;
|
||||
if (!string.IsNullOrWhiteSpace(fkeyFile)) FkeyFile = fkeyFile;
|
||||
}
|
||||
|
||||
/// <summary>从 GameExeFullPath 提取进程名(不带扩展名)</summary>
|
||||
static string GameProcessName
|
||||
{
|
||||
get
|
||||
{
|
||||
try { return Path.GetFileNameWithoutExtension(GameExeFullPath); }
|
||||
catch { return "FantasyMapSimulator"; }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>关闭所有同名游戏进程,返回是否已无残留</summary>
|
||||
static bool CloseGameProcesses()
|
||||
{
|
||||
var procName = GameProcessName;
|
||||
var procs = Process.GetProcessesByName(procName);
|
||||
if (procs.Length == 0)
|
||||
{
|
||||
Logger.PrintColor("未发现运行中的游戏进程 (" + procName + ")", ConsoleColor.DarkGray);
|
||||
return true;
|
||||
}
|
||||
|
||||
Logger.PrintColor("发现 " + procs.Length + " 个游戏进程 (" + procName + "),正在关闭...", ConsoleColor.Yellow);
|
||||
int killed = 0, failed = 0;
|
||||
foreach (var p in procs)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!p.HasExited)
|
||||
{
|
||||
try { p.CloseMainWindow(); } catch { }
|
||||
if (!p.WaitForExit(2000)) { p.Kill(); p.WaitForExit(3000); }
|
||||
}
|
||||
killed++;
|
||||
}
|
||||
catch { failed++; }
|
||||
finally { try { p.Close(); } catch { } }
|
||||
}
|
||||
|
||||
Thread.Sleep(500);
|
||||
var remain = Process.GetProcessesByName(procName);
|
||||
if (remain.Length > 0)
|
||||
{
|
||||
Logger.PrintColor("仍有 " + remain.Length + " 个进程未退出,强制结束...", ConsoleColor.Yellow);
|
||||
foreach (var r in remain)
|
||||
{
|
||||
try { if (!r.HasExited) r.Kill(); } catch { }
|
||||
finally { try { r.Close(); } catch { } }
|
||||
}
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
|
||||
bool allClosed = Process.GetProcessesByName(procName).Length == 0;
|
||||
Logger.PrintColor("关闭完成 (成功" + killed + ", 失败" + failed + ")", allClosed ? ConsoleColor.Green : ConsoleColor.Yellow);
|
||||
return allClosed;
|
||||
}
|
||||
|
||||
public static void LaunchGame()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!File.Exists(GameExeFullPath))
|
||||
{
|
||||
MessageBox.Show("找不到游戏文件:\n" + GameExeFullPath + "\n(配置路径: " + GameExePath + ")", "启动失败", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||
return;
|
||||
}
|
||||
var existing = Process.GetProcessesByName(GameProcessName);
|
||||
if (existing.Length > 0)
|
||||
{
|
||||
Logger.PrintColor("游戏已在运行中,跳过启动", ConsoleColor.Yellow);
|
||||
foreach (var p in existing) try { p.Close(); } catch { }
|
||||
return;
|
||||
}
|
||||
StartGameProcess();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex, "启动游戏失败: " + ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public static void RestartGame()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!File.Exists(GameExeFullPath))
|
||||
{
|
||||
MessageBox.Show("找不到游戏文件:\n" + GameExeFullPath + "\n(配置路径: " + GameExePath + ")", "启动失败", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
Logger.PrintColor("── 重启游戏:关闭进程 ──", ConsoleColor.Cyan);
|
||||
bool closed = CloseGameProcesses();
|
||||
if (!closed)
|
||||
{
|
||||
Logger.PrintColor("警告: 部分游戏进程未能完全关闭,仍尝试重新启动", ConsoleColor.Yellow);
|
||||
}
|
||||
|
||||
Thread.Sleep(1500);
|
||||
|
||||
Logger.PrintColor("── 重启游戏:重新启动 ──", ConsoleColor.Cyan);
|
||||
StartGameProcess();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex, "重启游戏失败: " + ex.Message);
|
||||
}
|
||||
}
|
||||
private static void StartGameProcess()
|
||||
{
|
||||
var psi = new ProcessStartInfo(GameExeFullPath)
|
||||
{
|
||||
WorkingDirectory = GameWorkFullPath,
|
||||
UseShellExecute = true
|
||||
};
|
||||
Process.Start(psi);
|
||||
Logger.PrintColor("游戏已启动", ConsoleColor.Green);
|
||||
}
|
||||
|
||||
/// <summary>加载 game_settings.json (启动项 + 配置表路径)</summary>
|
||||
private static void LoadGameSettings()
|
||||
{
|
||||
try
|
||||
{
|
||||
string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "game_settings.json");
|
||||
if (!File.Exists(path)) return;
|
||||
var json = JObject.Parse(File.ReadAllText(path));
|
||||
|
||||
// 启动项
|
||||
string exe = json["gameExePath"]?.Value<string>();
|
||||
string dir = json["gameWorkDir"]?.Value<string>();
|
||||
bool auto = json["autoLaunchGame"]?.Value<bool>() ?? true;
|
||||
if (!string.IsNullOrWhiteSpace(exe)) GameExePath = exe;
|
||||
if (!string.IsNullOrWhiteSpace(dir)) GameWorkDir = dir;
|
||||
AutoLaunchGame = auto;
|
||||
|
||||
// 配置表路径
|
||||
string configDir = json["configDir"]?.Value<string>();
|
||||
if (!string.IsNullOrWhiteSpace(configDir)) ConfigDir = configDir;
|
||||
var cfg = json["configFiles"];
|
||||
if (cfg != null)
|
||||
{
|
||||
string eff = cfg["effect"]?.Value<string>();
|
||||
string mac = cfg["macro"]?.Value<string>();
|
||||
string gift = cfg["gift"]?.Value<string>();
|
||||
string cmd = cfg["command"]?.Value<string>();
|
||||
string fkey = cfg["fkey"]?.Value<string>();
|
||||
if (!string.IsNullOrWhiteSpace(eff)) EffectFile = eff;
|
||||
if (!string.IsNullOrWhiteSpace(mac)) MacroFile = mac;
|
||||
if (!string.IsNullOrWhiteSpace(gift)) GiftFile = gift;
|
||||
if (!string.IsNullOrWhiteSpace(cmd)) CommandFile = cmd;
|
||||
if (!string.IsNullOrWhiteSpace(fkey)) FkeyFile = fkey;
|
||||
}
|
||||
|
||||
Logger.PrintColor($"已加载游戏设置: 自动启动={AutoLaunchGame}, 配置目录={ConfigDir}", ConsoleColor.DarkGray);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.PrintColor($"加载游戏设置失败: {ex.Message}", ConsoleColor.Yellow);
|
||||
}
|
||||
}
|
||||
|
||||
private const string WatchdogArg = "--watchdog";
|
||||
private const string WatchdogPidArg = "--pid";
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
if (IsWatchdogMode(args))
|
||||
{
|
||||
RunWatchdog(args);
|
||||
return;
|
||||
}
|
||||
if (IsWatchdogMode(args)) { RunWatchdog(args); return; }
|
||||
|
||||
if (!mutex.WaitOne(TimeSpan.Zero, true))
|
||||
{
|
||||
@@ -39,14 +246,11 @@ namespace BarrageGrab
|
||||
return;
|
||||
}
|
||||
|
||||
SetTitle("抖音弹幕监听推送");
|
||||
|
||||
SetTitle("弹幕监听推送");
|
||||
StartWatchdog();
|
||||
LoadGameSettings();
|
||||
|
||||
try
|
||||
{
|
||||
Init();
|
||||
}
|
||||
try { Init(); }
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex, $"程序初始化错误,{ex.Message}");
|
||||
@@ -54,18 +258,11 @@ namespace BarrageGrab
|
||||
exited = true;
|
||||
}
|
||||
|
||||
while (!exited)
|
||||
{
|
||||
Thread.Sleep(500);
|
||||
}
|
||||
|
||||
if (!AppRuntime.WsServer.IsDisposed)
|
||||
{
|
||||
AppRuntime.WsServer.Dispose();
|
||||
}
|
||||
while (!exited) Thread.Sleep(500);
|
||||
|
||||
if (!AppRuntime.WsServer.IsDisposed) AppRuntime.WsServer.Dispose();
|
||||
Logger.PrintColor("服务器已关闭...");
|
||||
WinApi.SetConsoleCtrlHandler(controlCtr, false);//反注册捕获控制台关闭
|
||||
WinApi.SetConsoleCtrlHandler(controlCtr, false);
|
||||
}
|
||||
|
||||
private static void StartWatchdog()
|
||||
@@ -74,21 +271,12 @@ namespace BarrageGrab
|
||||
{
|
||||
var exePath = Application.ExecutablePath;
|
||||
if (string.IsNullOrWhiteSpace(exePath) || !File.Exists(exePath)) return;
|
||||
|
||||
var pid = Process.GetCurrentProcess().Id;
|
||||
var args = string.Format("{0} {1} {2}", WatchdogArg, WatchdogPidArg, pid);
|
||||
var psi = new ProcessStartInfo(exePath, args)
|
||||
{
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true,
|
||||
WindowStyle = ProcessWindowStyle.Hidden
|
||||
};
|
||||
var psi = new ProcessStartInfo(exePath, args) { UseShellExecute = false, CreateNoWindow = true, WindowStyle = ProcessWindowStyle.Hidden };
|
||||
Process.Start(psi);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// best-effort only
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
private static bool IsWatchdogMode(string[] args)
|
||||
@@ -116,106 +304,69 @@ namespace BarrageGrab
|
||||
{
|
||||
var pid = TryGetWatchdogPid(args);
|
||||
if (pid == null || pid <= 0) return;
|
||||
|
||||
Process target;
|
||||
try
|
||||
{
|
||||
target = Process.GetProcessById(pid.Value);
|
||||
}
|
||||
catch
|
||||
{
|
||||
SafeCloseSystemProxy();
|
||||
return;
|
||||
}
|
||||
|
||||
for (; ; )
|
||||
{
|
||||
if (target.HasExited) break;
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
|
||||
try { target = Process.GetProcessById(pid.Value); }
|
||||
catch { SafeCloseSystemProxy(); return; }
|
||||
for (; ; ) { if (target.HasExited) break; Thread.Sleep(1000); }
|
||||
SafeCloseSystemProxy();
|
||||
}
|
||||
catch
|
||||
{
|
||||
try { SafeCloseSystemProxy(); } catch { }
|
||||
}
|
||||
catch { try { SafeCloseSystemProxy(); } catch { } }
|
||||
}
|
||||
|
||||
private static void SafeCloseSystemProxy()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!AppSetting.Current.UsedProxy) return;
|
||||
WinApi.CloseSystemProxy();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
try { if (!AppSetting.Current.UsedProxy) return; WinApi.CloseSystemProxy(); }
|
||||
catch { }
|
||||
}
|
||||
|
||||
private static void Init()
|
||||
{
|
||||
AppRuntime.Init();
|
||||
LiveCompanHelper.SwitchSetup();
|
||||
WinApi.SetConsoleCtrlHandler(controlCtr, true);//捕获控制台关闭
|
||||
WinApi.DisableQuickEditMode();//禁用控制台快速编辑模式
|
||||
AppRuntime.DisplayConsole(!AppSetting.Current.HideConsole);//控制控制台可见
|
||||
AppRuntime.WsServer.Grab.Proxy.SetUpstreamProxy(AppSetting.Current.UpstreamProxy);//设置上游代理
|
||||
AppRuntime.WsServer.OnClose += (s, e) =>
|
||||
{
|
||||
exited = true;
|
||||
};
|
||||
WinApi.SetConsoleCtrlHandler(controlCtr, true);
|
||||
WinApi.DisableQuickEditMode();
|
||||
AppRuntime.DisplayConsole(!AppSetting.Current.HideConsole);
|
||||
AppRuntime.WsServer.Grab.Proxy.SetUpstreamProxy(AppSetting.Current.UpstreamProxy);
|
||||
AppRuntime.WsServer.OnClose += (s, e) => { exited = true; };
|
||||
|
||||
//串口写入服务
|
||||
if (!AppSetting.Current.ComPort.IsNullOrWhiteSpace())
|
||||
{
|
||||
AppRuntime.ComPortServer.OpenStart();
|
||||
}
|
||||
|
||||
//显示窗体
|
||||
if (AppSetting.Current.ShowWindow)
|
||||
{
|
||||
var uiThread = new Thread(new ThreadStart(() =>
|
||||
{
|
||||
mainForm = new FormView();
|
||||
//开启消息循环
|
||||
System.Windows.Forms.Application.Run(mainForm);
|
||||
formExited = true;
|
||||
AppRuntime.WsServer.Dispose();//Close后自动释放资源
|
||||
AppRuntime.WsServer.Dispose();
|
||||
}));
|
||||
uiThread.SetApartmentState(ApartmentState.STA);
|
||||
uiThread.IsBackground = true;
|
||||
uiThread.Start();
|
||||
}
|
||||
|
||||
AppRuntime.WsServer.StartListen();//启动WS以及代理服务
|
||||
Logger.PrintColor($"{AppRuntime.WsServer.ServerLocation} 弹幕服务已启动,其他端可通过此地址获取到弹幕流信息", ConsoleColor.Green);
|
||||
AppRuntime.WsServer.StartListen();
|
||||
Logger.PrintColor($"{AppRuntime.WsServer.ServerLocation} 弹幕服务已启动", ConsoleColor.Green);
|
||||
|
||||
if (AutoLaunchGame) LaunchGame();
|
||||
|
||||
Version version = System.Reflection.Assembly.GetAssembly(typeof(Program)).GetName().Version;
|
||||
SetTitle($"抖音弹幕监听推送 v{version} [{AppRuntime.WsServer.ServerLocation}]");
|
||||
SetTitle($"弹幕监听推送 v{version} [{AppRuntime.WsServer.ServerLocation}]");
|
||||
}
|
||||
|
||||
//检测设置控制台标题
|
||||
private static void SetTitle(string title)
|
||||
{
|
||||
if (WinApi.GetConsoleWindow() != IntPtr.Zero)
|
||||
{
|
||||
Console.Title = title;
|
||||
}
|
||||
if (WinApi.GetConsoleWindow() != IntPtr.Zero) Console.Title = title;
|
||||
}
|
||||
|
||||
//监听控制台消息事件
|
||||
private static bool ControlCtrlHandle(int CtrlType)
|
||||
{
|
||||
switch (CtrlType)
|
||||
{
|
||||
case 0:
|
||||
//Logger.PrintColor("0工具被强制关闭"); //Ctrl+C关闭
|
||||
//server.Close();
|
||||
break;
|
||||
case 0: break;
|
||||
case 2:
|
||||
Logger.PrintColor("2工具被强制关闭");//按控制台关闭按钮关闭
|
||||
Logger.PrintColor("2工具被强制关闭");
|
||||
AppRuntime.WsServer.Dispose();
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user