Save endgame progress, team presets, technique support and camera controls

This commit is contained in:
CAtlas0784 committed 2026-10-17 23:44:36 +07:00
1 parent a681affdb3
commit 639cef7d19
52 files changed
+11940 -766

No files matched your search

+73
View File
@@ -81,6 +81,8 @@ type AvatarConfig struct {
}
type JsonConfig struct {
MapEntrances map[uint32]MapEntranceEntry `json:"-"`
SceneAnchors map[uint32][]AnchorItem `json:"-"`
// entryId -> "P<plane>_F<floor>" -> config
LevelOutputConfigs map[uint32]map[string]*LevelOutputConfig `json:"levelOutputConfigs"`
AvatarConfigs map[uint32]AvatarConfig `json:"avatarConfigs"`
@@ -192,6 +194,7 @@ func GameRes() (*JsonConfig, error) {
_ = Teleports() // ensure teleportDB is initialized
loadSupplementaryResources(gameRes)
applySceneMetadata(gameRes)
})
return gameRes, gameResErr
}
@@ -266,6 +269,8 @@ func loadSupplementaryResources(res *JsonConfig) {
}
planesByID := map[uint32]MazePlaneEntry{}
res.MapEntrances = entrancesByEntry
res.SceneAnchors = map[uint32][]AnchorItem{}
if raw, err := readResourceFile("resources/MazePlane.json", "MazePlane.json"); err == nil {
var list []MazePlaneEntry
if json.Unmarshal(raw, &list) != nil {
@@ -366,6 +371,7 @@ func loadSupplementaryResources(res *JsonConfig) {
name: {
IsEnteredSceneInfo: true,
Scenes: groups,
WorldID: planesByID[sc.PlaneID].WorldID,
},
}
}
@@ -377,6 +383,7 @@ func loadSupplementaryResources(res *JsonConfig) {
var aFile AnchorConfigFile
if json.Unmarshal(raw, &aFile) == nil && len(aFile.AnchorConfig) > 0 {
for _, item := range aFile.AnchorConfig {
res.SceneAnchors[item.EntryID] = item.Anchor
floorID := uint32(0)
if ent, ok := entrancesByEntry[item.EntryID]; ok && ent.FloorID != 0 {
floorID = ent.FloorID
@@ -415,6 +422,72 @@ func loadSupplementaryResources(res *JsonConfig) {
}
}
}
// Supplementary scenes do not carry world metadata. Resolve it from the
// installed entrance/plane tables, including entries supplied by Anchor.json.
floorSavedValues := map[uint32]map[string]int32{}
if raw, err := readResourceFile("resources/FloorSavedValuesConfig.json"); err == nil {
var table struct {
Floors []struct {
FloorID uint32 `json:"FloorID"`
Values []struct {
Name string `json:"Name"`
MaxValue int32 `json:"MaxValue"`
} `json:"SavedValues"`
} `json:"saved_values"`
}
if err := json.Unmarshal(raw, &table); err == nil {
// Same unlocked scene defaults as PearlSR 005d2c12 scene_mgr.zig.
for _, floor := range table.Floors {
values := map[string]int32{}
for _, value := range floor.Values {
if value.Name != "" {
values[value.Name] = value.MaxValue
}
}
floorSavedValues[floor.FloorID] = values
}
} else {
LogInfo("[SCENE] Invalid FloorSavedValuesConfig: %v", err)
}
}
for entryID, configs := range res.LevelOutputConfigs {
entrance, ok := entrancesByEntry[entryID]
if !ok {
continue
}
// Legacy dumps label every entrance in a plane with its first floor.
// An entrance has an explicit floor in MapEntrance; do not derive it.
if len(configs) == 1 {
canonical := fmt.Sprintf("P%d_F%d", entrance.PlaneID, entrance.FloorID)
for name, config := range configs {
if name != canonical {
delete(configs, name)
configs[canonical] = config
}
break
}
}
plane, ok := planesByID[entrance.PlaneID]
if !ok {
continue
}
for name, config := range configs {
config.WorldID = plane.WorldID
var configPlane, configFloor uint32
if n, _ := fmt.Sscanf(name, "P%d_F%d", &configPlane, &configFloor); n != 2 {
continue
}
if config.SavedValues == nil {
config.SavedValues = map[string]int32{}
}
for name, value := range floorSavedValues[configFloor] {
if _, exists := config.SavedValues[name]; !exists {
config.SavedValues[name] = value
}
}
}
}
}
// Teleports lazily parses teleports.json ({floor_id: {teleport_id: info}}).