yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
session_types.cc
Go to the documentation of this file.
2
3#include "zelda3/game_data.h"
4
5#include <algorithm>
6#include <filesystem>
7
11#include "app/editor/editor.h"
27
28namespace yaze::editor {
29
31 UserSettings* user_settings, size_t session_id,
32 EditorRegistry* editor_registry)
33 : session_id_(session_id),
34 rom_(rom),
35 game_data_(game_data),
36 user_settings_(user_settings),
37 editor_registry_(editor_registry),
38 gfx_group_workspace_(std::make_unique<GfxGroupWorkspaceState>()) {
39 auto register_factory = [&](EditorType type, auto&& fallback) {
40 editor_factories_[type] =
41 [this, type,
42 fallback = std::forward<decltype(fallback)>(
43 fallback)]() mutable -> std::unique_ptr<Editor> {
44 if (editor_registry_) {
45 if (auto created = editor_registry_->CreateEditor(type, rom_)) {
46 return created;
47 }
48 }
49 return fallback();
50 };
51 };
52
53 register_factory(EditorType::kAssembly,
54 [this]() { return std::make_unique<AssemblyEditor>(rom_); });
55 register_factory(EditorType::kDungeon, [this]() {
56 return std::make_unique<DungeonEditorV2>(rom_);
57 });
58 register_factory(EditorType::kGraphics,
59 [this]() { return std::make_unique<GraphicsEditor>(rom_); });
60 register_factory(EditorType::kMusic,
61 [this]() { return std::make_unique<MusicEditor>(rom_); });
62 register_factory(EditorType::kOverworld, [this]() {
63 return std::make_unique<OverworldEditor>(rom_);
64 });
65 register_factory(EditorType::kPalette,
66 [this]() { return std::make_unique<PaletteEditor>(rom_); });
67 register_factory(EditorType::kScreen,
68 [this]() { return std::make_unique<ScreenEditor>(rom_); });
69 register_factory(EditorType::kSprite,
70 [this]() { return std::make_unique<SpriteEditor>(rom_); });
71 register_factory(EditorType::kMessage,
72 [this]() { return std::make_unique<MessageEditor>(rom_); });
73 register_factory(EditorType::kHex,
74 [this]() { return std::make_unique<MemoryEditor>(rom_); });
75 register_factory(EditorType::kSettings,
76 []() { return std::make_unique<SettingsPanel>(); });
77 register_factory(EditorType::kPlanning,
78 []() { return std::make_unique<PlanningEditor>(); });
79}
80
81EditorSet::~EditorSet() = default;
82
84 user_settings_ = settings;
85 if (auto* panel = GetSettingsPanel()) {
86 panel->SetUserSettings(settings);
87 }
88}
89
91 game_data_ = game_data;
92 for (auto& [type, editor] : editors_) {
93 (void)type;
94 editor->SetGameData(game_data_);
95 }
96}
97
99 dependencies_ = dependencies;
100 for (auto& [type, editor] : editors_) {
101 editor->SetDependencies(dependencies);
102 }
103}
104
107 return;
108 }
110 for (auto& [type, editor] : editors_) {
111 (void)type;
112 editor->PrepareForSessionTeardown();
113 }
114}
115
117 return EnsureEditorCreated(type);
118}
119
121 if (type == EditorType::kUnknown) {
122 return nullptr;
123 }
124
125 if (auto it = editors_.find(type); it != editors_.end()) {
126 return it->second.get();
127 }
128 return nullptr;
129}
130
132 if (type == EditorType::kUnknown) {
133 return nullptr;
134 }
135
136 if (auto* editor = FindEditor(type)) {
137 return editor;
138 }
139
140 auto factory_it = editor_factories_.find(type);
141 if (factory_it == editor_factories_.end()) {
142 return nullptr;
143 }
144
145 auto editor = factory_it->second();
146 if (!editor) {
147 return nullptr;
148 }
149
150 if (dependencies_.has_value()) {
152 }
153 if (game_data_ != nullptr) {
154 editor->SetGameData(game_data_);
155 }
156 if (auto* dungeon = dynamic_cast<DungeonEditorV2*>(editor.get())) {
157 dungeon->SetRoomGraphicsOverworldProvider(
158 [this]() { return GetOverworldData(); });
159 }
160 auto main_usage =
161 [this](int group,
162 int slot) -> absl::StatusOr<zelda3::MainGroupUsageReport> {
164 return absl::FailedPreconditionError("No loaded graphics session");
165 }
166 auto rooms = zelda3::CollectRoomGfx(*rom_);
167 std::map<int, uint8_t> explicit_main;
168 if (const auto* dungeon = dynamic_cast<const DungeonEditorV2*>(
170 dungeon->rooms().ForEachLoaded([&](int id, const zelda3::Room& room) {
171 rooms[id] = {room.blockset(), room.spriteset()};
172 explicit_main[id] = room.render_entrance_blockset();
173 });
174 }
175 return zelda3::DescribeMainGroupUsage(*rom_, *game_data_, group, slot,
176 rooms, explicit_main,
178 };
179 auto roomset_usage =
180 [this](int group) -> absl::StatusOr<zelda3::RoomsetUsageReport> {
182 return absl::FailedPreconditionError("No loaded graphics session");
183 if (const auto* dungeon = dynamic_cast<const DungeonEditorV2*>(
185 return dungeon->GetRoomGraphicsUsage(group);
189 };
190 if (auto* graphics = dynamic_cast<GraphicsEditor*>(editor.get())) {
191 graphics->SetRoomUsageProvider([this]() {
194 return contexts;
195 if (auto* dungeon = static_cast<DungeonEditorV2*>(
197 dungeon->VisitGraphicsUsageRooms([&](int id, zelda3::Room& room,
198 const std::string& provenance,
199 bool current, int entrance_slot) {
200 contexts.emplace(id, usage_preview::LiveRoomContext{
201 &room, provenance, current, entrance_slot});
202 });
203 }
204 return contexts;
205 });
206 graphics->SetMainGraphicsUsageCallback(main_usage);
207 graphics->SetRoomsetGraphicsUsageCallback(roomset_usage);
208 }
209 if (auto* overworld = dynamic_cast<OverworldEditor*>(editor.get())) {
210 overworld->SetMainGraphicsUsageCallback(main_usage);
211 overworld->SetRoomsetGraphicsUsageCallback(roomset_usage);
212 }
213 if (type == EditorType::kSettings && user_settings_ != nullptr) {
214 if (auto* settings_panel = static_cast<SettingsPanel*>(editor.get())) {
215 settings_panel->SetUserSettings(user_settings_);
216 }
217 }
218
219 Editor* editor_ptr = editor.get();
220 editors_[type] = std::move(editor);
221
222 if (ShouldTrackAsActiveEditor(type)) {
223 const_cast<EditorSet*>(this)->TrackActiveEditor(editor_ptr);
224 }
225
226 return editor_ptr;
227}
228
230 switch (type) {
240 return true;
241 default:
242 return false;
243 }
244}
245
247 if (editor == nullptr) {
248 return;
249 }
250 if (std::find(active_editors_.begin(), active_editors_.end(), editor) ==
251 active_editors_.end()) {
252 active_editors_.push_back(editor);
253 }
254}
255
256void EditorSet::OpenAssemblyFolder(const std::string& folder_path) const {
257 if (auto* editor = GetAssemblyEditor()) {
258 editor->OpenFolder(folder_path);
259 }
260}
261
262void EditorSet::ChangeActiveAssemblyFile(std::string_view path) const {
263 if (auto* editor = GetAssemblyEditor()) {
264 editor->ChangeActiveFile(path);
265 }
266}
267
269 if (auto* editor =
271 return editor->asar_wrapper();
272 }
273 return nullptr;
274}
275
276const std::map<std::string, core::AsarSymbol>& EditorSet::GetAssemblySymbols()
277 const {
278 static const std::map<std::string, core::AsarSymbol> kEmpty;
279 if (auto* editor =
281 return editor->symbols();
282 }
283 return kEmpty;
284}
285
287 if (auto* editor =
289 return editor->LoadedRoomCount();
290 }
291 return 0;
292}
293
295 if (auto* editor =
297 return editor->TotalRoomCount();
298 }
299 return 0;
300}
301
302std::vector<std::pair<uint32_t, uint32_t>>
304 if (auto* editor =
306 return editor->CollectWriteRanges();
307 }
308 return {};
309}
310
312 if (!game_data_loaded || !rom.is_loaded()) {
313 return false;
314 }
315 auto diff = zelda3::DiffGfxGroups(rom, game_data);
316 return diff.ok() && diff->any();
317}
318
320 if (auto* editor =
322 return editor->HasPendingGraphicsChanges();
323 }
324 return false;
325}
326
328 if (auto* editor =
330 return editor->HasPendingScreenChanges();
331 }
332 return false;
333}
334
336 if (auto* editor =
338 editor->InvalidateRomBackedState();
339 }
340}
341
343 if (auto* editor =
345 return editor->HasPendingProjectDraftChanges();
346 }
347 return false;
348}
349
351 if (auto* editor =
353 return editor->PrepareProjectSave();
354 }
355 return absl::OkStatus();
356}
357
359 if (auto* editor =
361 return &editor->overworld();
362 }
363 return nullptr;
364}
365
366// Deprecated named accessors
368 return GetEditorAs<AssemblyEditor>(EditorType::kAssembly);
369}
371 return GetEditorAs<DungeonEditorV2>(EditorType::kDungeon);
372}
374 return GetEditorAs<GraphicsEditor>(EditorType::kGraphics);
375}
377 return GetEditorAs<MusicEditor>(EditorType::kMusic);
378}
380 return GetEditorAs<OverworldEditor>(EditorType::kOverworld);
381}
383 return GetEditorAs<PaletteEditor>(EditorType::kPalette);
384}
386 return GetEditorAs<ScreenEditor>(EditorType::kScreen);
387}
389 return GetEditorAs<SpriteEditor>(EditorType::kSprite);
390}
392 return GetEditorAs<SettingsPanel>(EditorType::kSettings);
393}
395 return GetEditorAs<MessageEditor>(EditorType::kMessage);
396}
398 return GetEditorAs<MemoryEditor>(EditorType::kHex);
399}
400
401RomSession::RomSession(UserSettings* user_settings, size_t session_id,
402 EditorRegistry* editor_registry)
403 : game_data(&rom),
404 editors(&rom, &game_data, user_settings, session_id, editor_registry) {}
405
406RomSession::RomSession(Rom&& r, UserSettings* user_settings, size_t session_id,
407 EditorRegistry* editor_registry)
408 : rom(std::move(r)),
409 game_data(&rom),
410 editors(&rom, &game_data, user_settings, session_id, editor_registry) {
414}
415
416void RomSession::CaptureRomIdentity(bool preserve_editing_source) {
417 if (!rom.is_loaded()) {
418 rom_baseline.reset();
419 return;
420 }
421 auto path = std::filesystem::path(rom.filename()).lexically_normal();
422 path.make_preferred();
423 const std::string editing_source = preserve_editing_source && rom_baseline
424 ? rom_baseline->editing_source_path
425 : path.string();
427 util::ComputeRomIdentityHashes(rom.data(), rom.size()), path.string(),
428 editing_source};
429}
430
434 std::make_unique<std::array<gfx::Bitmap, zelda3::kNumGfxSheets>>(
436 // Rehydration always reads the authoring store, including unsaved pixels.
437 for (uint16_t i = 0; i < graphics_display_->size(); ++i) {
438 auto& bitmap = graphics_display_->at(i);
439 if (!bitmap.is_active() || !game_data.sheet_store.HasSheet(i))
440 continue;
441 const auto pixels = game_data.sheet_store.Sheet(i);
442 bitmap.set_data(std::vector<uint8_t>(pixels.begin(), pixels.end()));
443 }
445}
446
450
452 auto& arena = gfx::Arena::Get();
453 if (arena.gfx_sheets_owner() == &game_data) {
454 arena.BindGraphicsSheets(nullptr, nullptr);
455 }
456 if (graphics_display_) {
457 for (auto& bitmap : *graphics_display_)
458 arena.RetireBitmap(bitmap);
459 graphics_display_.reset();
460 }
461}
462
467
468std::string RomSession::GetDisplayName() const {
469 if (!custom_name.empty()) {
470 return custom_name;
471 }
472 return rom.title().empty() ? "Untitled Session" : rom.title();
473}
474
475} // namespace yaze::editor
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
Definition rom.h:49
auto filename() const
Definition rom.h:207
auto data() const
Definition rom.h:201
auto size() const
Definition rom.h:200
bool is_loaded() const
Definition rom.h:187
auto title() const
Definition rom.h:199
Modern C++ wrapper for Asar 65816 assembler integration.
Text editor for modifying assembly code.
DungeonEditorV2 - Simplified dungeon editor using component delegation.
Manages editor types, categories, and lifecycle.
std::unique_ptr< Editor > CreateEditor(EditorType type, Rom *rom) const
Contains a complete set of editors for a single ROM instance.
std::optional< EditorDependencies > dependencies_
MemoryEditor * GetMemoryEditor() const
std::unordered_map< EditorType, std::unique_ptr< Editor > > editors_
DungeonEditorV2 * GetDungeonEditor() const
void OpenAssemblyFolder(const std::string &folder_path) const
MusicEditor * GetMusicEditor() const
ScreenEditor * GetScreenEditor() const
void SetGameData(zelda3::GameData *game_data)
bool HasPendingProjectDraftChanges() const
Editor * GetExistingEditor(EditorType type) const
bool ShouldTrackAsActiveEditor(EditorType type) const
core::AsarWrapper * GetAsarWrapper() const
absl::Status PrepareProjectSave()
void TrackActiveEditor(Editor *editor)
void ChangeActiveAssemblyFile(std::string_view path) const
void ApplyDependencies(const EditorDependencies &dependencies)
const std::map< std::string, core::AsarSymbol > & GetAssemblySymbols() const
EditorSet(Rom *rom=nullptr, zelda3::GameData *game_data=nullptr, UserSettings *user_settings=nullptr, size_t session_id=0, EditorRegistry *editor_registry=nullptr)
Editor * EnsureEditorCreated(EditorType type) const
SpriteEditor * GetSpriteEditor() const
UserSettings * user_settings_
Editor * GetEditor(EditorType type) const
GraphicsEditor * GetGraphicsEditor() const
int LoadedDungeonRoomCount() const
Editor * FindEditor(EditorType type) const
PaletteEditor * GetPaletteEditor() const
bool HasPendingGraphicsChanges() const
bool HasPendingScreenChanges() const
std::unordered_map< EditorType, EditorFactory > editor_factories_
EditorRegistry * editor_registry_
void set_user_settings(UserSettings *settings)
zelda3::Overworld * GetOverworldData() const
MessageEditor * GetMessageEditor() const
int TotalDungeonRoomCount() const
SettingsPanel * GetSettingsPanel() const
std::vector< Editor * > active_editors_
zelda3::GameData * game_data_
OverworldEditor * GetOverworldEditor() const
AssemblyEditor * GetAssemblyEditor() const
std::vector< std::pair< uint32_t, uint32_t > > CollectDungeonWriteRanges() const
Interface for editor classes.
Definition editor.h:249
virtual void SetDependencies(const EditorDependencies &deps)
Definition editor.h:254
Allows the user to edit graphics sheets from the game or view prototype graphics.
A class for editing music data in a Rom.
Main UI class for editing overworld maps in A Link to the Past.
Allows the user to view and edit in game palettes.
The ScreenEditor class allows the user to edit a variety of screens in the game or create a custom me...
Manages the settings UI displayed in the right sidebar.
Allows the user to edit sprites.
Manages user preferences and settings persistence.
void BindGraphicsSheets(GraphicsSheets *sheets, const void *owner)
Definition arena.cc:522
static Arena & Get()
Definition arena.cc:24
static PaletteManager & Get()
Get the singleton instance.
void ReleaseSession(const zelda3::GameData *game_data)
Forget all palette tracking for a closing or reloaded ROM session.
bool HasSheet(uint16_t sheet) const
True when the buffer holds all 4096 bytes of sheet.
absl::Span< const uint8_t > Sheet(uint16_t sheet) const
The sheet's 4096 pixels, or an empty span when it is not held.
uint8_t blockset() const
Definition room.h:1015
uint8_t spriteset() const
Definition room.h:1018
uint8_t render_entrance_blockset() const
Definition room.h:1016
std::map< int, LiveRoomContext > LiveRoomContexts
Editors are the view controllers for the application.
RomIdentityHashes ComputeRomIdentityHashes(const uint8_t *data, size_t size)
Definition rom_hash.cc:84
absl::StatusOr< RoomsetUsageReport > DescribeRoomsetUsage(Rom &rom, GameData &game_data, int roomset, const std::map< int, RoomGfxInfo > &rooms, const Overworld *live_overworld)
absl::StatusOr< MainGroupUsageReport > DescribeMainGroupUsage(Rom &rom, GameData &game_data, int group, int slot, const std::map< int, RoomGfxInfo > &rooms, const std::map< int, uint8_t > &explicit_room_main, const Overworld *live_overworld)
absl::StatusOr< GfxGroupDiff > DiffGfxGroups(const Rom &rom, const GameData &data)
Definition game_data.cc:334
std::map< int, RoomGfxInfo > CollectRoomGfx(const Rom &rom)
Unified dependency container for all editor types.
Definition editor.h:170
Per-ROM-session UI state shared by all GfxGroupEditor surfaces.
std::unique_ptr< std::array< gfx::Bitmap, zelda3::kNumGfxSheets > > graphics_display_
core::FeatureFlags::Flags feature_flags
void CaptureRomIdentity(bool preserve_editing_source=false)
bool HasPendingGfxGroupChanges() const
std::optional< RomBaselineIdentity > rom_baseline
zelda3::GameData game_data
std::string GetDisplayName() const
std::array< gfx::Bitmap, kNumGfxSheets > gfx_bitmaps
Definition game_data.h:90