yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
hack_manifest.h
Go to the documentation of this file.
1#ifndef YAZE_CORE_HACK_MANIFEST_H
2#define YAZE_CORE_HACK_MANIFEST_H
3
4#include <array>
5#include <cstdint>
6#include <optional>
7#include <string>
8#include <unordered_map>
9#include <utility>
10#include <vector>
11
12#include "absl/status/status.h"
15
16namespace yaze::core {
17
18// Private, exact-save producer transfer. Every PC range is half-open.
19// This is deliberately one fixed source contract, not an allocator capability.
21 struct Preimage {
22 std::array<uint32_t, 2> pc{};
23 std::string sha256;
24 bool operator==(const Preimage&) const = default;
25 };
26 std::string source_rom_sha256;
27 std::array<uint32_t, 2> tile32_id_range{};
28 std::array<uint32_t, 2> stream_pc_range{};
29 std::array<uint32_t, 4> dictionary_bases_pc{};
30 std::array<Preimage, 4> packed_preimages{};
32 bool operator==(const LyraPrivateReservation&) const = default;
33};
34
36
46enum class AddressOwnership : uint8_t {
47 kVanillaSafe, // Yaze can edit; asar doesn't touch
48 kHookPatched, // Asar patches this; yaze edits are overwritten on build
49 kAsmOwned, // Entire bank owned by ASM hack
50 kShared, // Both yaze and ASM write (e.g., ZSCustomOverworld)
51 kAsmExpansion, // ROM expansion bank — only exists in patched ROM
52 kRam, // WRAM definition (not ROM data)
53 kMirror, // HiROM mirror of vanilla bank
54};
55
56std::string AddressOwnershipToString(AddressOwnership ownership);
57
62 uint32_t start;
63 uint32_t end;
65 std::string module;
66};
67
71struct OwnedBank {
72 uint8_t bank;
73 uint32_t bank_start;
74 uint32_t bank_end;
76 std::string ownership_note;
77};
78
83 uint8_t tag_id;
84 uint32_t address;
85 std::string name;
86 std::string purpose;
87 std::string source;
88 std::string feature_flag; // Empty if always enabled
89 bool enabled = true;
90};
91
96 std::string name;
97 int value;
98 bool enabled;
99 std::string source;
100};
101
106 std::string name;
107 uint32_t address;
108 std::string purpose;
109};
110
115 struct Source {
116 std::string format;
117 int version = 0;
120 };
121
122 uint32_t hook_address; // $0ED436
123 uint32_t data_start; // $2F8000
124 uint32_t data_end; // $2FFFFF
125 uint16_t first_expanded_id; // $18D
126 uint16_t last_expanded_id; // $1D1
128 int vanilla_count; // 397
129 std::optional<Source> source;
130};
131
136 struct Source {
137 std::string format;
138 int version = 0;
139 std::string path;
140
141 bool operator==(const Source&) const = default;
142 };
143
144 std::optional<Source> source;
145};
146
151 std::string dev_rom;
152 std::string patched_rom;
153 std::string assembler;
154 std::string entry_point;
155 std::string build_script;
156};
157
161enum class DungeonStreamType : uint8_t {
162 kObjects,
163 kSprites,
164 kPotItems,
165};
166
170enum class DungeonPointerEncoding : uint8_t {
171 kLong24,
172 kBank16,
173};
174
178enum class DungeonWriteStrategy : uint8_t {
181};
182
187 uint32_t start = 0;
188 uint32_t end = 0;
189};
190
208
219 std::vector<SnesAddressRange> allocation_regions;
220 std::vector<uint16_t> reserved_sheets;
221};
222
227 uint32_t address;
229 std::string module; // From protected region, if applicable
230};
231
232// ─── Project Registry (Dungeon + Overworld data) ─────────────────────────
233
238 int id;
239 std::string name;
240 std::string floor; // "F1", "B1", etc. Optional project-map label.
242 bool has_grid_position = false;
243 std::string type; // "entrance", "boss", "mini_boss", "connector", "normal"
245 uint8_t tag1, tag2;
246};
247
253 std::string label;
254 std::string direction; // For doors: "north"/"south"/"east"/"west"
255};
256
261 std::string id; // "D4"
262 std::string name; // "Zora Temple"
263 std::string vanilla_name; // "Thieves' Town"
264 std::vector<DungeonRoom> rooms;
265 std::vector<DungeonConnection> stairs;
266 std::vector<DungeonConnection> holewarps;
267 std::vector<DungeonConnection> doors;
268};
269
275 std::string name;
276 std::string world; // "LW", "DW", "SW"
278};
279
287 std::vector<DungeonEntry> dungeons;
288 std::vector<OverworldArea> overworld_areas;
290
291 // Universal resource labels: type -> {id_str -> label}
292 //
293 // Notes:
294 // - Keys are normalized to decimal strings for project::YazeProject::resource_labels.
295 // - Input JSON may use either decimal ("57") or hex ("0x39") IDs.
296 //
297 // Types: "room", "sprite", "item", "entrance", "overworld_map", "music".
298 // Oracle `dungeons.json` room names are mirrored into "room" labels so the
299 // opened project file can serialize the current registry names.
300 std::unordered_map<std::string, std::unordered_map<std::string, std::string>>
302
303 // Backward-compat accessor for room labels only
304 const std::unordered_map<std::string, std::string>& room_labels() const {
305 static const std::unordered_map<std::string, std::string> empty;
306 auto it = all_resource_labels.find("room");
307 return it != all_resource_labels.end() ? it->second : empty;
308 }
309};
310
335 public:
336 HackManifest() = default;
337
341 absl::Status LoadFromFile(const std::string& filepath);
342
346 absl::Status LoadFromString(const std::string& json_content);
347
351 [[nodiscard]] bool loaded() const { return loaded_; }
352
359 void Clear() { Reset(); }
360
361 // ─── Address Classification ───────────────────────────────
362
372 [[nodiscard]] AddressOwnership ClassifyAddress(uint32_t address) const;
373
380 [[nodiscard]] bool IsWriteOverwritten(uint32_t address) const;
381
385 [[nodiscard]] bool IsProtected(uint32_t address) const;
386
394 [[nodiscard]] bool IsEditorManaged(uint32_t address) const;
395
399 [[nodiscard]] std::optional<AddressOwnership> GetBankOwnership(
400 uint8_t bank) const;
401
402 // ─── Room Tags ────────────────────────────────────────────
403
407 [[nodiscard]] std::string GetRoomTagLabel(uint8_t tag_id) const;
408
412 [[nodiscard]] std::optional<RoomTagEntry> GetRoomTag(uint8_t tag_id) const;
413
417 [[nodiscard]] const std::vector<RoomTagEntry>& room_tags() const {
418 return room_tags_;
419 }
420
421 // ─── Feature Flags ────────────────────────────────────────
422
423 [[nodiscard]] bool IsFeatureEnabled(const std::string& flag_name) const;
424
425 [[nodiscard]] const std::vector<FeatureFlag>& feature_flags() const {
426 return feature_flags_;
427 }
428
429 // ─── SRAM ─────────────────────────────────────────────────
430
431 [[nodiscard]] std::string GetSramVariableName(uint32_t address) const;
432
433 [[nodiscard]] const std::vector<SramVariable>& sram_variables() const {
434 return sram_variables_;
435 }
436
437 // ─── Messages ─────────────────────────────────────────────
438
439 [[nodiscard]] const MessageLayout& message_layout() const {
440 return message_layout_;
441 }
442
443 [[nodiscard]] bool IsExpandedMessage(uint16_t message_id) const;
444
445 // ─── Minecart Tracks ──────────────────────────────────────
446
447 [[nodiscard]] const MinecartTrackLayout& minecart_track_layout() const {
449 }
450
451 // ─── Dungeon Stream Allocation Layouts ────────────────────────────
452
459 [[nodiscard]] const DungeonStreamLayout* GetDungeonStreamLayout(
460 DungeonStreamType stream) const;
461
462 [[nodiscard]] bool HasDungeonStreamLayouts() const {
463 return !dungeon_stream_layouts_.empty();
464 }
465
466 // ─── Graphics Sheet Layout ────────────────────────────────
467
472 [[nodiscard]] const GraphicsSheetLayout& graphics_sheet_layout() const {
474 }
475
476 // ─── Protected Regions ──────────────────────────────────
477
478 [[nodiscard]] const std::vector<ProtectedRegion>& protected_regions() const {
479 return protected_regions_;
480 }
481
482 [[nodiscard]] const std::vector<SnesAddressRange>& editor_managed_regions()
483 const {
485 }
486
487 [[nodiscard]] const std::unordered_map<uint8_t, OwnedBank>& owned_banks()
488 const {
489 return owned_banks_;
490 }
491
492 // ─── Write Conflict Analysis ─────────────────────────────
493
501 [[nodiscard]] std::vector<WriteConflict> AnalyzeWriteRanges(
502 const std::vector<std::pair<uint32_t, uint32_t>>& ranges) const;
503
513 [[nodiscard]] std::vector<WriteConflict> AnalyzePcWriteRanges(
514 const std::vector<std::pair<uint32_t, uint32_t>>& pc_ranges) const;
515
516 // ─── Project Registry ────────────────────────────────────
517
524 absl::Status LoadProjectRegistry(const std::string& code_folder);
525
526 [[nodiscard]] const ProjectRegistry& project_registry() const {
527 return project_registry_;
528 }
529
530 [[nodiscard]] bool HasProjectRegistry() const {
531 return !project_registry_.dungeons.empty() ||
534 }
535
536 // ─── Oracle Progression (SRAM) ─────────────────────────────
537
538 // Updates story event completion coloring based on progression state parsed
539 // from an emulator SRAM file (.srm).
541
542 // Clears any loaded progression state and resets story graph status to
543 // default (no progress).
545
546 [[nodiscard]] std::optional<OracleProgressionState> oracle_progression_state()
547 const {
549 }
550
551 // ─── Build Pipeline ───────────────────────────────────────
552
553 [[nodiscard]] const BuildPipeline& build_pipeline() const {
554 return build_pipeline_;
555 }
556
557 // ─── Metadata ─────────────────────────────────────────────
558
559 [[nodiscard]] const std::string& hack_name() const { return hack_name_; }
560 [[nodiscard]] int manifest_version() const { return manifest_version_; }
561 [[nodiscard]] int total_hooks() const { return total_hooks_; }
562
563 const std::optional<LyraPrivateReservation>& lyra_private_reservation()
564 const {
566 }
567
568 private:
569 void Reset();
570 [[nodiscard]] const ProtectedRegion* FindProtectedRegion(
571 uint32_t address) const;
572
573 std::optional<LyraPrivateReservation> lyra_private_reservation_;
574 bool loaded_ = false;
576 std::string hack_name_;
578
579 // Protected regions (vanilla bank hooks) — sorted by start address
580 std::vector<ProtectedRegion> protected_regions_;
581
582 // Exact manifest-v3 regions that remain yaze-owned inside otherwise owned
583 // banks. Sorted, disjoint, and stored as canonical LoROM addresses.
584 std::vector<SnesAddressRange> editor_managed_regions_;
585
586 // Bank ownership lookup
587 std::unordered_map<uint8_t, OwnedBank> owned_banks_;
588
589 // Room tag lookup by tag ID
590 std::unordered_map<uint8_t, RoomTagEntry> room_tag_map_;
591 std::vector<RoomTagEntry> room_tags_;
592
593 // Feature flags by name
594 std::unordered_map<std::string, FeatureFlag> feature_flag_map_;
595 std::vector<FeatureFlag> feature_flags_;
596
597 // SRAM variable lookup by address
598 std::unordered_map<uint32_t, SramVariable> sram_map_;
599 std::vector<SramVariable> sram_variables_;
600
601 // Message layout
603
604 // Optional canonical source contract for the minecart track table.
606
607 // Explicit dungeon stream layouts, indexed by stream kind.
608 std::unordered_map<DungeonStreamType, DungeonStreamLayout>
610
611 // Optional graphics-sheet free space and reserved sheets.
613
614 // Build pipeline
616
617 // Project registry (loaded from code_folder JSON files)
619
620 // Optional: live progression state derived from SRAM/.srm. This is used to
621 // color story event nodes and can be updated at runtime by editor panels.
622 std::optional<OracleProgressionState> oracle_progression_state_;
623};
624
625} // namespace yaze::core
626
627#endif // YAZE_CORE_HACK_MANIFEST_H
Loads and queries the hack manifest JSON for yaze-ASM integration.
bool HasDungeonStreamLayouts() const
std::vector< WriteConflict > AnalyzeWriteRanges(const std::vector< std::pair< uint32_t, uint32_t > > &ranges) const
Analyze a set of address ranges for write conflicts.
std::unordered_map< std::string, FeatureFlag > feature_flag_map_
std::optional< RoomTagEntry > GetRoomTag(uint8_t tag_id) const
Get the full room tag entry for a tag ID.
const std::vector< FeatureFlag > & feature_flags() const
std::unordered_map< uint8_t, OwnedBank > owned_banks_
AddressOwnership ClassifyAddress(uint32_t address) const
Classify a ROM address by ownership.
bool IsFeatureEnabled(const std::string &flag_name) const
const MessageLayout & message_layout() const
std::vector< SramVariable > sram_variables_
std::optional< LyraPrivateReservation > lyra_private_reservation_
std::vector< ProtectedRegion > protected_regions_
bool IsWriteOverwritten(uint32_t address) const
Check if a ROM write at this address would be overwritten by asar.
const std::vector< SramVariable > & sram_variables() const
const std::vector< RoomTagEntry > & room_tags() const
Get all room tags.
const std::unordered_map< uint8_t, OwnedBank > & owned_banks() const
void Clear()
Clear any loaded manifest state.
const MinecartTrackLayout & minecart_track_layout() const
ProjectRegistry project_registry_
const std::optional< LyraPrivateReservation > & lyra_private_reservation() const
bool IsExpandedMessage(uint16_t message_id) const
const std::string & hack_name() const
bool IsEditorManaged(uint32_t address) const
Check if an address is explicitly managed by yaze.
const ProjectRegistry & project_registry() const
BuildPipeline build_pipeline_
const GraphicsSheetLayout & graphics_sheet_layout() const
Graphics-sheet free space and reserved sheets. Empty when the optional graphics_sheet_regions section...
std::optional< AddressOwnership > GetBankOwnership(uint8_t bank) const
Get the bank ownership for a given bank number.
std::optional< OracleProgressionState > oracle_progression_state_
GraphicsSheetLayout graphics_sheet_layout_
bool HasProjectRegistry() const
std::unordered_map< uint32_t, SramVariable > sram_map_
std::string GetSramVariableName(uint32_t address) const
std::unordered_map< uint8_t, RoomTagEntry > room_tag_map_
std::vector< SnesAddressRange > editor_managed_regions_
std::unordered_map< DungeonStreamType, DungeonStreamLayout > dungeon_stream_layouts_
const std::vector< ProtectedRegion > & protected_regions() const
absl::Status LoadProjectRegistry(const std::string &code_folder)
Load project registry data from the code folder.
const DungeonStreamLayout * GetDungeonStreamLayout(DungeonStreamType stream) const
Get an explicitly declared dungeon stream layout.
bool IsProtected(uint32_t address) const
Check if an address is in a protected region.
std::optional< OracleProgressionState > oracle_progression_state() const
MinecartTrackLayout minecart_track_layout_
absl::Status LoadFromFile(const std::string &filepath)
Load manifest from a JSON file path.
absl::Status LoadFromString(const std::string &json_content)
Load manifest from a JSON string.
MessageLayout message_layout_
std::string GetRoomTagLabel(uint8_t tag_id) const
Get the human-readable label for a room tag ID.
std::vector< WriteConflict > AnalyzePcWriteRanges(const std::vector< std::pair< uint32_t, uint32_t > > &pc_ranges) const
Analyze a set of PC-offset ranges for write conflicts.
bool loaded() const
Check if the manifest has been loaded.
void SetOracleProgressionState(const OracleProgressionState &state)
const ProtectedRegion * FindProtectedRegion(uint32_t address) const
const std::vector< SnesAddressRange > & editor_managed_regions() const
const BuildPipeline & build_pipeline() const
std::vector< RoomTagEntry > room_tags_
std::vector< FeatureFlag > feature_flags_
The complete Oracle narrative progression graph.
bool loaded() const
Check if the graph has been loaded.
DungeonWriteStrategy
Save strategy allowed for a dungeon stream layout.
std::string AddressOwnershipToString(AddressOwnership ownership)
DungeonStreamType
Dungeon stream kinds with allocator layouts in the hack manifest.
LyraPrivateReservation PrivateLyraExactSaveReservation()
AddressOwnership
Ownership classification for ROM addresses and banks.
DungeonPointerEncoding
Encoding used by entries in a dungeon stream pointer table.
Build pipeline information.
A connection between two rooms (stair, holewarp, or door).
A complete dungeon entry with rooms and connections.
std::vector< DungeonConnection > doors
std::vector< DungeonConnection > holewarps
std::vector< DungeonRoom > rooms
std::vector< DungeonConnection > stairs
A room within a dungeon, with spatial and metadata info.
Explicit pointer and storage layout for one dungeon stream.
DungeonWriteStrategy strategy
std::vector< SnesAddressRange > allocation_regions
std::optional< uint8_t > pointer_bank
std::vector< SnesAddressRange > data_regions
DungeonPointerEncoding pointer_encoding
A compile-time feature flag.
Graphics-sheet storage rules declared by the hack (graphics_sheet_regions).
std::vector< uint16_t > reserved_sheets
std::vector< SnesAddressRange > allocation_regions
bool operator==(const Preimage &) const =default
std::array< uint32_t, 2 > tile32_id_range
std::array< uint32_t, 4 > dictionary_bases_pc
bool operator==(const LyraPrivateReservation &) const =default
std::array< uint32_t, 2 > stream_pc_range
std::array< Preimage, 4 > packed_preimages
Message range information for the expanded message system.
std::optional< Source > source
bool operator==(const Source &) const =default
Canonical source metadata for the ASM-owned minecart track table.
std::optional< Source > source
Oracle of Secrets game progression state parsed from SRAM.
An overworld area from the overworld registry.
An expanded bank with ownership classification.
AddressOwnership ownership
std::string ownership_note
Project-level registry data loaded from the Oracle planning outputs.
std::vector< DungeonEntry > dungeons
std::vector< OverworldArea > overworld_areas
const std::unordered_map< std::string, std::string > & room_labels() const
std::unordered_map< std::string, std::unordered_map< std::string, std::string > > all_resource_labels
A contiguous protected ROM region owned by the ASM hack.
A room tag entry from the dispatch table.
A half-open [start, end) range of canonical LoROM SNES addresses.
A custom SRAM variable definition.
A conflict detected when yaze wants to write to an ASM-owned address.
AddressOwnership ownership