Files
bansonic_beta_main/Assets/scripts/_runtimecache/DlcRemoteManifestSyncService.cs
T
2026-06-30 21:21:30 +08:00

271 lines
7.4 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using GameServer.Client;
using UnityEngine;
using UnityEngine.Networking;
public static class DlcRemoteManifestSyncService
{
[Serializable]
private sealed class RemoteManifestEnvelope
{
public bool success;
public string message;
public RemoteManifestItem[] dlcs;
}
[Serializable]
private sealed class RemoteManifestItem
{
public string dlc_key;
public string display_name;
public string version;
public string manifest_file_name;
public string manifest_json;
public string uploaded_at;
public string updated_at;
}
private sealed class DlcRemoteManifestSyncRunner : MonoBehaviour
{
private void Start()
{
if (autoSyncOnStart)
{
SyncPublishedDlcs();
}
}
}
private const string DefaultServerUrl = "http://47.112.187.172:8080";
private const string RemoteManifestFilePrefix = "remote_";
private const string ManifestApiPath = "/api/dlcs/manifests";
private static DlcRemoteManifestSyncRunner runner;
private static bool autoSyncOnStart = true;
private static bool syncRequestedWhileBusy;
private static bool initialSyncPending = true;
public static bool IsSyncing { get; private set; }
public static event Action<bool> SyncCompleted;
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
private static void EnsureRunner()
{
if (runner != null)
{
return;
}
GameObject go = new GameObject(nameof(DlcRemoteManifestSyncService));
UnityEngine.Object.DontDestroyOnLoad(go);
runner = go.AddComponent<DlcRemoteManifestSyncRunner>();
}
public static void SetAutoSyncOnStart(bool enabled)
{
autoSyncOnStart = enabled;
if (!enabled)
{
initialSyncPending = false;
}
}
public static bool ShouldDeferInitialRefresh()
{
return autoSyncOnStart && initialSyncPending && !OnlineModeSettings.IsLocalOnlyMode;
}
public static void SyncPublishedDlcs()
{
EnsureRunner();
if (runner == null)
{
return;
}
if (IsSyncing)
{
syncRequestedWhileBusy = true;
return;
}
runner.StartCoroutine(SyncPublishedDlcsRoutine());
}
private static IEnumerator SyncPublishedDlcsRoutine()
{
if (IsSyncing)
{
yield break;
}
if (OnlineModeSettings.IsLocalOnlyMode)
{
initialSyncPending = false;
DlcRemoteContentService.RefreshInstalledDlc();
SyncCompleted?.Invoke(false);
yield break;
}
string url = BuildManifestApiUrl();
if (string.IsNullOrWhiteSpace(url))
{
initialSyncPending = false;
DlcRemoteContentService.RefreshInstalledDlc();
SyncCompleted?.Invoke(false);
yield break;
}
IsSyncing = true;
syncRequestedWhileBusy = false;
bool success = false;
using (UnityWebRequest request = UnityWebRequest.Get(url))
{
request.timeout = 10;
yield return request.SendWebRequest();
if (request.result == UnityWebRequest.Result.Success)
{
string responseText = request.downloadHandler != null ? request.downloadHandler.text : string.Empty;
success = TryApplyRemoteManifestPayload(responseText);
}
else
{
Debug.LogWarning("[DLC] Remote manifest sync failed: " + request.error);
}
}
initialSyncPending = false;
if (success)
{
DlcRemoteContentService.RefreshInstalledDlc();
}
else
{
DlcRemoteContentService.RefreshInstalledDlc();
}
IsSyncing = false;
SyncCompleted?.Invoke(success);
if (syncRequestedWhileBusy)
{
SyncPublishedDlcs();
}
}
private static bool TryApplyRemoteManifestPayload(string json)
{
if (string.IsNullOrWhiteSpace(json))
{
return false;
}
RemoteManifestEnvelope envelope;
try
{
envelope = JsonUtility.FromJson<RemoteManifestEnvelope>(json);
}
catch (Exception ex)
{
Debug.LogWarning("[DLC] Failed to parse remote manifest payload: " + ex.Message);
return false;
}
if (envelope == null || !envelope.success)
{
Debug.LogWarning("[DLC] Remote manifest payload reported failure.");
return false;
}
string manifestRoot = Path.Combine(Application.persistentDataPath, "DLC", "manifests");
try
{
Directory.CreateDirectory(manifestRoot);
DeleteExistingRemoteManifestFiles(manifestRoot);
RemoteManifestItem[] items = envelope.dlcs ?? Array.Empty<RemoteManifestItem>();
for (int i = 0; i < items.Length; i++)
{
RemoteManifestItem item = items[i];
if (item == null || string.IsNullOrWhiteSpace(item.manifest_json))
{
continue;
}
string safeKey = SanitizeFileName(item.dlc_key);
if (string.IsNullOrWhiteSpace(safeKey))
{
safeKey = "package_" + i;
}
string fileName = RemoteManifestFilePrefix + safeKey + ".json";
string path = Path.Combine(manifestRoot, fileName);
File.WriteAllText(path, item.manifest_json);
}
return true;
}
catch (Exception ex)
{
Debug.LogWarning("[DLC] Failed to write remote manifests: " + ex.Message);
return false;
}
}
private static void DeleteExistingRemoteManifestFiles(string manifestRoot)
{
string[] files = Directory.GetFiles(manifestRoot, RemoteManifestFilePrefix + "*.json", SearchOption.TopDirectoryOnly);
for (int i = 0; i < files.Length; i++)
{
try
{
File.Delete(files[i]);
}
catch (Exception ex)
{
Debug.LogWarning("[DLC] Failed to delete old remote manifest '" + files[i] + "': " + ex.Message);
}
}
}
private static string BuildManifestApiUrl()
{
string baseUrl = DefaultServerUrl;
NetworkManager manager = NetworkManager.Instance;
if (manager != null && !string.IsNullOrWhiteSpace(manager.ServerUrl))
{
baseUrl = manager.ServerUrl.Trim();
}
if (string.IsNullOrWhiteSpace(baseUrl))
{
return string.Empty;
}
return baseUrl.TrimEnd('/') + ManifestApiPath;
}
private static string SanitizeFileName(string value)
{
if (string.IsNullOrWhiteSpace(value))
{
return string.Empty;
}
char[] invalidChars = Path.GetInvalidFileNameChars();
string result = value.Trim();
for (int i = 0; i < invalidChars.Length; i++)
{
result = result.Replace(invalidChars[i], '_');
}
return result.Replace(' ', '_');
}
}