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

+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 {