mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-03-26 01:23:13 +01:00
fix(savedata): guard against sub-minimum backup data in recovery
nullcomp's passthrough path returns non-cmp-header data as-is without error, which is correct for old uncompressed saves. However, a corrupt backup slot containing garbage shorter than the minimum save layout (100 bytes) would pass Decompress() and then panic in updateStructWithSaveData() with a slice-bounds error at the name field read (offset 88–100). Add a minSaveSize check after each backup decompresses; skip the slot if the result is too small. Also document the campaign system and the fix in CHANGELOG under Unreleased.
This commit is contained in:
@@ -7,8 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fixed backup recovery panic: `recoverFromBackups` now rejects decompressed backup data smaller than the minimum save layout size, preventing a slice-bounds panic when nullcomp passes through garbage bytes as "already decompressed" data ([#182](https://github.com/Mezeporta/Erupe/pull/182)).
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
- Event Tent (campaign) system: code redemption, stamp tracking, reward claiming, and quest gating for special event quests, backed by 8 new database tables and seeded with community-researched live-game campaign data ([#182](https://github.com/Mezeporta/Erupe/pull/182), by stratick).
|
||||||
|
- Database migration `0010_campaign` (campaigns, campaign_categories, campaign_category_links, campaign_rewards, campaign_rewards_claimed, campaign_state, campaign_codes, campaign_quest).
|
||||||
- JSON Hunting Road config: `bin/rengoku_data.json` is now supported as a human-readable alternative to the opaque `rengoku_data.bin` — the server assembles and ECD-encrypts the binary at startup, with `.bin` used as a fallback ([#173](https://github.com/Mezeporta/Erupe/issues/173)).
|
- JSON Hunting Road config: `bin/rengoku_data.json` is now supported as a human-readable alternative to the opaque `rengoku_data.bin` — the server assembles and ECD-encrypts the binary at startup, with `.bin` used as a fallback ([#173](https://github.com/Mezeporta/Erupe/issues/173)).
|
||||||
- JSON quest files: `.json` files in `bin/quests/` are now supported alongside `.bin` — the server tries `.bin` first (full backward compatibility), then compiles `.json` on the fly to the MHF binary wire format ([#160](https://github.com/Mezeporta/Erupe/issues/160)). Covers all binary sections: quest text (UTF-8 → Shift-JIS), all 12 objective types, monster spawns (large + minion), reward tables, supply box, loaded stages, rank requirements, variant flags, forced equipment, map sections, area transitions, coordinate mappings, map info, gathering points, gathering tables, and area facilities. A `ParseQuestBinary` reverse function allows existing `.bin` files to be inspected and exported to JSON.
|
- JSON quest files: `.json` files in `bin/quests/` are now supported alongside `.bin` — the server tries `.bin` first (full backward compatibility), then compiles `.json` on the fly to the MHF binary wire format ([#160](https://github.com/Mezeporta/Erupe/issues/160)). Covers all binary sections: quest text (UTF-8 → Shift-JIS), all 12 objective types, monster spawns (large + minion), reward tables, supply box, loaded stages, rank requirements, variant flags, forced equipment, map sections, area transitions, coordinate mappings, map info, gathering points, gathering tables, and area facilities. A `ParseQuestBinary` reverse function allows existing `.bin` files to be inspected and exported to JSON.
|
||||||
|
|
||||||
|
|||||||
@@ -114,6 +114,19 @@ func recoverFromBackups(s *Session, base *CharacterSaveData, charID uint32) (*Ch
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nullcomp passes through data without a "cmp" header as-is (legitimate for
|
||||||
|
// old uncompressed saves). Guard against garbage data that is too small to
|
||||||
|
// contain the minimum save layout (name field at offset 88–100).
|
||||||
|
const minSaveSize = saveFieldNameOffset + saveFieldNameLen
|
||||||
|
if len(candidate.decompSave) < minSaveSize {
|
||||||
|
s.logger.Warn("Backup slot data too small after decompression, skipping",
|
||||||
|
zap.Uint32("charID", charID),
|
||||||
|
zap.Int("slot", backup.Slot),
|
||||||
|
zap.Int("size", len(candidate.decompSave)),
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
s.logger.Warn("Savedata recovered from backup — primary was corrupt",
|
s.logger.Warn("Savedata recovered from backup — primary was corrupt",
|
||||||
zap.Uint32("charID", charID),
|
zap.Uint32("charID", charID),
|
||||||
zap.Int("slot", backup.Slot),
|
zap.Int("slot", backup.Slot),
|
||||||
|
|||||||
Reference in New Issue
Block a user