fix: sync current handlers, repair relic data and restore visible launcher consoles
This commit is contained in:
1 parent
163d4433e6
commit
74f3c4411b
46 files changed
+4599
-1402
No files matched your search
@@ -52,6 +52,57 @@ func firstSceneOfEntry(res *common.JsonConfig, entryID uint32) (string, *common.
|
||||
return "", nil, false
|
||||
}
|
||||
|
||||
// sceneOfEntryForTeleport selects the floor config that actually owns the
|
||||
// requested teleport. Some resource sets put several floors under one entry;
|
||||
// choosing the lexicographically first config can then send a valid scene
|
||||
// transition with the wrong floor and spawn position.
|
||||
func sceneOfEntryForTeleport(res *common.JsonConfig, entryID, floorID, teleportID uint32) (string, *common.LevelOutputConfig, bool) {
|
||||
configs := res.LevelOutputConfigs[entryID]
|
||||
names := make([]string, 0, len(configs))
|
||||
for name := range configs {
|
||||
names = append(names, name)
|
||||
}
|
||||
sort.Strings(names)
|
||||
if floorID != 0 {
|
||||
want := fmt.Sprintf("_F%d", floorID)
|
||||
for _, name := range names {
|
||||
cfg := configs[name]
|
||||
if len(name) > len(want) && name[len(name)-len(want):] == want && sceneHasTeleport(cfg, teleportID) {
|
||||
return name, cfg, true
|
||||
}
|
||||
}
|
||||
}
|
||||
if teleportID != 0 {
|
||||
for _, name := range names {
|
||||
cfg := configs[name]
|
||||
if sceneHasTeleport(cfg, teleportID) {
|
||||
return name, cfg, true
|
||||
}
|
||||
}
|
||||
}
|
||||
if floorID != 0 {
|
||||
want := fmt.Sprintf("_F%d", floorID)
|
||||
for _, name := range names {
|
||||
if len(name) > len(want) && name[len(name)-len(want):] == want {
|
||||
return name, configs[name], true
|
||||
}
|
||||
}
|
||||
}
|
||||
return firstSceneOfEntry(res, entryID)
|
||||
}
|
||||
|
||||
func sceneHasTeleport(cfg *common.LevelOutputConfig, teleportID uint32) bool {
|
||||
if cfg == nil || teleportID == 0 {
|
||||
return false
|
||||
}
|
||||
for _, group := range cfg.Scenes {
|
||||
if _, ok := group.Teleports[teleportID]; ok {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// parsePlaneFloor splits "P<plane>_F<floor>".
|
||||
func parsePlaneFloor(name string) (uint32, uint32, error) {
|
||||
if len(name) < 2 || name[0] != 'P' {
|
||||
@@ -108,7 +159,7 @@ func init() {
|
||||
defaultScene.FloorId = player.Scene.FloorID
|
||||
}
|
||||
|
||||
scene, err := loadScene(s, entryID, false, nil, nil)
|
||||
scene, err := loadScene(s, entryID, false, false, nil, nil)
|
||||
rsp.Retcode = 0
|
||||
if err == nil {
|
||||
rsp.Scene = scene
|
||||
@@ -120,7 +171,7 @@ func init() {
|
||||
|
||||
handle("EnterScene", func(s *Session, req *goproto.EnterSceneCsReq, rsp *goproto.EnterSceneScRsp) error {
|
||||
Log(fmt.Sprintf("on_enter_scene_cs_req: entry_id=%d, teleport_id=%d, interact_id=%d", req.EntryId, req.TeleportId, req.InteractId))
|
||||
SceneDebugLog("ENTER_SCENE entry_id=%d teleport_id=%d interact_id=%d", req.EntryId, req.TeleportId, req.InteractId)
|
||||
SceneDebugLog("ENTER_SCENE entry_id=%d teleport_id=%d interact_id=%d scene_identifier=%v", req.EntryId, req.TeleportId, req.InteractId, req.SceneIdentifier)
|
||||
|
||||
res, err := common.GameRes()
|
||||
if err != nil {
|
||||
@@ -222,7 +273,7 @@ func init() {
|
||||
teleportID = &v
|
||||
}
|
||||
|
||||
sceneInfo, err := loadScene(s, resolvedEntry, true, teleportID, sceneIdent)
|
||||
sceneInfo, err := loadScene(s, resolvedEntry, true, false, teleportID, sceneIdent)
|
||||
if err != nil {
|
||||
SceneDebugLog("ENTER_SCENE_FAILED requested_entry=%d resolved_entry=%d err=%v", req.EntryId, resolvedEntry, err)
|
||||
Log(fmt.Sprintf("Failed to enter scene %d: %v", resolvedEntry, err))
|
||||
@@ -230,11 +281,21 @@ func init() {
|
||||
return nil
|
||||
}
|
||||
|
||||
SceneDebugLog("ENTER_SCENE_RESOLVED requested_entry=%d resolved_entry=%d", req.EntryId, resolvedEntry)
|
||||
SceneDebugLog("ENTER_SCENE_RESOLVED requested_entry=%d resolved_entry=%d floor_id=%d plane_id=%d teleport_id=%d", req.EntryId, resolvedEntry, sceneInfo.FloorId, sceneInfo.PlaneId, teleportIDValue(teleportID))
|
||||
rsp.Retcode = 0
|
||||
rsp.SceneIdentifier = sceneInfo.SceneIdentifier
|
||||
rsp.IsOverMap = true
|
||||
rsp.IsCloseMap = req.IsCloseMap
|
||||
return nil
|
||||
if err := s.Send(rsp); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Send(&goproto.EnterSceneByServerScNotify{
|
||||
Scene: sceneInfo,
|
||||
Lineup: common.ToLineupInfo(player.Lineups),
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
return errResponseAlreadySent
|
||||
})
|
||||
|
||||
handle("InteractProp", func(s *Session, req *goproto.InteractPropCsReq, rsp *goproto.InteractPropScRsp) error {
|
||||
@@ -268,14 +329,14 @@ func init() {
|
||||
return nil
|
||||
})
|
||||
|
||||
// decodeSceneIdentifiersLenient: the 4.6.51 client's cmd-1461 payload can
|
||||
// decodeSceneIdentifiersLenient: some Client scene-map payloads can
|
||||
// fail strict proto parsing (field layout drift between builds) — walk the
|
||||
// wire format manually and pull floor_id/content_id out of field 2.
|
||||
// GetSceneMapInfo as a raw handler: the 4.6.51 client's cmd-1461 payload
|
||||
// GetSceneMapInfo as a raw handler: some Client scene-map payloads
|
||||
// can fail strict proto parsing (layout drift), so fall back to a manual
|
||||
// wire walk instead of dropping the request (the map UI stalls without
|
||||
// this reply - no pillars, "navigation loading").
|
||||
rawHandlers[1461] = func(s *Session, payload []byte) error {
|
||||
rawNamed("GetSceneMapInfoCsReq", func(s *Session, payload []byte) error {
|
||||
res, err := common.GameRes()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -352,7 +413,7 @@ func init() {
|
||||
}
|
||||
|
||||
return s.Send(rsp)
|
||||
}
|
||||
})
|
||||
|
||||
handle("SceneEntityMove", func(s *Session, req *goproto.SceneEntityMoveCsReq, rsp *goproto.SceneEntityMoveScRsp) error {
|
||||
player := s.JSON()
|
||||
@@ -696,9 +757,9 @@ func sortedU32Keys2[V any](m map[uint32]V) []uint32 {
|
||||
|
||||
func sortedU32Keys[V any](m map[uint32]V) []uint32 { return sortedU32Keys2(m) }
|
||||
|
||||
// loadScene is the Go port of load_scene. When isEnterScene is true it also
|
||||
// sends EnterSceneByServerScNotify and persists the new position.
|
||||
func loadScene(s *Session, entryID uint32, isEnterScene bool, teleportID *uint32, reqSceneIdent *goproto.SceneIdentifier) (*goproto.SceneInfo, error) {
|
||||
// loadScene is the Go port of load_scene. When isEnterScene is true it updates
|
||||
// the player's scene; sendNotify controls whether it also emits the notify.
|
||||
func loadScene(s *Session, entryID uint32, isEnterScene, sendNotify bool, teleportID *uint32, reqSceneIdent *goproto.SceneIdentifier) (*goproto.SceneInfo, error) {
|
||||
player := s.JSON()
|
||||
if player == nil {
|
||||
return nil, fmt.Errorf("data is not set!")
|
||||
@@ -708,7 +769,15 @@ func loadScene(s *Session, entryID uint32, isEnterScene bool, teleportID *uint32
|
||||
return nil, err
|
||||
}
|
||||
|
||||
name, scene, ok := firstSceneOfEntry(res, entryID)
|
||||
floorHint := uint32(0)
|
||||
if reqSceneIdent != nil {
|
||||
floorHint = reqSceneIdent.FloorId
|
||||
}
|
||||
requestedTeleport := uint32(0)
|
||||
if teleportID != nil {
|
||||
requestedTeleport = *teleportID
|
||||
}
|
||||
name, scene, ok := sceneOfEntryForTeleport(res, entryID, floorHint, requestedTeleport)
|
||||
if !ok {
|
||||
Log(fmt.Sprintf("Map Entrance Not Found %d", entryID))
|
||||
return nil, fmt.Errorf("Map Entrance Not Found %d", entryID)
|
||||
@@ -750,6 +819,7 @@ func loadScene(s *Session, entryID uint32, isEnterScene bool, teleportID *uint32
|
||||
}
|
||||
}
|
||||
}
|
||||
SceneDebugLog("LOAD_SCENE_TELEPORT entry_id=%d config=%s floor_id=%d teleport_id=%d matched=%t pos=(%d,%d,%d)", entryID, name, floorID, *teleportID, found, jsonPos.X, jsonPos.Y, jsonPos.Z)
|
||||
} else if isEnterScene || jsonPos.Y < -5000 {
|
||||
// first teleport in the scene, else the teleport DB, else spawn near the first prop
|
||||
var firstTP *common.TeleportInfo
|
||||
@@ -861,7 +931,7 @@ func loadScene(s *Session, entryID uint32, isEnterScene bool, teleportID *uint32
|
||||
|
||||
for _, groupID := range sortedU32Keys2(scene.Scenes) {
|
||||
group := scene.Scenes[groupID]
|
||||
groupInfo := &goproto.SceneEntityGroupInfo{GroupId: groupID}
|
||||
groupInfo := &goproto.SceneEntityGroupInfo{State: 1, GroupId: groupID}
|
||||
|
||||
// props
|
||||
for i := range group.Props {
|
||||
@@ -924,6 +994,7 @@ func loadScene(s *Session, entryID uint32, isEnterScene bool, teleportID *uint32
|
||||
})
|
||||
}
|
||||
|
||||
sceneInfo.EntityList = append(sceneInfo.EntityList, groupInfo.EntityList...)
|
||||
if len(group.Props) == 0 && len(group.Npcs) == 0 && len(group.Monsters) == 0 {
|
||||
continue
|
||||
}
|
||||
@@ -959,17 +1030,26 @@ func loadScene(s *Session, entryID uint32, isEnterScene bool, teleportID *uint32
|
||||
player.Scene.PlaneID = planeID
|
||||
player.Position = jsonPos
|
||||
|
||||
if err := s.Send(&goproto.EnterSceneByServerScNotify{
|
||||
Scene: sceneInfo,
|
||||
Lineup: common.ToLineupInfo(player.Lineups),
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
if sendNotify {
|
||||
if err := s.Send(&goproto.EnterSceneByServerScNotify{
|
||||
Scene: sceneInfo,
|
||||
Lineup: common.ToLineupInfo(player.Lineups),
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sceneInfo, nil
|
||||
}
|
||||
|
||||
func teleportIDValue(id *uint32) uint32 {
|
||||
if id == nil {
|
||||
return 0
|
||||
}
|
||||
return *id
|
||||
}
|
||||
|
||||
func hasAvatar(player *common.FreesrData, id uint32) bool {
|
||||
_, ok := player.Avatars[id]
|
||||
return ok
|
||||
|
||||
Reference in new issue
Block a user