Fix hotfix AOT serialization entrypoints

This commit is contained in:
wuwenbo 2026-06-11 00:56:34 +08:00
parent 0e3cb360ee
commit d0e23e6408
18 changed files with 126 additions and 55 deletions

View File

@ -1,4 +1,4 @@
/*
/*
* @Author:
* @Description:
* @Date: 20250403 11:04:31
@ -114,8 +114,8 @@ namespace RuntimeData
public MapConfig CreateRuntimeCopy()
{
var bytes = MemoryPackSerializer.Serialize(this);
return MemoryPackSerializer.Deserialize<MapConfig>(bytes);
var bytes = TH1Serialization.Serialize(this);
return TH1Serialization.Deserialize<MapConfig>(bytes);
}
// MemoryPack 反序列化之后的后处理
@ -968,7 +968,7 @@ namespace RuntimeData
{
if (!LobbyManager.Instance.Lobby.IsInLobby()) return;
byte[] bytes = MemoryPackSerializer.Serialize(this);
byte[] bytes = TH1Serialization.Serialize(this);
var hash128 = new Hash128();
hash128.Append(bytes);
var hash = hash128.ToString();
@ -2295,7 +2295,7 @@ namespace RuntimeData
{
try
{
byte[] bytes = MemoryPackSerializer.Serialize(config);
byte[] bytes = TH1Serialization.Serialize(config);
if (FileTools.SafeWriteFile(path, bytes)) return true;
retryCount--;
if (retryCount <= 0)
@ -2343,7 +2343,7 @@ namespace RuntimeData
try
{
byte[] bytes = File.ReadAllBytes(path);
var config = MemoryPackSerializer.Deserialize<MapConfig>(bytes);
var config = TH1Serialization.Deserialize<MapConfig>(bytes);
config.ClearMultiCivs();
return config;
@ -2376,14 +2376,14 @@ namespace RuntimeData
// 新版所有 begin / quick_continue / continue / end 都通过 GameArchiveManager 管理。
private static byte[] SerializeMapArchive(MapData map)
{
var rawBytes = MemoryPackSerializer.Serialize(map);
var rawBytes = TH1Serialization.Serialize(map);
return NetworkPayloadCodec.Encode(rawBytes);
}
private static MapData DeserializeMapArchive(byte[] bytes)
{
var rawBytes = NetworkPayloadCodec.DecodeIfNeeded(bytes);
return MemoryPackSerializer.Deserialize<MapData>(rawBytes);
return TH1Serialization.Deserialize<MapData>(rawBytes);
}
// 给新版 GameArchiveManager 使用的 MapData 存档序列化入口。
@ -2961,8 +2961,8 @@ namespace RuntimeData
{
try
{
var bytes1 = MemoryPackSerializer.Serialize(obj1);
var bytes2 = MemoryPackSerializer.Serialize(obj2);
var bytes1 = TH1Serialization.Serialize(obj1);
var bytes2 = TH1Serialization.Serialize(obj2);
return bytes1.SequenceEqual(bytes2);
}
@ -2977,8 +2977,8 @@ namespace RuntimeData
{
try
{
var bytes1 = MemoryPackSerializer.Serialize(obj1);
var bytes2 = MemoryPackSerializer.Serialize(obj2);
var bytes1 = TH1Serialization.Serialize(obj1);
var bytes2 = TH1Serialization.Serialize(obj2);
if (!bytes1.SequenceEqual(bytes2))
{

View File

@ -1,4 +1,4 @@
/*
/*
* @Author:
* @Description:
* @Date: 20250403 11:04:31
@ -15,6 +15,7 @@ using Logic.CrashSight;
using MemoryPack;
using TH1_Logic.Core;
using TH1_Logic.Net;
using TH1_Logic.Tools;
using UnityEngine;
@ -460,7 +461,7 @@ namespace RuntimeData
// mapData.Net.Actions = null;
//
// _bufferWriter.Clear();
// MemoryPackSerializer.Serialize(_bufferWriter, mapData);
// TH1Serialization.Serialize(_bufferWriter, mapData);
//
// mapData.Net.Actions = actions;
//
@ -478,7 +479,7 @@ namespace RuntimeData
try
{
_bufferWriter.Clear();
MemoryPackSerializer.Serialize(_bufferWriter, mapData);
TH1Serialization.Serialize(_bufferWriter, mapData);
var hash128 = new Hash128();
var writtenMemory = _bufferWriter.WrittenMemory;
if (MemoryMarshal.TryGetArray(writtenMemory, out ArraySegment<byte> segment) && segment.Array != null)

View File

@ -15,6 +15,7 @@ using Logic.Pool;
using MemoryPack;
using RuntimeData;
using TH1_Logic.Core;
using TH1_Logic.Tools;
using UnityEngine;
@ -409,7 +410,7 @@ namespace TH1_Logic.AITrain
if (_actionLogicIdData != null) return;
TextAsset asset = TH1Resource.ResourceLoader.Load<TextAsset>($"CommonIdData/CommonIdData");
var data = asset?.bytes ?? Array.Empty<byte>();
_actionLogicIdData = MemoryPackSerializer.Deserialize<ActionLogicIdData>(data) ?? new ActionLogicIdData();
_actionLogicIdData = TH1Serialization.Deserialize<ActionLogicIdData>(data) ?? new ActionLogicIdData();
}
}

View File

@ -1,4 +1,4 @@
/*
/*
* @Author:
* @Description:
* @Date: 20250410 11:04:44
@ -27,6 +27,7 @@ using TH1_Presentation.Sequencer.Task;
using TH1_Renderer;
using TH1_Logic.Net;
using TH1_Logic.Steam;
using TH1_Logic.Tools;
using UnityEngine;
using TH1Renderer;
@ -1831,8 +1832,8 @@ namespace Logic.Action
#if CHECK_ACTIONDEFFERENCE
if (actionParams.MapData == Main.MapData)
{
byte[] bt = MemoryPack.MemoryPackSerializer.Serialize(Main.MapData);
Main.Instance.CheckMapData = MemoryPack.MemoryPackSerializer.Deserialize<MapData>(bt);
byte[] bt = TH1Serialization.Serialize(Main.MapData);
Main.Instance.CheckMapData = TH1Serialization.Deserialize<MapData>(bt);
}
#endif
}

View File

@ -10,6 +10,7 @@ using System.Collections.Generic;
using System.IO;
using Logic.CrashSight;
using MemoryPack;
using TH1_Logic.Tools;
using UnityEngine;
using Vector2 = System.Numerics.Vector2;
@ -123,7 +124,7 @@ namespace TH1_Logic.Comic
return null;
}
ComicAsset comicConfig = MemoryPackSerializer.Deserialize<ComicAsset>(textAsset.bytes);
ComicAsset comicConfig = TH1Serialization.Deserialize<ComicAsset>(textAsset.bytes);
LogSystem.LogInfo($"LoadComicAsset: 加载成功");
return comicConfig;
}
@ -146,7 +147,7 @@ namespace TH1_Logic.Comic
return null;
}
ImageMapData imageMap = MemoryPackSerializer.Deserialize<ImageMapData>(textAsset.bytes);
ImageMapData imageMap = TH1Serialization.Deserialize<ImageMapData>(textAsset.bytes);
LogSystem.LogInfo($"LoadImageMap: 加载成功");
return imageMap;
}
@ -168,7 +169,7 @@ namespace TH1_Logic.Comic
if (!Directory.Exists(folderPath)) Directory.CreateDirectory(folderPath);
string filePath = Path.Combine(folderPath, $"ImageMap.bytes");
byte[] bytes = MemoryPackSerializer.Serialize(_imageMap);
byte[] bytes = TH1Serialization.Serialize(_imageMap);
File.WriteAllBytes(filePath, bytes);
// 刷新 AssetDatabase
@ -193,7 +194,7 @@ namespace TH1_Logic.Comic
if (!Directory.Exists(folderPath)) Directory.CreateDirectory(folderPath);
string filePath = Path.Combine(folderPath, $"ComicAsset.bytes");
byte[] bytes = MemoryPackSerializer.Serialize(_asset);
byte[] bytes = TH1Serialization.Serialize(_asset);
File.WriteAllBytes(filePath, bytes);
// 刷新 AssetDatabase

View File

@ -1,4 +1,4 @@
/*
/*
* @Author:
* @Description:
* @Date: 20250401 11:04:16
@ -27,6 +27,7 @@ using TH1_Logic.MatchConfig;
using TH1_Logic.Net;
using TH1_Logic.Oss;
using TH1_Logic.Steam;
using TH1_Logic.Tools;
using TH1_UI.Controller.Interaction;
using TH1Renderer;
using TH1Resource;
@ -284,8 +285,8 @@ namespace TH1_Logic.Core
GameArchiveManager.Instance.SaveBeginArchive(MapData);
#if CHECK_ACTIONDEFFERENCE
byte[] bt = MemoryPack.MemoryPackSerializer.Serialize(Main.MapData);
Main.Instance.CheckMapData = MemoryPack.MemoryPackSerializer.Deserialize<MapData>(bt);
byte[] bt = TH1Serialization.Serialize(Main.MapData);
Main.Instance.CheckMapData = TH1Serialization.Deserialize<MapData>(bt);
#endif
MapData.RefreshTurn();
}

View File

@ -1,4 +1,4 @@
/*
/*
* @Author:
* @Description:
* @Date: 20250522 11:05:24
@ -237,7 +237,7 @@ namespace RuntimeData
// 统一保存 GameRecordData避免 Add/Remove/Upsert 到处重复序列化逻辑。
private void SaveGameRecordData()
{
byte[] bytes = MemoryPackSerializer.Serialize(_gameRecord);
byte[] bytes = TH1Serialization.Serialize(_gameRecord);
FileTools.SafeWriteFile(Application.persistentDataPath + "/../Config/game_record.dat", bytes);
}
@ -262,7 +262,7 @@ namespace RuntimeData
LogSystem.LogInfo("[GameRecord] 从备份恢复成功");
try
{
byte[] bytes = MemoryPackSerializer.Serialize(_gameRecord);
byte[] bytes = TH1Serialization.Serialize(_gameRecord);
FileTools.SafeWriteFile(path, bytes);
}
catch (Exception e)

View File

@ -1,4 +1,4 @@
/*
/*
* @Author:
* @Description:
* @Date: 20250905 15:09:36
@ -90,7 +90,7 @@ namespace Logic
LogSystem.LogInfo("[InputConfig] 从备份恢复成功");
try
{
byte[] bytes = MemoryPackSerializer.Serialize(_config);
byte[] bytes = TH1Serialization.Serialize(_config);
FileTools.SafeWriteFile(path, bytes);
}
catch (System.Exception e)
@ -111,7 +111,7 @@ namespace Logic
public void SaveInputConfig()
{
if (_config == null) return;
byte[] bytes = MemoryPackSerializer.Serialize(_config);
byte[] bytes = TH1Serialization.Serialize(_config);
FileTools.SafeWriteFile(Application.persistentDataPath + "/../Config/input_config.dat", bytes);
}

View File

@ -12,6 +12,7 @@ using Logic.CrashSight;
using MemoryPack;
using RuntimeData;
using TH1_Logic.MatchConfig;
using TH1_Logic.Tools;
using UnityEngine;
@ -49,7 +50,7 @@ namespace Logic
string filePath = Path.Combine(folderPath, $"{name}.bytes");
var record = new MapRecordData(map, name);
byte[] bytes = MemoryPackSerializer.Serialize(record);
byte[] bytes = TH1Serialization.Serialize(record);
File.WriteAllBytes(filePath, bytes);
// 刷新 AssetDatabase
@ -81,7 +82,7 @@ namespace Logic
return null;
}
MapRecordData map = MemoryPackSerializer.Deserialize<MapRecordData>(textAsset.bytes);
MapRecordData map = TH1Serialization.Deserialize<MapRecordData>(textAsset.bytes);
LogSystem.LogInfo($"LoadMapRecord: 地图 {name} 加载成功");
return map;
}
@ -92,4 +93,4 @@ namespace Logic
}
}
}
}
}

View File

@ -11,6 +11,7 @@ using System.IO;
using Logic.CrashSight;
using MemoryPack;
using RuntimeData;
using TH1_Logic.Tools;
using UnityEngine;
@ -59,7 +60,7 @@ namespace TH1_Logic.MatchConfig
return null;
}
MatchLevelData matchConfig = MemoryPackSerializer.Deserialize<MatchLevelData>(textAsset.bytes);
MatchLevelData matchConfig = TH1Serialization.Deserialize<MatchLevelData>(textAsset.bytes);
LogSystem.LogInfo($"LoadMatchLevelData: 关卡配置加载成功");
return matchConfig;
}
@ -89,7 +90,7 @@ namespace TH1_Logic.MatchConfig
if (!Directory.Exists(folderPath)) Directory.CreateDirectory(folderPath);
string filePath = Path.Combine(folderPath, $"LevelData.bytes");
byte[] bytes = MemoryPackSerializer.Serialize(LevelData);
byte[] bytes = TH1Serialization.Serialize(LevelData);
File.WriteAllBytes(filePath, bytes);
// 刷新 AssetDatabase

View File

@ -28,7 +28,7 @@ namespace Logic.Multilingual
// 原始翻译快照仅在游戏启动时拍照一次apply mod 之前的纯净数据)。
// 之后所有 mod apply / 重 apply 都基于"先 restore 再 apply",避免覆盖叠加。
// key = MultilingualItem.ID, value = 各语种字段的原始值
private Dictionary<uint, OriginalLangFields> _originalSnapshot;
private Dictionary<uint, object> _originalSnapshot;
// 跟踪 export 数据是否已经被 mod 改写过:用于在切语言时判断是否需要重新 apply
// (理论上只有 SaveAndApplyMods 会改写,所以这个标志只在那里翻转)
@ -114,7 +114,7 @@ namespace Logic.Multilingual
_multilingualData.RefreshDict();
if (_multilingualData.ItemDict == null) return;
_originalSnapshot = new Dictionary<uint, OriginalLangFields>(_multilingualData.ItemDict.Count);
_originalSnapshot = new Dictionary<uint, object>(_multilingualData.ItemDict.Count);
foreach (var kv in _multilingualData.ItemDict)
{
_originalSnapshot[kv.Key] = OriginalLangFields.From(kv.Value);
@ -131,7 +131,9 @@ namespace Logic.Multilingual
foreach (var kv in _originalSnapshot)
{
if (!_multilingualData.ItemDict.TryGetValue(kv.Key, out var item)) continue;
kv.Value.RestoreTo(item);
var fields = kv.Value as OriginalLangFields;
if (fields == null) continue;
fields.RestoreTo(item);
}
_modsApplied = false;
}
@ -371,7 +373,7 @@ namespace Logic.Multilingual
/// <summary>
/// 原始翻译快照行:仅保存 mod 会覆盖的字段(与 WorkshopModLoader.SetItemStr 列表对齐)
/// </summary>
internal struct OriginalLangFields
internal sealed class OriginalLangFields
{
public string ZH;
public string TDZH;

View File

@ -1,4 +1,4 @@
using System;
using System;
using System.Threading.Tasks;
using Logic.CrashSight;
using MemoryPack;
@ -9,6 +9,7 @@ using TH1_Logic.Config;
using TH1_Logic.Core;
using TH1_Logic.GameArchive;
using TH1_Logic.Net;
using TH1_Logic.Tools;
using UnityEngine;
namespace TH1_Logic.Oss
@ -55,7 +56,7 @@ namespace TH1_Logic.Oss
ossData.Actions = endMap.Net.Actions;
ossData.CollectData = CollectManager.Instance.CollectData;
ossData.CollectData.MemberId = LobbyManager.Instance.Lobby.GetSelfMemberId();
byte[] bytes = MemoryPackSerializer.Serialize(ossData);
byte[] bytes = TH1Serialization.Serialize(ossData);
_ = UploadGameDataAsync(steamId, bytes);
}
@ -110,7 +111,7 @@ namespace TH1_Logic.Oss
LogSystem.LogInfo($"Collect STS token obtained, expires at {_collectCredentialsExpireTime}");
}
byte[] data = MemoryPackSerializer.Serialize(collectData);
byte[] data = TH1Serialization.Serialize(collectData);
var result = await _uploadService.UploadFileAsync(_cachedCollectCredentials, data);
if (result)
{

View File

@ -1,4 +1,4 @@
using Logic;
using Logic;
using System;
using System.Collections.Generic;
using System.Linq;
@ -12,6 +12,7 @@ using TH1_Core.Managers;
using TH1_Logic.Config;
using TH1_Logic.Core;
using TH1_Logic.Net;
using TH1_Logic.Tools;
using UnityEngine;
namespace TH1_Logic.Steam
@ -25,7 +26,7 @@ namespace TH1_Logic.Steam
{
try
{
var message = MemoryPack.MemoryPackSerializer.Deserialize<BaseMessage>(data);
var message = TH1Serialization.Deserialize<BaseMessage>(data);
if (message == null) return;
if (message.MessageType == P2PMsgType.NetworkStress) return;

View File

@ -1,4 +1,4 @@
/*
/*
* @Author:
* @Description:
* @Date: 20250908 17:09:18
@ -17,6 +17,7 @@ using TH1_Logic.Chat;
using TH1_Logic.Config;
using TH1_Logic.Core;
using TH1_Logic.Net;
using TH1_Logic.Tools;
namespace TH1_Logic.Steam
@ -67,7 +68,7 @@ namespace TH1_Logic.Steam
LobbyVersion = lobbyInfo.Version,
};
byte[] messageBytes = NetworkPayloadCodec.Encode(MemoryPackSerializer.Serialize<BaseMessage>(data));
byte[] messageBytes = NetworkPayloadCodec.Encode(TH1Serialization.Serialize<BaseMessage>(data));
if (SimpleP2P.Instance.SendToWithOutConnect(targetId, messageBytes)) return true;
LogSystem.LogError($"InviteVersionMismatchMessage: 发送给房主失败 owner={lobbyInfo.OwnerId}, lobby={lobbyInfo.LobbyId}");
@ -97,7 +98,7 @@ namespace TH1_Logic.Steam
private static byte[] SerializeForNetwork(BaseMessage message)
{
var rawBytes = MemoryPack.MemoryPackSerializer.Serialize<BaseMessage>(message);
var rawBytes = TH1Serialization.Serialize<BaseMessage>(message);
return NetworkPayloadCodec.Encode(rawBytes);
}

View File

@ -1,4 +1,4 @@

using System;
using System.Collections.Generic;
using System.IO;
@ -17,6 +17,7 @@ using TH1_Logic.Chat;
using TH1_Logic.Config;
using TH1_Logic.Core;
using TH1_Logic.Net;
using TH1_Logic.Tools;
using UnityEngine;
@ -1036,7 +1037,7 @@ namespace TH1_Logic.Steam
};
var data = new InviteMessage();
data.LobbyInfo = lobbyInfo;
byte[] bytes = MemoryPackSerializer.Serialize<BaseMessage>(data);
byte[] bytes = TH1Serialization.Serialize<BaseMessage>(data);
// 优先从缓存获取,否则直接构造 CSteamID
var targetId = _onlineFriendsId.TryGetValue(targetSteamId, out var cachedId) ? cachedId : new CSteamID(targetSteamId);
@ -1103,7 +1104,7 @@ namespace TH1_Logic.Steam
ReporterId = selfId,
Version = ConfigManager.Instance.VersionCfg.CurVersionInfo.Version,
};
var bytes = MemoryPackSerializer.Serialize<BaseMessage>(data);
var bytes = TH1Serialization.Serialize<BaseMessage>(data);
if (!SimpleP2P.Instance.SendToWithOutConnect(targetId, bytes))
{
LogSystem.LogError($"Report lobby failed: send to owner failed, lobby={lobbyInfo.LobbyId}, owner={lobbyInfo.OwnerId}");

View File

@ -9,7 +9,6 @@
using System;
using System.IO;
using Logic.CrashSight;
using MemoryPack;
namespace TH1_Logic.Tools
@ -29,7 +28,7 @@ namespace TH1_Logic.Tools
return null;
}
var data = MemoryPackSerializer.Deserialize<T>(bytes);
var data = TH1Serialization.Deserialize<T>(bytes);
if (data == null)
{
LogSystem.LogError($"反序列化结果无效: {path}");
@ -101,4 +100,4 @@ namespace TH1_Logic.Tools
return true;
}
}
}
}

View File

@ -0,0 +1,48 @@
/*
* @Author: Codex
* @Description: AOT-safe MemoryPack entrypoints for hotfix types
* @Date: 20260611 00:00:00
* @Modify:
*/
using System;
using System.Buffers;
using MemoryPack;
namespace TH1_Logic.Tools
{
public static class TH1Serialization
{
public static byte[] Serialize<T>(T value)
{
return MemoryPackSerializer.Serialize(typeof(T), value);
}
public static byte[] Serialize(Type type, object value)
{
if (type == null) throw new ArgumentNullException(nameof(type));
return MemoryPackSerializer.Serialize(type, value);
}
public static void Serialize<T>(IBufferWriter<byte> writer, T value)
{
if (writer == null) throw new ArgumentNullException(nameof(writer));
MemoryPackSerializer.Serialize(typeof(T), writer, value);
}
public static T Deserialize<T>(byte[] bytes)
{
if (bytes == null) throw new ArgumentNullException(nameof(bytes));
object value = MemoryPackSerializer.Deserialize(typeof(T), bytes);
return value is T data ? data : default;
}
public static object Deserialize(Type type, byte[] bytes)
{
if (type == null) throw new ArgumentNullException(nameof(type));
if (bytes == null) throw new ArgumentNullException(nameof(bytes));
return MemoryPackSerializer.Deserialize(type, bytes);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8f579489cbe74efc80aab7da3c1aa1f3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: