pre cw with probe and a bunch script to read game behavior

This commit is contained in:
CAtlas0784 committed 2026-10-21 20:40:13 +07:00
1 parent 5120219ae2
commit da8a32f60d
310 files changed
+219693 -872

No files matched your search

+77 -6
View File
@@ -136,6 +136,16 @@ func parsePlaneFloor(name string) (uint32, uint32, error) {
}
func init() {
handle("SetTrainWorldId", func(s *Session, req *goproto.SetTrainWorldIdCsReq, rsp *goproto.SetTrainWorldIdScRsp) error {
// The default unknown-request path sends an empty response. The Client
// expects the selected train world ID in this response before it enters
// Train-plane scenes.
rsp.Retcode = 0
rsp.TrainWorldId = req.TrainWorldId
SceneDebugLog("SET_TRAIN_WORLD_ID interact_id=%d world_id=%d", req.InteractId, req.TrainWorldId)
return nil
})
handle("GetCurSceneInfo", func(s *Session, req *goproto.GetCurSceneInfoCsReq, rsp *goproto.GetCurSceneInfoScRsp) error {
player := s.JSON()
if player == nil {
@@ -280,6 +290,20 @@ func init() {
teleportID = &v
}
// Map checkpoints may name the Mission entrance even when a Town
// entrance exists on the same floor. Route only checkpoint teleports;
// direct story entries and scripted prop interactions keep their entry.
if teleportID != nil && *teleportID != 0 && interactID == 0 && !mapHasEntry(res, req.EntryId) {
floorID := res.MapEntrances[resolvedEntry].FloorID
if floorID == 0 && sceneIdent != nil {
floorID = sceneIdent.FloorId
}
if target := res.MapTeleportEntrances[floorID]; target != 0 {
SceneDebugLog("MAP_TELEPORT_ENTRY requested=%d resolved=%d floor=%d teleport=%d", resolvedEntry, target, floorID, *teleportID)
resolvedEntry = target
}
}
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)
@@ -377,12 +401,19 @@ func init() {
// 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 {
entryID := findEntryForFloor(res, floorID)
if player := s.JSON(); player != nil {
current := res.MapEntrances[player.Scene.EntryID]
if current.FloorID == floorID && mapHasEntry(res, player.Scene.EntryID) {
entryID = player.Scene.EntryID
}
}
if entryID != 0 {
if _, cfg, ok := firstSceneOfEntry(res, entryID); ok {
groupIDs := sortedU32Keys2(cfg.Scenes)
for _, groupID := range groupIDs {
group := cfg.Scenes[groupID]
mapInfo.GroupList = append(mapInfo.GroupList, &goproto.MapInfoGroup{GroupId: groupID})
mapInfo.GroupList = append(mapInfo.GroupList, &goproto.MapInfoGroup{GroupId: groupID, PropertyMap: s.sceneGroupProperties(floorID, groupID, cfg.GroupProperties[groupID])})
for tp := range group.Teleports {
mapInfo.UnlockedTeleportList = append(mapInfo.UnlockedTeleportList, tp)
@@ -396,6 +427,14 @@ func init() {
}
}
mapInfo.LightenSectionList = cfg.Sections
// Client-owned groups still have saved properties used by navmap
// conditions. Include data without spawning their entities.
for _, groupID := range sortedU32Keys2(cfg.GroupProperties) {
if _, exists := cfg.Scenes[groupID]; exists {
continue
}
mapInfo.GroupList = append(mapInfo.GroupList, &goproto.MapInfoGroup{GroupId: groupID, PropertyMap: s.sceneGroupProperties(floorID, groupID, cfg.GroupProperties[groupID])})
}
if cfg.SavedValues != nil {
mapInfo.FloorSavedData = cfg.SavedValues
}
@@ -794,6 +833,24 @@ func loadScene(s *Session, entryID uint32, isEnterScene, sendNotify bool, telepo
return nil, err
}
var cwEntrance *common.CurrencyWarsEntrance
cwCatalog, err := common.LoadCurrencyWarsCatalog()
if err != nil {
return nil, err
}
if cwCatalog.Entrance.EntryID == entryID {
catalog := cwCatalog
if catalog.Entrance.PlaneID != planeID || catalog.Entrance.FloorID != floorID {
return nil, fmt.Errorf("CW entrance scene differs from captured start anchor")
}
if isEnterScene && teleportID == nil {
cwEntrance = &catalog.Entrance
}
scene, err = currencyWarsEntranceScene(scene, catalog.Entrance)
if err != nil {
return nil, err
}
}
jsonPos := player.Position
if teleportID != nil {
found := false
@@ -827,6 +884,13 @@ func loadScene(s *Session, entryID uint32, isEnterScene, sendNotify bool, telepo
}
}
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 cwEntrance != nil {
anchor := cwEntrance.Anchor
jsonPos.X, jsonPos.Y, jsonPos.Z, jsonPos.RotY = anchor.Pos.X, anchor.Pos.Y, anchor.Pos.Z, anchor.Rot.Y
SceneDebugLog("CW_ENTRANCE_SPAWN entry=%d floor=%d group=%d anchor=%d pos=(%d,%d,%d)", entryID, floorID, cwEntrance.StartGroupID, anchor.ID, anchor.Pos.X, anchor.Pos.Y, anchor.Pos.Z)
} else if anchor, ok := sceneEntranceAnchor(res, entryID, floorID); isEnterScene && ok {
jsonPos.X, jsonPos.Y, jsonPos.Z, jsonPos.RotY = anchor.Pos.X, anchor.Pos.Y, anchor.Pos.Z, anchor.Rot.Y
SceneDebugLog("ENTRANCE_ANCHOR_SPAWN entry=%d floor=%d group=%d anchor=%d pos=(%d,%d,%d)", entryID, floorID, res.MapEntrances[entryID].StartGroupID, anchor.ID, anchor.Pos.X, anchor.Pos.Y, anchor.Pos.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
@@ -893,6 +957,7 @@ func loadScene(s *Session, entryID uint32, isEnterScene, sendNotify bool, telepo
}
sceneInfo := &goproto.SceneInfo{
DimensionId: scene.DimensionID,
FloorId: floorID,
PlaneId: planeID,
EntryId: entryID,
@@ -931,20 +996,22 @@ func loadScene(s *Session, entryID uint32, isEnterScene, sendNotify bool, telepo
monsterEntityID := uint32(30000)
s.PropEntities = map[uint32]PropEntry{}
s.CurrentSceneFloor = floorID
s.MonsterEntities = map[uint32]uint32{}
s.SceneMonsterIdentities = map[uint32]sceneMonsterIdentity{}
s.ChallengeStageID = 0
s.ChallengeBattleConfig = nil
s.ChallengeRun = nil
for _, groupID := range sortedU32Keys2(scene.Scenes) {
group := scene.Scenes[groupID]
groupInfo := &goproto.SceneEntityGroupInfo{State: 1, GroupId: groupID}
groupInfo := &goproto.SceneEntityGroupInfo{State: 1, GroupId: groupID, PropertyMap: s.sceneGroupProperties(floorID, groupID, scene.GroupProperties[groupID])}
// props
for i := range group.Props {
prop := &group.Props[i]
propEntityID++
s.PropEntities[propEntityID] = PropEntry{PropID: prop.PropID, InstID: prop.InstID, State: prop.PropState}
s.PropEntities[propEntityID] = PropEntry{GroupID: prop.GroupID, PropID: prop.PropID, InstID: prop.InstID, State: prop.PropState}
groupInfo.EntityList = append(groupInfo.EntityList, &goproto.SceneEntityInfo{
InstId: prop.InstID,
@@ -985,6 +1052,7 @@ func loadScene(s *Session, entryID uint32, isEnterScene, sendNotify bool, telepo
monster := &group.Monsters[i]
monsterEntityID++
s.MonsterEntities[monsterEntityID] = monster.EventID
s.SceneMonsterIdentities[monsterEntityID] = sceneMonsterIdentity{MonsterID: monster.MonsterID, GroupID: monster.GroupID}
groupInfo.EntityList = append(groupInfo.EntityList, &goproto.SceneEntityInfo{
InstId: monster.InstID,
@@ -995,7 +1063,7 @@ func loadScene(s *Session, entryID uint32, isEnterScene, sendNotify bool, telepo
NpcMonster: &goproto.SceneNpcMonsterInfo{
MonsterId: monster.MonsterID,
EventId: monster.EventID,
WorldLevel: 6,
WorldLevel: playerWorldLevel,
},
},
})
@@ -1026,7 +1094,7 @@ func loadScene(s *Session, entryID uint32, isEnterScene, sendNotify bool, telepo
AvatarType: goproto.AvatarType_AVATAR_FORMAL_TYPE,
BaseAvatarId: avatarID,
MapLayer: 0,
Uid: 25,
Uid: playerUID,
},
},
})
@@ -1042,6 +1110,9 @@ func loadScene(s *Session, entryID uint32, isEnterScene, sendNotify bool, telepo
sceneInfo.LeaderEntityId = s.leaderSlot + 1
sceneInfo.EntityGroupList = append(sceneInfo.EntityGroupList, playerGroup)
SceneDebugLog("[SCENE] entry=%d floor=%d plane=%d world=%d mode=%d savedValues=%d groups=%v", entryID, floorID, planeID, sceneInfo.WorldId, sceneInfo.GameModeType, len(sceneInfo.FloorSavedData), sortedU32Keys2(scene.Scenes))
if res.MapTeleportEntrances[floorID] != 0 {
SceneDebugLog("SCENE_SAVED_VALUES entry=%d floor=%d values=%v", entryID, floorID, sceneInfo.FloorSavedData)
}
if isEnterScene {
// in-memory only: the scene is persisted by SceneEntityMove once the