fix(scene): unlock teleport pillars on maps missing from mapDefaultEntranceMap

The user report: pillars visible on the map but locked, and clicking a
teleport does nothing (client never sends EnterScene).

Root cause: mapDefaultEntranceMap covers only 115 of 371 floors - the
GetSceneMapInfo reply had no unlocked teleports for the missing floors
(mostly new-region 2xxxxx maps), so the client locked the pillars and
never initiated the teleport.

- findEntryForFloor: resolve entry by searching config names P*_F<floor>
  directly, with mapDefaultEntranceMap as the first chance
- GetSceneMapInfo: use the new resolver and merge teleports.json keys
  into unlocked_teleport_list for every floor
- EnterScene: floor ids resolve through the same path; a teleport id
  arriving via scene_identifier (MDAIDPPKOPO.PLIDNBMCIJH) now also
  resolves the destination entry
- loadScene: exact teleport position from teleports.json when the res
  config has no inline teleport with that id
This commit is contained in:
CAtlas0784 committed 2026-10-07 01:45:56 +07:00
1 parent 72861c3028
commit d364b9616f
4 files changed
+90 -12

No files matched your search

+1
View File
@@ -2,3 +2,4 @@
gameserver.log
server_debug.log
*.log
*.exe~
+66 -5
View File
@@ -120,12 +120,18 @@ func init() {
switch {
case req.EntryId != 0 && mapHasEntry(res, req.EntryId):
resolvedEntry = req.EntryId
case sceneIdent != nil && res.MapDefaultEntranceMap[sceneIdent.FloorId] != 0:
resolvedEntry = res.MapDefaultEntranceMap[sceneIdent.FloorId]
case res.MapDefaultEntranceMap[req.EntryId] != 0:
resolvedEntry = res.MapDefaultEntranceMap[req.EntryId]
case sceneIdent != nil && sceneIdent.FloorId != 0:
resolvedEntry = findEntryForFloor(res, sceneIdent.FloorId)
case req.EntryId != 0 && findEntryForFloor(res, req.EntryId) != 0:
// req.EntryId doubles as a floor id in some map flows
resolvedEntry = findEntryForFloor(res, req.EntryId)
case req.TeleportId != 0:
resolvedEntry = findEntryByTeleport(res, req.TeleportId, currentEntry())
case sceneIdent != nil && sceneIdent.TeleportNigger != nil:
if t, okc := sceneIdent.TeleportNigger.(*goproto.SceneIdentifier_MDAIDPPKOPO); okc && t.MDAIDPPKOPO != nil && t.MDAIDPPKOPO.PLIDNBMCIJH != 0 {
// map teleport click: teleport id arrives via scene_identifier
resolvedEntry = findEntryByTeleport(res, t.MDAIDPPKOPO.PLIDNBMCIJH, currentEntry())
}
case interactID != 0:
resolvedEntry = findEntryByInteract(res, interactID, currentEntry())
default:
@@ -233,7 +239,10 @@ func init() {
&goproto.ChestInfo{ChestType: goproto.ChestType_MAP_INFO_CHEST_TYPE_PUZZLE},
)
if entryID := res.MapDefaultEntranceMap[floorID]; entryID != 0 {
// resolve the floor's entry directly (mapDefaultEntranceMap covers
// only 115/371 floors - new-region maps were left with no unlocked
// teleports, which locked the pillars)
if entryID := findEntryForFloor(res, floorID); entryID != 0 {
if _, cfg, ok := firstSceneOfEntry(res, entryID); ok {
groupIDs := sortedU32Keys2(cfg.Scenes)
for _, groupID := range groupIDs {
@@ -258,6 +267,20 @@ func init() {
}
}
// teleports.json covers every map (incl. floors whose res config
// has no inline teleports)
if m := common.Teleports()[floorID]; m != nil {
seen := map[uint32]bool{}
for _, t := range mapInfo.UnlockedTeleportList {
seen[t] = true
}
for id := range m {
if id != 0 && !seen[id] {
mapInfo.UnlockedTeleportList = append(mapInfo.UnlockedTeleportList, id)
}
}
}
rsp.SceneMapInfo = append(rsp.SceneMapInfo, mapInfo)
}
return nil
@@ -366,12 +389,40 @@ func init() {
})
}
// findEntryForFloor resolves an entry id for a floor WITHOUT relying on
// mapDefaultEntranceMap (which misses 287/371 floors): search the config
// names "P<plane>_F<floor>" directly.
func findEntryForFloor(res *common.JsonConfig, floorID uint32) uint32 {
if entryID := res.MapDefaultEntranceMap[floorID]; entryID != 0 {
return entryID
}
suffix := fmt.Sprintf("_F%d", floorID)
entryIDs := sortedU32Keys2(res.LevelOutputConfigs)
for _, eid := range entryIDs {
for name := range res.LevelOutputConfigs[eid] {
if len(name) > len(suffix) && name[len(name)-len(suffix):] == suffix {
return eid
}
}
}
return 0
}
func mapHasEntry(res *common.JsonConfig, entryID uint32) bool {
_, ok := res.LevelOutputConfigs[entryID]
return ok
}
func findEntryByTeleport(res *common.JsonConfig, teleportID uint32, fallback uint32) uint32 {
// teleports.json covers floors whose res config has no inline teleports:
// teleport id -> floor -> entry (via the floor name search)
for floorID, m := range common.Teleports() {
if _, ok := m[teleportID]; ok {
if entry := findEntryForFloor(res, floorID); entry != 0 {
return entry
}
}
}
entryIDs := sortedU32Keys2(res.LevelOutputConfigs)
for _, eid := range entryIDs {
names := make([]string, 0, len(res.LevelOutputConfigs[eid]))
@@ -459,6 +510,16 @@ func loadScene(s *Session, entryID uint32, isEnterScene bool, teleportID *uint32
break
}
}
if !found {
// exact teleport from teleports.json (covers floors whose res
// config has no inline teleports)
if m := common.Teleports()[floorID]; m != nil {
if tp, ok := m[*teleportID]; ok {
jsonPos.X, jsonPos.Y, jsonPos.Z, jsonPos.RotY = tp.Pos.X, tp.Pos.Y, tp.Pos.Z, tp.Rot.Y
found = true
}
}
}
if !found && len(groupIDs) > 0 {
// first teleport of the first group that has one
for _, gid := range groupIDs {
+7 -7
View File
@@ -6,15 +6,15 @@
"3": 1004
},
"position": {
"x": -92,
"y": 4278,
"z": 68083,
"rot_y": 155566
"x": 780,
"y": -153008,
"z": -621450,
"rot_y": 0
},
"scene": {
"plane_id": 10202,
"floor_id": 10202001,
"entry_id": 102020107
"plane_id": 30141,
"floor_id": 30141001,
"entry_id": 3014101
},
"main_character": "FemaleHarmony",
"march_type": "MarchHunt",
+16
View File
@@ -47,3 +47,19 @@
1. **ทดสอบกับ client จริง** — เปิด `run_go.bat` (GaC-hkrpg-go) แล้ว login ด้วย hosts/proxy เดิม
2. Gacha handlers ถูก skip (proto 4.6.51 เปลี่ยนชื่อ GetGachaInfoCsReq/DoGachaCsReq) — หาชื่อใหม่จาก dump
3. ถ้า client ฟ้อง cmd ไหน "Unknown" ให้เช็ค `gameserver.log` แล้วเติม handler ในตัว Go
## เพิ่มเติม (รอบแก้เสาวาป — 01:3x)
**อาการ:** เสาวาปในแมพใหม่ๆ มองเห็นในแมพแต่ไม่เปิด + กดวาปไม่ไป (client ไม่ส่ง EnterScene เลย)
**ต้นเหตุ:** `mapDefaultEntranceMap` ใน res.json ครอบคลุมแค่ 115/371 ฟลอร์ — โค้ด GetSceneMapInfo
และ EnterScene resolution พึ่งมันทั้งคู่ ฟลอร์ที่ไม่อยู่ในนี้ = ไม่มีรายชื่อเสาปลดล็อคส่งกลับ
→ client ล็อคเสา และไม่เริ่มวาป
**แก้ (commit 0fdadd0):**
- `findEntryForFloor` — หา entry จากชื่อ config `P*_F<floor>` โดยตรง (mapDefaultEntranceMap เป็น first chance)
- GetSceneMapInfo รวมรายชื่อเสาจาก teleports.json ทุกฟลอร์
- EnterScene: teleport id ผ่าน scene_identifier (MDAIDPPKOPO.PLIDNBMCIJH) resolve ปลายทางได้
- loadScene: ใช้ตำแหน่ง teleport จาก teleports.json ตรงๆ ถ้า res ไม่มี id นั้น
**บทเรียน:** data index บางตัวใน res.json ไม่ครอบคลุมทุกแมพ — ต้องมี fallback ค้นจากชื่อ config / teleports.json เสมอ