Files
AIC-Project/Client/Assets/Script/xmain/MiniGame/PcMiniGameSmokeLauncher.cs
T
2026-07-10 10:24:29 +08:00

147 lines
5.2 KiB
C#

using System;
using System.IO;
using UnityEngine;
namespace XGame.MiniGame
{
// PC 本地端到端烟测入口:连接本地 Gateway,再用 MiniGameHost 下载/加载 rps 小游戏。
// 挂到任意场景对象后 Play;也可以运行时由 AddComponent 创建。
public sealed class PcMiniGameSmokeLauncher : MonoBehaviour
{
public string GatewayUrl = "ws://127.0.0.1:5005/ws?pid=1";
public string CdnBase = "";
public string GameId = "rps";
public int Version = 1;
public bool AutoStart;
private string _status = "idle";
private XWebSocket _socket;
private MiniGameHost _host;
private void Start()
{
if (AutoStart) StartSmoke();
}
private void OnDestroy()
{
_socket?.close();
_socket = null;
}
private void OnGUI()
{
GUILayout.BeginArea(new Rect(16, 16, 620, 230), GUI.skin.box);
GUILayout.Label("PC MiniGame Smoke");
GUILayout.Label("Status: " + _status);
GUILayout.Label("Gateway URL");
GatewayUrl = GUILayout.TextField(GatewayUrl);
GUILayout.Label("CDN Base");
CdnBase = GUILayout.TextField(string.IsNullOrEmpty(CdnBase) ? DefaultCdnBase() : CdnBase);
GUILayout.BeginHorizontal();
GUILayout.Label("Game", GUILayout.Width(48));
GameId = GUILayout.TextField(GameId, GUILayout.Width(120));
GUILayout.Label("Version", GUILayout.Width(56));
int.TryParse(GUILayout.TextField(Version.ToString(), GUILayout.Width(60)), out Version);
GUILayout.EndHorizontal();
if (GUILayout.Button("Start Smoke")) StartSmoke();
GUILayout.Label("Expected: download rps DLLs -> connect -> MatchFound(+AI) -> snapshots -> RoomEnd.");
GUILayout.EndArea();
}
public void StartSmoke()
{
string gatewayUrl = WithLocalPid(GatewayUrl);
_status = "connecting " + gatewayUrl;
_socket?.close();
_socket = new XWebSocket();
_socket.Connect(gatewayUrl, (sock, err) =>
{
if (!string.IsNullOrEmpty(err) || sock == null)
{
_status = "connect failed: " + err;
Debug.LogError("[PcMiniGameSmoke] " + _status);
return;
}
_status = "connected, entering " + GameId + " v" + Version;
Debug.Log("[PcMiniGameSmoke] " + _status);
_host = gameObject.GetComponent<MiniGameHost>();
if (_host == null) _host = gameObject.AddComponent<MiniGameHost>();
_host.EnterGame(ResolvedCdnBase(), GameId, Version, sock);
});
}
private static string WithLocalPid(string gatewayUrl)
{
if (string.IsNullOrWhiteSpace(gatewayUrl))
{
return gatewayUrl;
}
int pid = GetLocalPlayerId();
int queryStart = gatewayUrl.IndexOf('?');
if (queryStart < 0)
{
return gatewayUrl + "?pid=" + pid;
}
string head = gatewayUrl.Substring(0, queryStart);
string query = gatewayUrl.Substring(queryStart + 1);
string[] parts = query.Split('&');
bool replaced = false;
for (int i = 0; i < parts.Length; i++)
{
if (parts[i].StartsWith("pid=", StringComparison.OrdinalIgnoreCase))
{
parts[i] = "pid=" + pid;
replaced = true;
break;
}
}
return head + "?" + (replaced ? string.Join("&", parts) : query + "&pid=" + pid);
}
private static int GetLocalPlayerId()
{
const string key = "LocalClientId";
string id = XData.GetString(key, string.Empty);
if (string.IsNullOrEmpty(id))
{
id = SystemInfo.deviceUniqueIdentifier;
if (string.IsNullOrEmpty(id) || id == "unsupported")
{
id = Guid.NewGuid().ToString("N");
}
XData.SetString(key, id);
XData.Save();
}
unchecked
{
uint hash = 2166136261u;
for (int i = 0; i < id.Length; i++)
{
hash ^= id[i];
hash *= 16777619u;
}
return (int)(hash % 2000000000u) + 1;
}
}
private string ResolvedCdnBase()
{
return string.IsNullOrEmpty(CdnBase) ? DefaultCdnBase() : CdnBase;
}
private static string DefaultCdnBase()
{
// Editor: <repo>/Client/Assets -> <repo>/CDN/minigame/(由 XWorld/生成小游戏更新 菜单产出)
var assets = new DirectoryInfo(Application.dataPath);
var client = assets.Parent;
var repo = client?.Parent;
string root = repo != null ? repo.FullName : Directory.GetCurrentDirectory();
return "file:///" + root.Replace('\\', '/') + "/CDN/minigame/";
}
}
}