diff --git a/Tools/OSS/game-upload-function/index.js b/Tools/OSS/game-upload-function/index.js index 14e8478d7..1c78c90d6 100644 --- a/Tools/OSS/game-upload-function/index.js +++ b/Tools/OSS/game-upload-function/index.js @@ -9,7 +9,7 @@ const TableStore = require('tablestore'); const MAX_BODY_SIZE = 1024; const PORT = 9000; const TOKEN_CACHE_DURATION_MS = 5 * 60 * 1000; // 5分钟 -const MAX_UPLOAD_SIZE = 2 * 1024 * 1024; // 2MB +const MAX_UPLOAD_SIZE = 3 * 1024 * 1024; // 3MB const STS_DURATION_SECONDS = 900; // 15分钟 /** @@ -26,8 +26,10 @@ function getOtsClient() { /** * 从 Tablestore 获取缓存的令牌 + * @param {string} steamId + * @param {string|null} version 客户端版本号,null 表示老版本未传 */ -async function getCachedToken(steamId) { +async function getCachedToken(steamId, version) { const otsClient = getOtsClient(); const params = { @@ -54,6 +56,14 @@ async function getCachedToken(steamId) { : value; } + // 版本号比对:缓存中存储的版本号(无版本号时为空字符串或不存在) + const cachedVersion = attrs.version || null; + const requestVersion = version || null; + if (cachedVersion !== requestVersion) { + console.log(`[缓存查询] SteamID: ${steamId} 版本号不匹配,缓存版本: ${cachedVersion ?? '(无)'}, 请求版本: ${requestVersion ?? '(无)'},忽略缓存`); + return null; + } + const issuedAt = attrs.issuedAt; if (!issuedAt || Date.now() - issuedAt > TOKEN_CACHE_DURATION_MS) { console.log(`[缓存查询] SteamID: ${steamId} 缓存已过期(签发时间: ${new Date(issuedAt).toISOString()})`); @@ -68,7 +78,7 @@ async function getCachedToken(steamId) { } const expiresIn = Math.floor((stsExpireAt - Date.now()) / 1000); - console.log(`[缓存命中] SteamID: ${steamId} 命中缓存,剩余有效期 ${expiresIn} 秒`); + console.log(`[缓存命中] SteamID: ${steamId} 命中缓存,版本: ${cachedVersion ?? '(无)'},剩余有效期 ${expiresIn} 秒`); return { accessKeyId: attrs.accessKeyId, @@ -89,34 +99,41 @@ async function getCachedToken(steamId) { /** * 将令牌存入 Tablestore + * @param {string} steamId + * @param {object} tokenData + * @param {string|null} version 客户端版本号,null 表示老版本未传 */ -async function saveTokenToCache(steamId, tokenData) { +async function saveTokenToCache(steamId, tokenData, version) { const otsClient = getOtsClient(); const now = Date.now(); const stsExpireAt = now + tokenData.expiresIn * 1000; + const attributeColumns = [ + { accessKeyId: tokenData.accessKeyId }, + { accessKeySecret: tokenData.accessKeySecret }, + { securityToken: tokenData.securityToken }, + { endpoint: tokenData.endpoint }, + { bucket: tokenData.bucket }, + { objectKey: tokenData.objectKey }, + { policy: tokenData.policy }, + { signature: tokenData.signature }, + { issuedAt: TableStore.Long.fromNumber(now) }, + { stsExpireAt: TableStore.Long.fromNumber(stsExpireAt) }, + // version 为 null 时存空字符串,与查询时保持一致 + { version: version !== null && version !== undefined ? version : '' } + ]; + const params = { tableName: 'Players', condition: new TableStore.Condition(TableStore.RowExistenceExpectation.IGNORE, null), primaryKey: [{ PlayerId: steamId }], - attributeColumns: [ - { accessKeyId: tokenData.accessKeyId }, - { accessKeySecret: tokenData.accessKeySecret }, - { securityToken: tokenData.securityToken }, - { endpoint: tokenData.endpoint }, - { bucket: tokenData.bucket }, - { objectKey: tokenData.objectKey }, - { policy: tokenData.policy }, - { signature: tokenData.signature }, - { issuedAt: TableStore.Long.fromNumber(now) }, - { stsExpireAt: TableStore.Long.fromNumber(stsExpireAt) } - ], + attributeColumns, returnContent: { returnType: TableStore.ReturnType.NONE } }; try { - console.log(`[缓存写入] 正在写入 SteamID: ${steamId} 的令牌缓存...`); + console.log(`[缓存写入] 正在写入 SteamID: ${steamId} 的令牌缓存,版本: ${version ?? '(无)'}...`); await otsClient.putRow(params); console.log(`[缓存写入] SteamID: ${steamId} 缓存写入成功,过期时间: ${new Date(stsExpireAt).toISOString()}`); } catch (e) { @@ -270,6 +287,10 @@ async function handleRequest(req, res) { try { const requestData = JSON.parse(body || '{}'); const { steamId, authTicket } = requestData; + // version 为可选字段,老版本不传则为 null + const version = (typeof requestData.version === 'string' && requestData.version.trim() !== '') + ? requestData.version.trim() + : null; if (!steamId) { console.warn('[参数校验] 缺少 steamId 参数'); @@ -286,10 +307,10 @@ async function handleRequest(req, res) { } const requestId = req.headers['x-fc-request-id'] || '-'; - console.log(`[请求开始] RequestId: ${requestId},SteamID: ${steamId},AuthTicket长度: ${authTicket.length}`); + console.log(`[请求开始] RequestId: ${requestId},SteamID: ${steamId},AuthTicket长度: ${authTicket.length},版本: ${version ?? '(无)'}`); - // 1. 先检查 Tablestore 缓存 - const cachedToken = await getCachedToken(steamId); + // 1. 先检查 Tablestore 缓存(版本号必须一致才命中) + const cachedToken = await getCachedToken(steamId, version); if (cachedToken) { console.log(`[请求完成] RequestId: ${requestId},SteamID: ${steamId} — 返回缓存令牌,剩余有效期 ${cachedToken.expiresIn} 秒`); res.writeHead(200, { 'Content-Type': 'application/json' }); @@ -316,7 +337,10 @@ async function handleRequest(req, res) { apiVersion: '2015-04-01' }); - const objectKey = `${steamId}/${Date.now()}.dat`; + // 根据版本号构建文件路径:有版本号时为 {version}/{steamId}/...,无版本号时为 common/{steamId}/... + const pathPrefix = version !== null ? version : 'common'; + const objectKey = `${pathPrefix}/${steamId}/${Date.now()}.dat`; + console.log(`[路径构建] SteamID: ${steamId},版本: ${version ?? '(无)'},ObjectKey: ${objectKey}`); const stsParams = { RoleArn: process.env.ROLE_ARN, @@ -356,8 +380,8 @@ async function handleRequest(req, res) { expiresIn: STS_DURATION_SECONDS }; - // 5. 存入 Tablestore 缓存 - await saveTokenToCache(steamId, tokenData); + // 5. 存入 Tablestore 缓存(携带版本号) + await saveTokenToCache(steamId, tokenData, version); console.log(`[请求完成] RequestId: ${requestId},SteamID: ${steamId} 全流程完成 ✅(验证 → 签发 → Policy → 缓存)`); @@ -376,4 +400,4 @@ async function handleRequest(req, res) { const server = http.createServer(handleRequest); server.listen(PORT, '0.0.0.0', () => { console.log(`[服务启动] 服务器已启动,监听端口: ${PORT},最大上传文件: ${MAX_UPLOAD_SIZE} 字节`); -}) \ No newline at end of file +}) diff --git a/Unity/Assets/Scripts/TH1_Data/MapData.cs b/Unity/Assets/Scripts/TH1_Data/MapData.cs index 2c0191eeb..6e715e148 100644 --- a/Unity/Assets/Scripts/TH1_Data/MapData.cs +++ b/Unity/Assets/Scripts/TH1_Data/MapData.cs @@ -1326,13 +1326,13 @@ namespace RuntimeData } // 当场上有小兵死亡时 - public void OnAnyUnitDie(MapData map) + public void OnAnyUnitDie(MapData map, UnitData dieUnit) { foreach (var unit in UnitMap.UnitList) { //避免在遍历的时候,直接改到了skillsList var copy = new List(unit.Skills); - foreach (var skill in copy) skill.OnAnyUnitDie(map, unit); + foreach (var skill in copy) skill.OnAnyUnitDie(map, unit, dieUnit); } } diff --git a/Unity/Assets/Scripts/TH1_Logic/Config/VersionConfig.cs b/Unity/Assets/Scripts/TH1_Logic/Config/VersionConfig.cs index 6cf7cab35..c4bc6363e 100644 --- a/Unity/Assets/Scripts/TH1_Logic/Config/VersionConfig.cs +++ b/Unity/Assets/Scripts/TH1_Logic/Config/VersionConfig.cs @@ -40,7 +40,7 @@ namespace Logic.Config { if (version.VersionId == versionId) return version; } - return null; + return Versions[0]; } diff --git a/Unity/Assets/Scripts/TH1_Logic/Editor/OssEditorWindow.cs b/Unity/Assets/Scripts/TH1_Logic/Editor/OssEditorWindow.cs index bb860c4f1..ae72e8409 100644 --- a/Unity/Assets/Scripts/TH1_Logic/Editor/OssEditorWindow.cs +++ b/Unity/Assets/Scripts/TH1_Logic/Editor/OssEditorWindow.cs @@ -7,7 +7,9 @@ using System; +using System.IO; using System.Text; +using MemoryPack; using Steamworks; using TH1_Logic.Net; using TH1_Logic.Oss; @@ -86,6 +88,11 @@ namespace Logic.Editor if (InspectorUtils.InspectorButtonWithTextWidth("测试5: 上传文件到OSS(大文件)")) { TestUploadBigFile(); + } + + if (InspectorUtils.InspectorButtonWithTextWidth("测试存档反序列化")) + { + TestDeserializeArchive(); } EditorGUILayout.EndScrollView(); @@ -209,5 +216,60 @@ namespace Logic.Editor ? "完整流程测试成功!" : "完整流程测试失败"); } + + // 测试存档反序列化 + public void TestDeserializeArchive() + { + string path = "F:/gamerecord/"; + + if (!Directory.Exists(path)) + { + Debug.LogError($"路径不存在: {path}"); + return; + } + + var datFiles = Directory.GetFiles(path, "*.dat"); + + if (datFiles.Length == 0) + { + Debug.LogWarning($"路径下没有找到 .dat 文件: {path}"); + return; + } + + Debug.Log($"=== 开始测试存档反序列化,共找到 {datFiles.Length} 个文件 ==="); + + int successCount = 0; + int failCount = 0; + + foreach (var filePath in datFiles) + { + string fileName = Path.GetFileName(filePath); + try + { + byte[] data = File.ReadAllBytes(filePath); + Debug.Log($"读取文件: {fileName}, 大小: {data.Length} bytes"); + + var ossData = MemoryPackSerializer.Deserialize(data); + + if (ossData != null) + { + Debug.Log($"[成功] {fileName} 反序列化成功"); + successCount++; + } + else + { + Debug.LogError($"[失败] {fileName} 反序列化结果为 null"); + failCount++; + } + } + catch (Exception ex) + { + Debug.LogError($"[异常] {fileName} 反序列化失败: {ex.Message}"); + failCount++; + } + } + + Debug.Log($"=== 反序列化完成: 成功 {successCount} / 失败 {failCount} / 共 {datFiles.Length} 个文件 ==="); + } } } \ No newline at end of file diff --git a/Unity/Assets/Scripts/TH1_Logic/Oss/StsTokenService.cs b/Unity/Assets/Scripts/TH1_Logic/Oss/StsTokenService.cs index 8e08b82cc..cab04ec10 100644 --- a/Unity/Assets/Scripts/TH1_Logic/Oss/StsTokenService.cs +++ b/Unity/Assets/Scripts/TH1_Logic/Oss/StsTokenService.cs @@ -2,6 +2,7 @@ using System.Text; using System.Threading.Tasks; using Logic.CrashSight; +using TH1_Logic.Config; using UnityEngine; using UnityEngine.Networking; @@ -35,7 +36,8 @@ namespace TH1_Logic.Oss var requestBody = JsonUtility.ToJson(new StsRequest { steamId = steamId, - authTicket = authTicket + authTicket = authTicket, + version = ConfigManager.Instance.VersionCfg.CurVersionInfo.Version, }); var bodyBytes = Encoding.UTF8.GetBytes(requestBody); @@ -65,6 +67,7 @@ namespace TH1_Logic.Oss { public string steamId; public string authTicket; + public string version; } } } \ No newline at end of file diff --git a/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/MeilingRestSkill.cs b/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/MeilingRestSkill.cs index b186d5f89..d84340748 100644 --- a/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/MeilingRestSkill.cs +++ b/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/MeilingRestSkill.cs @@ -50,7 +50,7 @@ namespace Logic.Skill RefreshAroundGiant(map, self); } - public override void OnAnyUnitDie(MapData map, UnitData self) + public override void OnAnyUnitDie(MapData map, UnitData self, UnitData dieUnit) { RefreshAroundGiant(map, self); } diff --git a/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/RinCorpseColletSkill.cs b/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/RinCorpseColletSkill.cs index a5d753ba6..c69a6b3d6 100644 --- a/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/RinCorpseColletSkill.cs +++ b/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/RinCorpseColletSkill.cs @@ -23,6 +23,11 @@ namespace Logic.Skill { return SkillType.RinCorpseCollet; } + + public override void OnAnyUnitDie(MapData map, UnitData self, UnitData dieUnit) + { + + } } } diff --git a/Unity/Assets/Scripts/TH1_Logic/Skill/SkillBase.cs b/Unity/Assets/Scripts/TH1_Logic/Skill/SkillBase.cs index 1e99544e5..d8b15de6e 100644 --- a/Unity/Assets/Scripts/TH1_Logic/Skill/SkillBase.cs +++ b/Unity/Assets/Scripts/TH1_Logic/Skill/SkillBase.cs @@ -366,7 +366,7 @@ namespace Logic.Skill public void OnAnyUnitMove(MapData map, UnitData self, UnitData moveUnit, GridData target, MoveType moveType); // 当有单位死亡时 - public void OnAnyUnitDie(MapData map, UnitData self); + public void OnAnyUnitDie(MapData map, UnitData self, UnitData dieUnit); // 当有单位创建时 public void OnAnyUnitCreate(MapData map, UnitData self, UnitData newUnit); @@ -797,7 +797,7 @@ namespace Logic.Skill } - public virtual void OnAnyUnitDie(MapData map, UnitData self) + public virtual void OnAnyUnitDie(MapData map, UnitData self, UnitData dieUnit) { } diff --git a/Unity/Assets/Scripts/TH1_Logic/Unit/UnitLogic.cs b/Unity/Assets/Scripts/TH1_Logic/Unit/UnitLogic.cs index b52c0b08f..cd29d7901 100644 --- a/Unity/Assets/Scripts/TH1_Logic/Unit/UnitLogic.cs +++ b/Unity/Assets/Scripts/TH1_Logic/Unit/UnitLogic.cs @@ -594,8 +594,8 @@ namespace Logic }); } + map.OnAnyUnitDie(map, unit); map.SetUnitDataDie(unit); - map.OnAnyUnitDie(map); } //unit非自然死亡,如背盟、国家灭亡、解散、被挤死等