Save endgame progress, team presets, technique support and camera controls
This commit is contained in:
1 parent
a681affdb3
commit
639cef7d19
52 files changed
+11940
-766
No files matched your search
@@ -3,8 +3,6 @@ package gameserver
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"sync"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
@@ -16,11 +14,6 @@ import (
|
||||
// tierce lineup store + challenge scene loading
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
var (
|
||||
tierceLineups = map[uint32][][]uint32{}
|
||||
tierceLineupsMu sync.Mutex
|
||||
)
|
||||
|
||||
// loadChallengeScene is the Go port of scene.rs load_challenge_scene.
|
||||
func loadChallengeScene(s *Session, entryID, targetGroupID, monsterID, eventID uint32, avatarIDs []uint32) (*goproto.SceneInfo, *goproto.MotionInfo, error) {
|
||||
player := s.JSON()
|
||||
@@ -41,101 +34,38 @@ func loadChallengeScene(s *Session, entryID, targetGroupID, monsterID, eventID u
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// 1. locate the boss monster position from scene config
|
||||
var monsPos common.Position
|
||||
var instID uint32 = 1
|
||||
fallbackPos := common.Position{X: -61000, Y: -2141, Z: -170700, RotY: 90000}
|
||||
if grp, okg := scene.Scenes[targetGroupID]; okg && len(grp.Monsters) > 0 {
|
||||
m := grp.Monsters[0]
|
||||
monsPos = common.Position{X: m.Pos.X, Y: m.Pos.Y, Z: m.Pos.Z, RotY: m.Rot.Y}
|
||||
instID = m.InstID
|
||||
} else {
|
||||
found := false
|
||||
for _, gid := range sortedU32Keys2(scene.Scenes) {
|
||||
g := scene.Scenes[gid]
|
||||
if len(g.Monsters) > 0 {
|
||||
m := g.Monsters[0]
|
||||
monsPos = common.Position{X: m.Pos.X, Y: m.Pos.Y, Z: m.Pos.Z, RotY: m.Rot.Y}
|
||||
instID = m.InstID
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
monsPos = fallbackPos
|
||||
}
|
||||
// Use the selected group's resource placement, with no guessed arena
|
||||
// height or offset towards world origin (arena floors need not be there).
|
||||
group, ok := scene.Scenes[targetGroupID]
|
||||
if !ok || len(group.Monsters) == 0 {
|
||||
return nil, nil, fmt.Errorf("challenge entrance %d group %d has no monster placement", entryID, targetGroupID)
|
||||
}
|
||||
|
||||
// 2. position the player safely between boss and arena center
|
||||
// 2. detect arena floor platform height from props in scene
|
||||
// In some challenge arenas (e.g. entrance 3012602 / AS Starward 30225),
|
||||
// the boss monster pos in config is placed at Y = -193081 (22m below the floor),
|
||||
// while the arena stage prop (102259) is at Y = -170770.
|
||||
// Spawning at monsPos.Y puts the player under the map into the void.
|
||||
hasFloorProp := false
|
||||
var floorY int32 = -2147483648
|
||||
for _, g := range scene.Scenes {
|
||||
for _, p := range g.Props {
|
||||
dx := float64(p.Pos.X)
|
||||
dz := float64(p.Pos.Z)
|
||||
if math.Sqrt(dx*dx+dz*dz) < 150000.0 { // within 150 meters of center
|
||||
if p.Pos.Y > floorY {
|
||||
floorY = p.Pos.Y
|
||||
hasFloorProp = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if hasFloorProp && floorY > monsPos.Y {
|
||||
monsPos.Y = floorY
|
||||
placement := group.Monsters[0]
|
||||
monsPos := common.Position{X: placement.Pos.X, Y: placement.Pos.Y, Z: placement.Pos.Z, RotY: placement.Rot.Y}
|
||||
instID := placement.InstID
|
||||
playerMotion := monsPos.ToMotionInfo()
|
||||
spawnSource := "monster-placement"
|
||||
if anchors := res.SceneAnchors[entryID]; len(anchors) > 0 {
|
||||
anchor := anchors[0] // PearlSR scene_mgr.zig getAnchorMotion.
|
||||
playerMotion = (&common.Position{X: anchor.Pos.X, Y: anchor.Pos.Y, Z: anchor.Pos.Z, RotY: anchor.Rot.Y}).ToMotionInfo()
|
||||
spawnSource = "anchor"
|
||||
}
|
||||
SceneDebugLog("[CHALLENGE] spawn entry=%d floor=%d source=%s player=%v monster=%v", entryID, floorID, spawnSource, playerMotion, monsPos)
|
||||
|
||||
centerVX := float64(-monsPos.X)
|
||||
centerVZ := float64(-monsPos.Z)
|
||||
distToCenter := math.Sqrt(centerVX*centerVX + centerVZ*centerVZ)
|
||||
s.resetTechniqueRoom()
|
||||
|
||||
var spawnX, spawnY, spawnZ, spawnRotY, bossRotY int32
|
||||
if distToCenter > 1000.0 {
|
||||
nx := centerVX / distToCenter
|
||||
nz := centerVZ / distToCenter
|
||||
offset := math.Min(6000.0, distToCenter*0.6)
|
||||
spawnX = monsPos.X + int32(nx*offset)
|
||||
spawnZ = monsPos.Z + int32(nz*offset)
|
||||
|
||||
pDeg := int32(math.Round(math.Atan2(-nx, -nz) * 180.0 / math.Pi))
|
||||
if pDeg < 0 {
|
||||
pDeg += 360
|
||||
}
|
||||
bDeg := int32(math.Round(math.Atan2(nx, nz) * 180.0 / math.Pi))
|
||||
if bDeg < 0 {
|
||||
bDeg += 360
|
||||
}
|
||||
spawnY = monsPos.Y
|
||||
spawnRotY = pDeg * 1000
|
||||
bossRotY = bDeg * 1000
|
||||
} else {
|
||||
spawnX, spawnY, spawnZ, spawnRotY, bossRotY = 0, monsPos.Y, 6000, 180000, 0
|
||||
}
|
||||
monsPos.RotY = bossRotY
|
||||
|
||||
playerMotion := &goproto.MotionInfo{
|
||||
Pos: &goproto.Vector{X: spawnX, Y: spawnY, Z: spawnZ},
|
||||
Rot: &goproto.Vector{Y: spawnRotY},
|
||||
}
|
||||
// NOTE: keep player.Scene intact so returning to overworld or relogging spawns in overworld
|
||||
|
||||
sceneInfo := &goproto.SceneInfo{
|
||||
FloorId: floorID,
|
||||
PlaneId: planeID,
|
||||
EntryId: entryID,
|
||||
GameModeType: scene.PlaneType,
|
||||
GameModeType: sceneModeChallenge,
|
||||
LeaderEntityId: 1,
|
||||
WorldId: scene.WorldID,
|
||||
SceneIdentifier: &goproto.SceneIdentifier{FloorId: floorID},
|
||||
SceneMissionInfo: &goproto.MissionStatusBySceneInfo{},
|
||||
}
|
||||
if sceneInfo.WorldId == 100 {
|
||||
sceneInfo.WorldId = 501
|
||||
FloorSavedData: scene.SavedValues,
|
||||
}
|
||||
sceneInfo.LightenSectionList = scene.Sections
|
||||
|
||||
@@ -144,7 +74,7 @@ func loadChallengeScene(s *Session, entryID, targetGroupID, monsterID, eventID u
|
||||
s.PropEntities = map[uint32]PropEntry{}
|
||||
for _, gid := range sortedU32Keys2(scene.Scenes) {
|
||||
group := scene.Scenes[gid]
|
||||
groupInfo := &goproto.SceneEntityGroupInfo{GroupId: gid}
|
||||
groupInfo := &goproto.SceneEntityGroupInfo{State: 1, GroupId: gid}
|
||||
for i := range group.Props {
|
||||
prop := &group.Props[i]
|
||||
propEntityID++
|
||||
@@ -165,7 +95,7 @@ func loadChallengeScene(s *Session, entryID, targetGroupID, monsterID, eventID u
|
||||
}
|
||||
|
||||
// single boss monster (entity 30001, registered for SceneCastSkill battles)
|
||||
monsterGroup := &goproto.SceneEntityGroupInfo{GroupId: targetGroupID}
|
||||
monsterGroup := &goproto.SceneEntityGroupInfo{State: 1, GroupId: targetGroupID}
|
||||
s.MonsterEntities = map[uint32]uint32{30001: eventID}
|
||||
s.ChallengeStageID = eventID
|
||||
monsterGroup.EntityList = append(monsterGroup.EntityList, &goproto.SceneEntityInfo{
|
||||
@@ -203,7 +133,7 @@ func loadChallengeScene(s *Session, entryID, targetGroupID, monsterID, eventID u
|
||||
AvatarType: goproto.AvatarType_AVATAR_FORMAL_TYPE,
|
||||
BaseAvatarId: aid,
|
||||
MapLayer: 0,
|
||||
Uid: 1337,
|
||||
Uid: playerUID,
|
||||
},
|
||||
},
|
||||
})
|
||||
@@ -229,10 +159,6 @@ func handleStartChallengePeak(s *Session, req *goproto.StartChallengePeakCsReq,
|
||||
}
|
||||
eventID := stage.EventID
|
||||
monsterID := stage.MonsterID
|
||||
buff := stage.DefaultBuff
|
||||
if req.BossBuffId != 0 {
|
||||
buff = req.BossBuffId
|
||||
}
|
||||
Log("[PEAK] Start: peak_id=" + itoa(int(peakID)) + " event=" + itoa(int(eventID)) + " monster=" + itoa(int(monsterID)))
|
||||
|
||||
avatars := dedupeTruncate4(req.PeakAvatarIdList)
|
||||
@@ -240,34 +166,35 @@ func handleStartChallengePeak(s *Session, req *goproto.StartChallengePeakCsReq,
|
||||
avatars = challengeAvatarsFallback(s)
|
||||
}
|
||||
|
||||
if player := s.JSON(); player != nil {
|
||||
customLineup := map[uint32]uint32{}
|
||||
for i, aid := range avatars {
|
||||
customLineup[uint32(i)] = aid
|
||||
}
|
||||
player.BattleConfig.CustomBattleLineup = customLineup
|
||||
player.BattleConfig.StageID = eventID
|
||||
player.BattleConfig.CycleCount = 30
|
||||
player.BattleConfig.BattleType = common.BattleTypeDefault
|
||||
player.BattleConfig.Monsters = [][]common.Monster{{{Level: 68, MonsterID: monsterID}}}
|
||||
if buff != 0 {
|
||||
player.BattleConfig.Blessings = []common.BattleBuffJson{{ID: buff, Level: 1}}
|
||||
}
|
||||
player.SavePersistent()
|
||||
buffs := append([]uint32(nil), stage.Buffs...)
|
||||
if stage.IsBoss && s.PeakHardModes[stage.GroupID] {
|
||||
eventID = stage.HardEventID
|
||||
buffs = append([]uint32(nil), stage.HardBuffs...)
|
||||
}
|
||||
|
||||
// standard arena 3000101 (group 2 = boss position)
|
||||
sceneInfo, _, err := loadChallengeScene(s, 3000101, 2, monsterID, eventID, avatars)
|
||||
if err != nil {
|
||||
Log("[PEAK] Failed to load peak arena scene!")
|
||||
if req.BossBuffId != 0 {
|
||||
buffs = append(buffs, req.BossBuffId)
|
||||
}
|
||||
if stage.Entrance == 0 || stage.Group == 0 || eventID == 0 || len(avatars) == 0 {
|
||||
rsp.Retcode = uint32(goproto.Retcode_RET_CHALLENGE_NOT_EXIST)
|
||||
return nil
|
||||
}
|
||||
|
||||
custom := map[uint32]uint32{}
|
||||
for i, aid := range avatars {
|
||||
custom[uint32(i)] = aid
|
||||
previousConfig := s.ChallengeBattleConfig
|
||||
if err := setChallengeBattleConfig(s, avatars, peakID, eventID, buffs); err != nil {
|
||||
SceneDebugLog("[PEAK] stage rejected: %v", err)
|
||||
rsp.Retcode = uint32(goproto.Retcode_RET_CHALLENGE_NOT_EXIST)
|
||||
return nil
|
||||
}
|
||||
lineupInfo := common.ToLineupInfo(custom)
|
||||
s.ChallengeBattleConfig.BattleType = common.BattleTypeAA
|
||||
sceneInfo, _, err := loadChallengeScene(s, stage.Entrance, stage.Group, monsterID, eventID, avatars)
|
||||
if err != nil {
|
||||
s.ChallengeBattleConfig = previousConfig
|
||||
SceneDebugLog("[PEAK] scene rejected: %v", err)
|
||||
rsp.Retcode = uint32(goproto.Retcode_RET_CHALLENGE_NOT_EXIST)
|
||||
return nil
|
||||
}
|
||||
s.ChallengeRun = &challengeRun{ID: peakID, Peak: true, Single: true, Rooms: []challengeRoom{{Entrance: stage.Entrance, Group: stage.Group, Monster: monsterID, Event: eventID, Avatars: avatars, Buffs: buffs}}, Scores: make([]uint32, 1), PeakBuff: req.BossBuffId}
|
||||
|
||||
lineupInfo := lineupInfoFromAvatars(avatars, sceneInfo.PlaneId, goproto.ExtraLineupType_ExtraLineupType_LineupChallenge, 0)
|
||||
|
||||
return s.Send(&goproto.EnterSceneByServerScNotify{
|
||||
Scene: sceneInfo,
|
||||
|
||||
Reference in new issue
Block a user