243 lines
7.9 KiB
C#
243 lines
7.9 KiB
C#
using System.Diagnostics;
|
||
using System.IO;
|
||
using System.Security.Cryptography;
|
||
using System.Windows;
|
||
using Zerolauncher.Defender;
|
||
|
||
namespace Zerolauncher.Manager
|
||
{
|
||
internal class EngineManager
|
||
{
|
||
private static Dictionary<string, SingleGame> mGame = new Dictionary<string, SingleGame>();
|
||
|
||
//运行时才能决定是否执行内联
|
||
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
|
||
private static string AccToKey(Account account)
|
||
{
|
||
return string.Format("{0}{1}{2}", account.providerId, account.serverId, account.userName);
|
||
}
|
||
|
||
public static bool CreateGame(Account account)
|
||
{
|
||
var key = AccToKey(account);
|
||
if (mGame.ContainsKey(key)) { return false; }
|
||
if (EngineCacheSha.errorCode != 0) {
|
||
switch (EngineCacheSha.errorCode)
|
||
{
|
||
case 1:
|
||
MessageBox.Show("发生网络错误==EMS。\n 请检查网络", "错误", MessageBoxButton.OKCancel, MessageBoxImage.Error);
|
||
break;
|
||
case 2:
|
||
MessageBox.Show("发生游戏服务错误==EMS。\n 请联系管理员", "错误", MessageBoxButton.OKCancel, MessageBoxImage.Error);
|
||
break;
|
||
default:
|
||
MessageBox.Show("发生未知错误==EMS。\n 请联系管理员", "错误", MessageBoxButton.OKCancel, MessageBoxImage.Error);
|
||
break;
|
||
}
|
||
return false;
|
||
}
|
||
try
|
||
{
|
||
mGame[key] = new SingleGame(account);
|
||
}catch (Exception _ex)
|
||
{
|
||
MessageBox.Show("发生错误!\n如重复发生此错误,\n请重新下载登陆器文件或联系管理员。", "错误", MessageBoxButton.OKCancel, MessageBoxImage.Error);
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
public static bool CreateGame(int memberId)
|
||
{
|
||
return CreateGame(AccountManager.accountsList[memberId]);
|
||
}
|
||
|
||
public static int CheckGameState(Account account)
|
||
{
|
||
var key = AccToKey(account);
|
||
if (mGame.ContainsKey(key)) { return mGame[key].mHandle; }
|
||
return -1;
|
||
}
|
||
|
||
public static short TurnGameSizeMini(Account account)
|
||
{
|
||
var key = AccToKey(account);
|
||
if (mGame.ContainsKey(key))
|
||
{
|
||
var game = mGame[key];
|
||
if (game.mHandle != 0)
|
||
{
|
||
game.Send(StaticHandleS.MiniSize);
|
||
return 2;
|
||
}
|
||
return 1;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
public static short TurnGameSizeNormal(Account account)
|
||
{
|
||
var key = AccToKey(account);
|
||
if (mGame.ContainsKey(key))
|
||
{
|
||
var game = mGame[key];
|
||
if (game.mHandle != 0)
|
||
{
|
||
game.Send(StaticHandleS.NormalSize);
|
||
return 2;
|
||
}
|
||
return 1;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
public static bool ExitGame(Account account)
|
||
{
|
||
var key = AccToKey(account);
|
||
if (!mGame.ContainsKey(key)) { return false; }
|
||
mGame[key].Send(StaticHandleS.CloseGame);
|
||
return true;
|
||
}
|
||
|
||
public static void OnGameExit(Account account)
|
||
{
|
||
mGame.Remove(AccToKey(account));
|
||
}
|
||
|
||
public static bool CheckEmpy()
|
||
{
|
||
return mGame.Count == 0;
|
||
}
|
||
}
|
||
|
||
class SingleGame
|
||
{
|
||
Process process;
|
||
|
||
string? restartUrl;
|
||
|
||
public int mHandle;
|
||
|
||
public Account account;
|
||
|
||
public SingleGame(Account acc)
|
||
{
|
||
restartUrl = null;
|
||
this.account = acc;
|
||
mHandle = 0;
|
||
process = EngineShell.CheckEngineSafe();
|
||
process.OutputDataReceived += Handle;
|
||
process.Exited += Process_Exited;
|
||
process.Start();
|
||
process.BeginOutputReadLine(); // 开始异步读取
|
||
}
|
||
|
||
private void CreateProcess()
|
||
{
|
||
process = EngineShell.CheckEngineSafe();
|
||
process.OutputDataReceived += Handle;
|
||
process.Exited += Process_Exited;
|
||
process.Start();
|
||
process.BeginOutputReadLine(); // 开始异步读取
|
||
}
|
||
|
||
private void Process_Exited(object? sender, EventArgs e)
|
||
{
|
||
Trace.WriteLine(
|
||
$"Exit time : {process.ExitTime}\n" +
|
||
$"Exit code : {process.ExitCode}\n" +
|
||
$"Elapsed time : {Math.Round((process.ExitTime - process.StartTime).TotalMilliseconds)}");
|
||
Trace.WriteLine($"进程已退出:{account.nickName}");
|
||
if ( restartUrl == null )
|
||
{
|
||
EngineManager.OnGameExit(account);
|
||
return;
|
||
}
|
||
CreateProcess();
|
||
}
|
||
|
||
private void Handle(object sender, DataReceivedEventArgs e)
|
||
{
|
||
var lines = e.Data == null? [""] : e.Data.Split(" ");
|
||
switch (lines[0])
|
||
{
|
||
case StaticHandleC.StartDone:
|
||
if(restartUrl == null)
|
||
{
|
||
Send($"{StaticHandleS.ShowWindow} {ServicesStaticInfo.ServicesName[account.providerId]}-{account.nickName}");
|
||
_ = LoginManager.DoLogin(this);
|
||
}
|
||
else
|
||
{
|
||
Send($"{StaticHandleS.ShowWindow} {ServicesStaticInfo.ServicesName[account.providerId]}-{account.nickName}");
|
||
Send($"{StaticHandleS.GameSa} {restartUrl}");
|
||
restartUrl = null;
|
||
}
|
||
break;
|
||
case StaticHandleC.GameDone:
|
||
mHandle = int.Parse(lines[1]);
|
||
break;
|
||
case StaticHandleC.BrowserDone:
|
||
restartUrl = lines[1];
|
||
Send(StaticHandleS.CloseGame);
|
||
break;
|
||
}
|
||
}
|
||
|
||
public bool Send(string msg)
|
||
{
|
||
if(process.HasExited) { return false; }
|
||
process.StandardInput.WriteLine(msg);
|
||
return true;
|
||
}
|
||
|
||
}
|
||
|
||
public class FileReadException : Exception
|
||
{
|
||
public FileReadException(string message) : base(message)
|
||
{
|
||
}
|
||
}
|
||
|
||
class EngineShell
|
||
{
|
||
static bool is_check = false;
|
||
const string engine_file = @"ZeroEngine.exe";
|
||
public static Process CheckEngineSafe()
|
||
{
|
||
if (!is_check && EngineManager.CheckEmpy())
|
||
{
|
||
string? now_bit;
|
||
using (SHA256 sha256 = SHA256.Create())
|
||
{
|
||
using (FileStream fileStream = File.OpenRead(engine_file))
|
||
{
|
||
byte[] hashBytes = sha256.ComputeHash(fileStream);
|
||
now_bit = BitConverter.ToString(hashBytes).Replace("-", string.Empty);
|
||
}
|
||
}
|
||
if (EngineCacheSha.Get() != now_bit)
|
||
{
|
||
throw new FileReadException("无法读取文件内容");
|
||
}
|
||
}
|
||
is_check = true;
|
||
var process = new Process
|
||
{
|
||
StartInfo = new ProcessStartInfo
|
||
{
|
||
FileName = engine_file,
|
||
Arguments = StaticHandleA.GameMode,
|
||
UseShellExecute = false,
|
||
CreateNoWindow = true,
|
||
RedirectStandardInput = true,
|
||
RedirectStandardOutput = true
|
||
},
|
||
EnableRaisingEvents = true
|
||
};
|
||
return process;
|
||
}
|
||
}
|
||
}
|