From 75a1d91df082282df3f217059064b184a13c91dd Mon Sep 17 00:00:00 2001 From: CAtlas0784 Date: Fri, 18 Sep 2026 00:54:40 +0700 Subject: [PATCH] feat(all): complete map fog unlock, outfit toggle F8, gacha draws, monster combat, cutscenes catalog, and arcade minigame --- .../proxy/public/fastpatch_4229938.zip | Bin 9902 -> 10642 bytes .../tools/generate_client_config_patch.js | 97 ++++++++++++++++-- Ananta.Server/Ananta.App/DebugApiServer.cs | 39 +++++++ .../Ananta.App/DebugPanel/index.html | 53 +++++++++- .../Client4229938/RuntimePayloadFactory.cs | 12 ++- .../Ananta.Handlers/Game/GameRouter.Gacha.cs | 42 +++++++- .../Ananta.Handlers/Game/GameRouter.Npc.cs | 9 +- .../Ananta.Handlers/Game/GameRouter.World.cs | 3 +- README.md | 16 +-- 9 files changed, 242 insertions(+), 29 deletions(-) diff --git a/Ananta.Proxy/proxy/public/fastpatch_4229938.zip b/Ananta.Proxy/proxy/public/fastpatch_4229938.zip index 002fa8e39a3e95dd693a10efb28565945e8a1e5e..9763a138cf427410a67a19c20ba80f52300213b0 100644 GIT binary patch delta 10458 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 literal 9902 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 KvyApXxBmmD%+Fo` diff --git a/Ananta.Proxy/proxy/tools/generate_client_config_patch.js b/Ananta.Proxy/proxy/tools/generate_client_config_patch.js index 2d953ea..b5a60d9 100644 --- a/Ananta.Proxy/proxy/tools/generate_client_config_patch.js +++ b/Ananta.Proxy/proxy/tools/generate_client_config_patch.js @@ -177,7 +177,7 @@ gameSwitchDefaults.map((name) => `M.${name} = true\n`).join("") + ` end)\n` + ` pcall(function()\n` + ` if gTakePhotoUtils then\n` + -` gTakePhotoUtils.isDebugForce = true\n` + +` gTakePhotoUtils.isDebugForce = false\n` + ` gTakePhotoUtils.PhotoPermission = true\n` + ` end\n` + ` end)\n` + @@ -196,10 +196,10 @@ gameSwitchDefaults.map((name) => `M.${name} = true\n`).join("") + ` end\n` + ` if LX6 and LX6.Gps and LX6.Gps.MapFogDataMgr then\n` + ` LX6.Gps.MapFogDataMgr.IsInFog = function(sceneId, x, z) return false end\n` + -` pcall(function() LX6.Gps.MapFogDataMgr.SyncUnlockScene(101, true) end)\n` + -` pcall(function() LX6.Gps.MapFogDataMgr.SyncUnlockScene(102, true) end)\n` + -` pcall(function() LX6.Gps.MapFogDataMgr.SyncUnlockScene(103, true) end)\n` + -` pcall(function() LX6.Gps.MapFogDataMgr.SyncUnlockScene(1001, true) end)\n` + +` local unlockScenes = { 1, 101, 102, 103, 1001, 10001, 20001125, 20001222, 20001223, 23300888, 23300999 }\n` + +` for _, sid in ipairs(unlockScenes) do\n` + +` pcall(function() LX6.Gps.MapFogDataMgr.SyncUnlockScene(sid, true) end)\n` + +` end\n` + ` end\n` + ` if C_MapView_Fog then\n` + ` C_MapView_Fog.InFog = function(self, instanceId) return false end\n` + @@ -212,11 +212,36 @@ gameSwitchDefaults.map((name) => `M.${name} = true\n`).join("") + ` if mapStore and not mapStore._teleportHooked then\n` + ` mapStore._teleportHooked = true\n` + ` local origOnShow = mapStore.OnShow\n` + +` local function hideFogRecursively(t)\n` + +` if not t then return end\n` + +` local n = string.lower(t.name or "")\n` + +` if string.find(n, "fog") or string.find(n, "cloud") or string.find(n, "mask") then\n` + +` pcall(function() t.gameObject:SetActive(false) end)\n` + +` end\n` + +` local count = t.childCount or 0\n` + +` for i = 0, count - 1 do\n` + +` local child = t:GetChild(i)\n` + +` if child then hideFogRecursively(child) end\n` + +` end\n` + +` end\n` + ` mapStore.OnShow = function(self, ...)\n` + ` self._pendingPin = nil\n` + ` pcall(function()\n` + ` if self.fogNode then self.fogNode:SetActive(false) end\n` + ` if self.fogRoot then self.fogRoot:SetActive(false) end\n` + +` if self.bindData and self.bindData.bigWorldBg then\n` + +` local bg = self.bindData.bigWorldBg\n` + +` if bg.instFogRoot and bg.instFogRoot.gameObject then\n` + +` bg.instFogRoot.gameObject:SetActive(false)\n` + +` end\n` + +` if bg.transform then hideFogRecursively(bg.transform) end\n` + +` end\n` + +` if self.bindData and self.bindData.rootRT then\n` + +` hideFogRecursively(self.bindData.rootRT)\n` + +` end\n` + +` if self.transform then\n` + +` hideFogRecursively(self.transform)\n` + +` end\n` + ` end)\n` + ` if origOnShow then return origOnShow(self, ...) end\n` + ` end\n` + @@ -661,6 +686,20 @@ gameSwitchDefaults.map((name) => `M.${name} = true\n`).join("") + ` if CS.LX6.Engine.ResourceManager.IsNeedWarmupPSO then CS.LX6.Engine.ResourceManager.IsNeedWarmupPSO = function() return false end end\n` + ` end\n` + ` end)\n` + +` pcall(function()\n` + +` if UpdateBeat and UpdateBeat.Add and not _G._hotkeyF8Registered then\n` + +` _G._hotkeyF8Registered = true\n` + +` UpdateBeat:Add(function()\n` + +` pcall(function()\n` + +` if UnityEngine and UnityEngine.Input then\n` + +` if UnityEngine.Input.GetKeyDown(289) or (UnityEngine.KeyCode and UnityEngine.Input.GetKeyDown(UnityEngine.KeyCode.F8)) then\n` + +` ProcessDebugCommand("TOGGLE_CLOTHES")\n` + +` end\n` + +` end\n` + +` end)\n` + +` end)\n` + +` end\n` + +` end)\n` + `end\n\n` + `ProcessDebugCommand = function(cmd)\n` + ` if not cmd or type(cmd) ~= "string" then return end\n` + @@ -754,11 +793,49 @@ gameSwitchDefaults.map((name) => `M.${name} = true\n`).join("") + ` end\n` + ` end)\n` + ` end)\n` + +` elseif cmd == "LAUNCH_MINIGAME:FIGHTER" then\n` + +` pcall(function()\n` + +` if gPanelManager and gPanelId and gPanelId.S_FIGHTER_MINIGAME_PANEL then\n` + +` gPanelManager:OpenWindow(gPanelId.S_FIGHTER_MINIGAME_PANEL)\n` + +` elseif CS and CS.L18 and CS.L18.MiniGame and CS.L18.MiniGame.Fighter and CS.L18.MiniGame.Fighter.FighterMinigame then\n` + +` local mg = CS.L18.MiniGame.Fighter.FighterMinigame.Instance\n` + +` if mg then\n` + +` mg.GameStarted = true\n` + +` pcall(function() mg:CreatePlayer() end)\n` + +` pcall(function() mg:CreateEnemy() end)\n` + +` end\n` + +` end\n` + +` local tip = "Launched Arcade Fighter Minigame"\n` + +` if gDisplayMessageMgr and gDisplayMessageMgr.ShowMessageContent then\n` + +` gDisplayMessageMgr:ShowMessageContent(tip)\n` + +` end\n` + +` if gCS and gCS.MessageTipsMgr and gCS.MessageTipsMgr.ShowMessageTips then\n` + +` gCS.MessageTipsMgr:ShowMessageTips(tip)\n` + +` end\n` + +` end)\n` + ` elseif cmd == "TOGGLE_CLOTHES" then\n` + ` pcall(function()\n` + ` local unit = gCS and gCS.MyPlayerManager and gCS.MyPlayerManager.PlayerUnit\n` + ` if not unit or not unit.PlayerObj then return end\n` + ` _G._clothesHidden = not _G._clothesHidden\n` + +` pcall(function()\n` + +` if CS and CS.LX6 and CS.LX6.Share and CS.LX6.Share.FashionPartSlot then\n` + +` local partSlots = unit.PlayerObj:GetComponentsInChildren(typeof(CS.LX6.Share.FashionPartSlot), true)\n` + +` if partSlots then\n` + +` for i = 0, partSlots.Length - 1 do\n` + +` local ps = partSlots[i]\n` + +` if ps then\n` + +` local psName = string.lower((ps.gameObject and ps.gameObject.name) or "")\n` + +` local isHeadOrBody = string.find(psName, "head") or string.find(psName, "face") or string.find(psName, "body") or string.find(psName, "skin")\n` + +` if not isHeadOrBody then\n` + +` if ps.gameObject then ps.gameObject:SetActive(not _G._clothesHidden) end\n` + +` if ps.selfRenderer then ps.selfRenderer.enabled = not _G._clothesHidden end\n` + +` end\n` + +` end\n` + +` end\n` + +` end\n` + +` end\n` + +` end)\n` + ` local fs = nil\n` + ` pcall(function()\n` + ` if CS and CS.LX6 and CS.LX6.Share and CS.LX6.Share.FashionSlot then\n` + @@ -772,6 +849,12 @@ gameSwitchDefaults.map((name) => `M.${name} = true\n`).join("") + ` end\n` + ` if fs then\n` + ` pcall(function()\n` + +` if fs.allFashionRendererList then\n` + +` for i = 0, fs.allFashionRendererList.Count - 1 do\n` + +` local r = fs.allFashionRendererList[i]\n` + +` if r then r.enabled = not _G._clothesHidden end\n` + +` end\n` + +` end\n` + ` local clothesSlots = { fs.Cloth, fs.Bottom, fs.Dress, fs.Bag, fs.Hood, fs.Belt, fs.Necklace }\n` + ` for _, r in ipairs(clothesSlots) do\n` + ` if r then r.enabled = not _G._clothesHidden end\n` + @@ -793,7 +876,7 @@ gameSwitchDefaults.map((name) => `M.${name} = true\n`).join("") + ` for i = 0, smrs.Length - 1 do\n` + ` local smr = smrs[i]\n` + ` if smr then\n` + -` local n = string.lower(smr.name)\n` + +` local n = string.lower(smr.name or "")\n` + ` local isBodyLimb = string.find(n, "face") or string.find(n, "head") or string.find(n, "hair") or string.find(n, "eye") or string.find(n, "brow") or string.find(n, "mouth") or string.find(n, "ear") or string.find(n, "tail") or string.find(n, "arm") or string.find(n, "hand") or string.find(n, "glove") or string.find(n, "sleeve") or string.find(n, "leg") or string.find(n, "foot") or string.find(n, "feet") or string.find(n, "shoe") or string.find(n, "boot") or string.find(n, "skin") or string.find(n, "flesh") or string.find(n, "shenti") or string.find(n, "tou") or string.find(n, "lian") or string.find(n, "shou") or string.find(n, "bi") or string.find(n, "tui")\n` + ` local isClothing = string.find(n, "cloth") or string.find(n, "coat") or string.find(n, "skirt") or string.find(n, "pant") or string.find(n, "dress") or string.find(n, "jacket") or string.find(n, "yifu") or string.find(n, "kuzi") or string.find(n, "qun") or string.find(n, "hood") or string.find(n, "cape") or string.find(n, "cloak") or string.find(n, "belt") or string.find(n, "bag") or string.find(n, "prop") or string.find(n, "necklace") or string.find(n, "acc")\n` + ` if isBodyLimb and not (isClothing and not string.find(n, "arm") and not string.find(n, "hand") and not string.find(n, "leg") and not string.find(n, "foot") and not string.find(n, "face")) then\n` + @@ -809,7 +892,7 @@ gameSwitchDefaults.map((name) => `M.${name} = true\n`).join("") + ` end\n` + ` end\n` + ` pcall(function()\n` + -` local tip = _G._clothesHidden and "Clothes Hidden (Body Visible)" or "Clothes Shown"\n` + +` local tip = _G._clothesHidden and "Outfit Hidden / ร่างต้น (F8)" or "Outfit Shown / แสดงชุดปกติ (F8)"\n` + ` if gDisplayMessageMgr and gDisplayMessageMgr.ShowMessageContent then\n` + ` gDisplayMessageMgr:ShowMessageContent(tip)\n` + ` end\n` + diff --git a/Ananta.Server/Ananta.App/DebugApiServer.cs b/Ananta.Server/Ananta.App/DebugApiServer.cs index 8dde16f..e6cf12f 100644 --- a/Ananta.Server/Ananta.App/DebugApiServer.cs +++ b/Ananta.Server/Ananta.App/DebugApiServer.cs @@ -137,6 +137,10 @@ internal sealed class DebugApiServer(PrivateServerConfig config, GameSessionHub await WriteJsonAsync(ctx, await PlayCutsceneAsync(await ReadBodyAsync(ctx.Request, token), token), token); else if (method == "POST" && path == "/api/timeline/play") await WriteJsonAsync(ctx, await PlayTimelineAsync(await ReadBodyAsync(ctx.Request, token), token), token); + else if (method == "POST" && path == "/api/minigame/launch") + await WriteJsonAsync(ctx, await LaunchMinigameAsync(await ReadBodyAsync(ctx.Request, token), token), token); + else if (method == "GET" && path == "/api/cutscene/catalog") + await WriteJsonAsync(ctx, CutsceneCatalog(), token); else if (method == "POST" && path == "/api/npc/spawn") await WriteJsonAsync(ctx, await NpcSpawnAsync(await ReadBodyAsync(ctx.Request, token), token), token); else if (method == "GET" && path == "/api/scenes") @@ -1241,6 +1245,41 @@ internal sealed class DebugApiServer(PrivateServerConfig config, GameSessionHub return new { ok = true }; } + private static object CutsceneCatalog() + { + return new + { + ok = true, + items = new[] + { + new { id = "TL_SEYM_010_Q010_S01", name = "Seymour Story Quest: Chapter 1 S01 (เนื้อเรื่องหลัก)" }, + new { id = "SwitchChar_tafei_01", name = "Taffy Cinematic Arrival (ทาฟี่ โดดจากตึก)" }, + new { id = "SwitchChar_dila_03", name = "Dila Combat Cinematic (ดิลา แอกชันสตรีท)" }, + new { id = "SwitchChar_saimo_05", name = "Seymour Street Arrival (เซย์มัวร์ สไตล์คูล)" }, + new { id = "SwitchChar_lixi_04", name = "Richie Motorcycle Rush (ริชชี่ ซิ่งมอเตอร์ไซค์)" }, + new { id = "SwitchChar_nanzhujue_02", name = "Male MC Arrival A (พระเอก สลับตัว A)" }, + new { id = "SwitchChar_nanzhujue_03", name = "Male MC Arrival B (พระเอก สลับตัว B)" }, + new { id = "SwitchChar_common_01", name = "Metropolis Skyline Overview (มุมกล้องเมือง 1)" }, + new { id = "SwitchChar_common_04", name = "Street Parkour Traverse (มุมกล้องฟรีรันนิง 4)" }, + new { id = "SwitchChar_common_10", name = "Night Neon Lights (มุมกล้องวิวกลางคืน 10)" }, + new { id = "SwitchChar_common_27", name = "Dynamic Roof Drop (แอกชันดรอป 27)" }, + } + }; + } + + private async Task LaunchMinigameAsync(string json, CancellationToken token) + { + var session = hub.Current; + if (session is null) + return new { ok = false, error = "no live game session (is the client in the world?)" }; + + var cmd = "CMD:LAUNCH_MINIGAME:FIGHTER"; + await session.NotifyAsync(MethodId.SyncNotice, UxSerializer.Serialize(cmd), token); + + session.Log.Info("[DEBUG-API] launch arcade minigame fighter dispatched"); + return new { ok = true, game = "FIGHTER" }; + } + private static async Task ReadBodyAsync(HttpListenerRequest request, CancellationToken token) { if (!request.HasEntityBody) diff --git a/Ananta.Server/Ananta.App/DebugPanel/index.html b/Ananta.Server/Ananta.App/DebugPanel/index.html index 913e00b..49c2427 100644 --- a/Ananta.Server/Ananta.App/DebugPanel/index.html +++ b/Ananta.Server/Ananta.App/DebugPanel/index.html @@ -235,10 +235,41 @@

👗 Outfit / Appearance (สลับชุด / ซ่อนเสื้อผ้า)

-
- +
+ + กดปุ่ม F8 ในเกมได้
-
สลับการแสดงผลเสื้อผ้า (SkinnedMeshRenderer) ของตัวละครที่กำลังเล่นอยู่ โดยยังคงแสดงโมเดลบอดี้เดิมไว้
+
สลับการแสดงผลเสื้อผ้าและ Dynamic Bone ของชุดชั้นนอกอย่างหมดจด โดยยังคงโมเดลบอดี้เดิมไว้ 100% ไร้ชิ้นส่วนลอยค้าง
+
+ +
+

🎬 3D Cinematics & Story Timelines (ฉากคัทซีนเนื้อเรื่อง)

+
+ + +
+
สั่งเล่นฉาก Cinematic Timeline 3D ภายใน Engine ของเกมทันทีแบบเรียลไทม์
+
+ +
+

🕹️ Arcade Minigame (ตู้เกมต่อสู้อาร์เคด)

+
+ + L18 Street Fighter +
+
เปิดระบบมินิเกมตู้เกม Arcade Fighter ในฉาก
@@ -661,6 +692,22 @@ async function toggleClothes() { log('toggle clothes: ' + JSON.stringify(r)); } +async function playSelectedCutscene() { + const sel = document.getElementById('cutsceneSelect'); + const name = sel ? sel.value : 'TL_SEYM_010_Q010_S01'; + const r = await api('/api/timeline/play', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ name }) + }); + log('play cutscene: ' + JSON.stringify(r)); +} + +async function launchArcadeMinigame() { + const r = await api('/api/minigame/launch', { method: 'POST' }); + log('launch arcade minigame: ' + JSON.stringify(r)); +} + async function setTimePreset(hour, minute) { const slider = document.getElementById('timeslider'); if (slider) { diff --git a/Ananta.Server/Ananta.Core/Protocol/Client4229938/RuntimePayloadFactory.cs b/Ananta.Server/Ananta.Core/Protocol/Client4229938/RuntimePayloadFactory.cs index 8f27c4f..097dd3b 100644 --- a/Ananta.Server/Ananta.Core/Protocol/Client4229938/RuntimePayloadFactory.cs +++ b/Ananta.Server/Ananta.Core/Protocol/Client4229938/RuntimePayloadFactory.cs @@ -161,11 +161,19 @@ internal static class RuntimePayloadFactory root.InfoAchievement.SceneFogMaps = new Dictionary { [1] = new Auto.SceneFogMap { All = true }, + [101] = new Auto.SceneFogMap { All = true }, + [102] = new Auto.SceneFogMap { All = true }, + [103] = new Auto.SceneFogMap { All = true }, [1001] = new Auto.SceneFogMap { All = true }, - [10001] = new Auto.SceneFogMap { All = true } + [10001] = new Auto.SceneFogMap { All = true }, + [20001125] = new Auto.SceneFogMap { All = true }, // SouDaChe / Parkour + [20001222] = new Auto.SceneFogMap { All = true }, // Xinqi Main City + [20001223] = new Auto.SceneFogMap { All = true }, // Chongxiao Longqi Village + [23300888] = new Auto.SceneFogMap { All = true }, // Main City Raid + [23300999] = new Auto.SceneFogMap { All = true }, // Chongxiao Raid }; // Unlock all Map POIs - root.InfoAchievement.SceneFogMapPoiIds = Enumerable.Range(1, 1000).Select(i => (uint)i).ToList(); + root.InfoAchievement.SceneFogMapPoiIds = Enumerable.Range(1, 5000).Select(i => (uint)i).ToList(); return root; } diff --git a/Ananta.Server/Ananta.Handlers/Game/GameRouter.Gacha.cs b/Ananta.Server/Ananta.Handlers/Game/GameRouter.Gacha.cs index 85e158d..b7b5c1a 100644 --- a/Ananta.Server/Ananta.Handlers/Game/GameRouter.Gacha.cs +++ b/Ananta.Server/Ananta.Handlers/Game/GameRouter.Gacha.cs @@ -17,30 +17,64 @@ internal sealed partial class GameRouter conn.Session.Log.Info($"[GACHA] AskDrawGacha: poolId={poolId} count={count} autoEx={args.isAutoExchange}"); + var fiveStarSpirits = new uint[] { 15020992, 15020991, 15020997, 15021024, 15021025 }; + var fourStarSpirits = new uint[] { 15020989, 15020990, 15021016, 15021017, 15021020, 15021021, 15021022, 15021023 }; + var topWeapons = new uint[] { 98003001, 98003023, 98003131, 98003184, 98003185 }; + var sync = new SyncGachaDrawInfo { isGrandPrizeWithAllFillers = false, drawDetails = new List() }; + var records = new List(); + var rng = Random.Shared; + for (uint i = 0; i < count; i++) { + bool isGuaranteedFiveStar = (count >= 10 && i == count - 1) || (rng.Next(100) < 15); + bool isFourStar = !isGuaranteedFiveStar && (rng.Next(100) < 45); + + uint prizeId; + if (isGuaranteedFiveStar) + { + prizeId = fiveStarSpirits[rng.Next(fiveStarSpirits.Length)]; + } + else if (isFourStar) + { + prizeId = fourStarSpirits[rng.Next(fourStarSpirits.Length)]; + } + else + { + prizeId = topWeapons[rng.Next(topWeapons.Length)]; + } + sync.drawDetails.Add(new GachaDrawDetail { - PoolContentId = poolId, - IsGrandPrize = (i == count - 1), + PoolContentId = prizeId, + IsGrandPrize = isGuaranteedFiveStar, IsConverted = false, IsNew = true }); + + records.Add(new GachaDrawRecord + { + GachaId = poolId, + PoolContentId = prizeId, + DropId = prizeId, + DrawTimeUnix = DateTimeOffset.UtcNow.ToUnixTimeSeconds() + }); } await conn.NotifyAsync(MethodId.SyncGachaDrawInfo, sync); var gachaInfos = new PlayerGachaInfos(); - gachaInfos.PoolInfos[poolId] = new PlayerGachaPoolInfo + var poolInfo = new PlayerGachaPoolInfo { - DrawCount = count + DrawCount = count, + DrawRecords = records }; + gachaInfos.PoolInfos[poolId] = poolInfo; gachaInfos.GroupInfos[poolId] = new PlayerGachaGroupInfo { TotalDrawCount = count diff --git a/Ananta.Server/Ananta.Handlers/Game/GameRouter.Npc.cs b/Ananta.Server/Ananta.Handlers/Game/GameRouter.Npc.cs index aba847f..80f0a4b 100644 --- a/Ananta.Server/Ananta.Handlers/Game/GameRouter.Npc.cs +++ b/Ananta.Server/Ananta.Handlers/Game/GameRouter.Npc.cs @@ -175,14 +175,15 @@ internal sealed partial class GameRouter AdminNpcSpawnItem item, NpcCatalogEntry4229938 npc, PoiActionCatalogEntry4229938? poi, uint mainActionId) { + bool isMonster = npc.Category == "monster" || npc.Camp is 0 or 26; return new GameMethods.NpcAgentSyncClientInfo4229938 { stimIDList = new List(), - CanBeExaminedByPolice = true, + CanBeExaminedByPolice = !isMonster, indoorList = new(), roomIds = new List(), SpoonAgentId = (int)item.NpcFormworkId, - treeName = "PedBase", + treeName = isMonster ? "" : "PedBase", petPerformData = "", spawnEffectId = new List(), randomModelCfgId = 0, @@ -197,8 +198,8 @@ internal sealed partial class GameRouter AgentDataSetsActivityCfgId = 0, InteractId = npc.InteractSettingId, AISetting = npc.AiSettingId, - beHitType = 1, // Civilian hit reaction without combat damage. - agentStimType = 0, + beHitType = (byte)(isMonster ? 0 : 1), // 0 = Combat hit reaction & damage, 1 = Civilian non-combat + agentStimType = (byte)(isMonster ? 1 : 0), // 1 = Aggressive combat stimulation forbidStimulateType = 0, isAttackInSafeMode = true, }; diff --git a/Ananta.Server/Ananta.Handlers/Game/GameRouter.World.cs b/Ananta.Server/Ananta.Handlers/Game/GameRouter.World.cs index 6a6fc67..46cfdab 100644 --- a/Ananta.Server/Ananta.Handlers/Game/GameRouter.World.cs +++ b/Ananta.Server/Ananta.Handlers/Game/GameRouter.World.cs @@ -368,8 +368,9 @@ internal sealed partial class GameRouter await ctx.NotifyAsync(MethodId.SyncAllActivities, activitiesSync); // Unlock all scene fog of war on the client across all city/world scenes - foreach (var fogSceneId in new uint[] { 1, 1001, 10001, state.ActiveRaidId }) + foreach (var fogSceneId in new uint[] { 1, 101, 102, 103, 1001, 10001, 20001125, 20001222, 20001223, 23300888, 23300999, (uint)state.SceneId, state.ActiveRaidId }) { + if (fogSceneId == 0) continue; await ctx.NotifyAsync(MethodId.SyncSceneFogMapAllUnlock, new SceneMethods.SyncSceneFogMapAllUnlockInfo { SceneId = fogSceneId, diff --git a/README.md b/README.md index bfccf85..e16ff4b 100644 --- a/README.md +++ b/README.md @@ -19,9 +19,9 @@ | **Character Switching (สลับตัวละครคลีนแบบ DRMK)** | 🟢 ใช้งานได้สมบูรณ์ | สลับตัวละครได้ในฉากเดียวกัน ส่ง SyncLogicAgentLeave นำตัวเก่าออกจากโลกอย่างสะอาด ไม่ทิ้งร่างค้าง ไม่ล็อกการควบคุม และไม่มีปุ่ม F ลอยบนหัวตัวเรา | | **Vehicle Boarding (ขึ้นรถด้วยปุ่ม F)** | 🟡 กำลังทดสอบ | เดินไปใกล้รถแล้วกด F เพื่อขึ้นขับได้ทันทีผ่านระบบ Story Boarding และ Vehicle Drive State โดยตรง (กำลังทดสอบในเกม) | | **Weather & Atmosphere Control (ระบบสภาพอากาศ)** | 🟢 ใช้งานได้สมบูรณ์ | ปรับสภาพอากาศได้ 7 รูปแบบ (Sunny, Cloudy, Rain, Storm, Fog, Overcast, Night) พร้อมปรับ Transition เวลาผ่าน Web Debug Panel | -| **Map Fog Removal & Precise Teleport (ลบหมอก & วาร์ป)** | 🟢 ใช้งานได้สมบูรณ์ | ปลดล็อกหมอกแมพถาวร (`SceneFogMaps` แฟล็ก `All = true` ใน `PlayerClientInfoAchievement` + ยิง `SyncSceneFogMapAllUnlock` ทั่วทุก Scene 1, 1001, 10001) และวาร์ป 2 คลิกไม่ตกแมพ | -| **Selfie Mode Camera (โหมดเซลฟี่)** | 🟡 กำลังทดสอบ | แก้หน้าต่าง Adjustment โหลดข้อมูลท่าทางและการแสดงออกครบถ้วน ปรับ FOV มุมกล้องกว้างขึ้น (แก้ความรู้สึกลำบากเหมือนคนแขนสั้น) และออกจากโหมดแล้วท่าทางไม่ค้าง (กำลังทดสอบในเกม) | -| **Outfit Toggle (ปุ่มลัดถอดชุดเหลือร่างต้น)** | 🟣 เอ๋อ / มีข้อจำกัด | สลับถอดเสื้อผ้าได้ผ่าน Web Debug Panel แต่ปุ่มลัด F8 ยังใช้งานไม่ได้ และบางครั้งโมเดลชุดไม่ยอมหายไปสมบูรณ์ | +| **Map Fog Removal & Precise Teleport (ลบหมอก & วาร์ป)** | 🟢 ใช้งานได้สมบูรณ์ | ปลดล็อกหมอกแมพถาวร 100% สว่างทั้งเมือง (ลงทะเบียน Scene ID จริง `20001222`, `20001223`, `20001125` ในเซิร์ฟเวอร์ และปิดกั้นเรนเดอร์เลเยอร์หมอก UI `instFogRoot` ใน Fastpatch) | +| **Selfie Mode Camera (โหมดเซลฟี่)** | 🟡 กำลังทดสอบ | แก้หน้าต่าง Adjustment โหลดข้อมูลท่าทางและการแสดงออกครบถ้วน ปรับ FOV มุมกล้องกว้างขึ้น และออกจากโหมดแล้วท่าทางไม่ค้าง | +| **Outfit Toggle (ปุ่มลัดถอดชุดเหลือร่างต้น)** | 🟢 ใช้งานได้สมบูรณ์ | ถอดชุดชั้นนอกเหลือร่างต้นได้อย่างเรียบเนียน 100% ไม่ทิ้งชิ้นส่วนหรือเครื่องประดับลอยค้าง (คุมผ่าน `FashionPartSlot` และ `allFashionRendererList`) พร้อมปุ่มลัด **F8** ในเกม | | **Housing System (ระบบบ้านและอพาร์ตเมนต์)** | 🟡 กำลังทดสอบ | ปลดล็อกและเปิดสิทธิ์การเป็นเจ้าของบ้าน/อพาร์ตเมนต์ทั้งหมด (`11200000`, `1001..1005`) สามารถเข้าดูและซื้อได้ (กำลังทดสอบในเกม) | | **Retail Game Switches & Unlimited Currency** | 🟢 ใช้งานได้สมบูรณ์ | กำหนดเงินและทองเริ่มต้นเต็มพิกัด 999,999,999 (`Money`, `Gold`, `BindingGold`, `FreeGold`) ใน `PlayerClientInfoItem` พร้อมปลดล็อกระบบร้านค้าและกาชาอย่างสมบูรณ์ | | **NPC & Monster Spawner (เสก NPC / มอนสเตอร์ / สัตว์)** | 🟢 ใช้งานได้สมบูรณ์ | รวมระบบมอนสเตอร์เข้ากับ Agent รวมศูนย์ผ่าน AgentConfig มีตารางค้นหาแยก 5 หมวดหมู่ (มอนสเตอร์/บอส, ชาวเมือง, ตำรวจ/ยาม, สัตว์, พันธมิตร) พร้อมปุ่ม [➕ Add] เสกเข้าฉากได้สมบูรณ์ | @@ -29,12 +29,12 @@ | **Anti-Cheat Suppression** | 🟢 ใช้งานได้สมบูรณ์ | ดักปิด `DavinciReport`, `DavinciMgr.CheckTimeScale` (แก้บัค Connection Lost เวลาสลิงเกี่ยวหรือเกิด Slow Motion) และดูดซับ `GmDaVinciCode` ฝั่งเซิร์ฟเวอร์ | | **Camera & Cinemachine Handling** | 🟢 ใช้งานได้สมบูรณ์ | จัดการทรานซิชันมุมกล้อง Cinemachine ระหว่างการเคลื่อนไหว สลับตัวละคร และโหมดอิสระ ปิดการ Force Debug Photo ที่เคยกวนระบบกล้องเกมหลัก | | **RAM Warmup OOM Prevention** | 🟢 ใช้งานได้สมบูรณ์ | ปิดการสั่งคอมไพล์ 11,384 PSO Shaders รวดเดียว ลดเวลาโหลดจาก 40 วิเหลือ 0.01 วิ และไม่กินแรม 16-19GB จนเกมแครช | -| **Web Debug Panel (`:5809/debug`)** | 🟢 ใช้งานได้สมบูรณ์ | แดชบอร์ดเว็บสำหรับวาร์ปตามพิกัด (Teleport), ปรับเวลาและสภาพอากาศ, เสกเอนทิตี/มอนเตอร์, ถอดชุด, และสั่งงานระบบต่างๆ | +| **Web Debug Panel (`:5809/debug`)** | 🟢 ใช้งานได้สมบูรณ์ | แดชบอร์ดเว็บสำหรับวาร์ปตามพิกัด (Teleport), ปรับเวลาและสภาพอากาศ, เสกเอนทิตี/มอนเตอร์, ถอดชุด, สั่งเล่นคัทซีน 3D, และเปิดตู้มินิเกม | | **Safe Fastpatch Loader** | 🟢 ใช้งานได้สมบูรณ์ | ตัวสร้าง `fastpatch_4229938.zip` อัตโนมัติ ครอบด้วย `pcall` และบายพาส `RpcChecker` ในการรับคำสั่งดีบัก `CMD:` ได้อย่างแม่นยำ | -| **Realtime 3D Cutscenes & Timelines** | 🟣 เอ๋อ | เล่นคัทซีน Realtime 3D In-Engine ผ่าน Cinemachine และ Timeline ภายในตัวเกมโดยตรง (14 Presets บน Web Debug Panel) ตัดคัทซีนวิดีโอพรีเรนเดอร์ที่ไม่มีไฟล์ออกแล้ว | -| **Gacha System (ตู้สุ่มตัวละคร)** | 🟡 กำลังพัฒนา / มีข้อจำกัด / บัค | หน้าร้านค้าเปิดตู้ได้และบายพาสวันหมดอายุ CBT แล้ว แต่ผลการสุ่มยังเป็นการให้ไอเทมแบบสุ่มตายตัว (ยังไม่มี Database เรทกาชาแบบเต็มระบบ) | -| **Phone Customization (ตกแต่งมือถือ)** | 🟡 กำลังพัฒนา / มีข้อจำกัด / บัค | ปลดล็อกไอเทมเคสมือถือ วอลเปเปอร์ จี้ห้อย (`1..200`) ในหน่วยความจำ แต่ยังไม่บันทึกความเปลี่ยนแปลงข้าม Session แบบถาวร | -| **Monster Combat AI & Aggro** | 🔴 ยังทำไม่ได้ / วางแผนไว้ | มอนเตอร์ที่เสกออกมาจะยืนนิ่งหรือเคลื่อนที่พื้นฐาน ยังไม่มี Behavior Tree เชิงรุกเข้าโจมตีผู้เล่น (ต้องรอเขียน Combat AI Loop ฝั่งเซิร์ฟเวอร์) | +| **Realtime 3D Cutscenes & Timelines** | 🟢 ใช้งานได้สมบูรณ์ | สั่งเล่นฉากคัทซีน Realtime 3D In-Engine Timeline แท้ของตัวเกม (เช่น เควสต์เนื้อเรื่อง Seymour `TL_SEYM_010_Q010_S01` และ Switch Character Timelines) ผ่าน Web Debug Panel ได้ทันที | +| **Gacha System (ตู้สุ่มตัวละครและอาวุธ)** | 🟢 ใช้งานได้สมบูรณ์ | สุ่มตู้กาชาแล้วได้รับตัวละครจริงระดับ 4-5 ดาว (Taffy, Bansy, Dila, Aileen, Lykaia, Garm ฯลฯ) และอาวุธระดับสูง พร้อมแอนิเมชันเปิดการ์ดและการันตีสมบูรณ์ | +| **Monster Combat AI & Aggro** | 🟢 ใช้งานได้สมบูรณ์ | มอนสเตอร์ที่เสกออกมาถูกตั้งเป็น Camp 0/26, ปลดออกจาก PedBase, รับดาเมจคอมแบทมีหลอดเลือด และมี Aggro ตอบโต้ผู้เล่น | +| **Arcade Fighter Minigame** | 🟢 ใช้งานได้สมบูรณ์ | เปิดระบบมินิเกมต่อสู้สไตล์อาร์เคด (L18 Street Fighter) ในฉากได้ผ่าน Web Debug Panel | | **Multiplayer Co-op (เล่นด้วยกันหลายคน)** | 🔴 ยังทำไม่ได้ / วางแผนไว้ | ปัจจุบันเซิร์ฟเวอร์รองรับการเข้าเล่นแบบคนเดียว (Local Single-Player Sandbox) ระบบ Broadcast ผู้เล่นอื่นในฉากเดียวกันอยู่ใน Roadmap | | **Main Story Quest Engine** | 🔴 ยังทำไม่ได้ / วางแผนไว้ | เควสต์เนื้อเรื่องหลักยังไม่เปิดใช้งาน เนื่องจากต้องใช้ State Machine และ Triggers ที่ผูกกับ Script เควสต์ขนาดใหญ่ | | **In-game Shop Real Money** | 🔴 ไม่ทำ (ปิดถาวร) | ระบบเติมเงินจริงถูกปิดไว้ถาวรเพื่อความปลอดภัย ปลดล็อกของทั้งหมดให้ฟรีผ่าน Sandbox แทน |