6#include "absl/strings/str_format.h"
15 : toast_manager_(toast_manager) {}
18 const std::string& template_name) {
22 if (template_name.empty()) {
35 return absl::OkStatus();
42 if (filename.empty()) {
44 return absl::InvalidArgumentError(
"No filename provided");
52 return absl::InvalidArgumentError(
53 absl::StrFormat(
"Invalid project file: %s", filename));
60 absl::StrFormat(
"Failed to load project: %s", status.message()),
72 return absl::OkStatus();
77 return absl::FailedPreconditionError(
"No active project to save");
84 if (filename.empty()) {
86 return absl::InvalidArgumentError(
"No filename provided for save as");
97 absl::StrFormat(
"Failed to save project: %s", status.message()),
108 return absl::OkStatus();
112 if (project_path.empty()) {
113 return absl::InvalidArgumentError(
"No project path provided");
116#ifndef __EMSCRIPTEN__
117 if (!std::filesystem::exists(project_path)) {
118 return absl::NotFoundError(
119 absl::StrFormat(
"Project path does not exist: %s", project_path));
126 if (project_path.ends_with(
".zsproj")) {
130 "ZScream project imported successfully. Please configure ROM and "
139 absl::StrFormat(
"Project imported: %s", project_path),
145 return absl::OkStatus();
150 return absl::FailedPreconditionError(
"No active project to export");
153 if (export_path.empty()) {
154 return absl::InvalidArgumentError(
"No export path provided");
165 return absl::OkStatus();
170 return absl::FailedPreconditionError(
"No active project to repair");
180 return absl::OkStatus();
185 return absl::FailedPreconditionError(
"No active project to validate");
192 absl::StrFormat(
"Project validation failed: %s", result.message()),
202 return absl::OkStatus();
215 return {
"Empty Project",
"Dungeon Editor Project",
"Overworld Editor Project",
216 "Graphics Editor Project",
"Full Editor Project"};
220 const std::string& template_name,
const std::string& project_name) {
221 if (template_name.empty() || project_name.empty()) {
222 return absl::InvalidArgumentError(
223 "Template name and project name required");
232 const std::string preset_name =
233 template_name ==
"Basic ROM Hack" ?
"Vanilla ROM Hack" : template_name;
235 if (std::any_of(zso_templates.begin(), zso_templates.end(),
236 [&preset_name](
const auto& project_template) {
237 return project_template.name == preset_name;
246 absl::StrFormat(
"Project created from template: %s", template_name),
250 return absl::OkStatus();
254 const std::string& project_name)
const {
256 std::string filename = project_name;
257 std::replace(filename.begin(), filename.end(),
' ',
'_');
258 std::replace(filename.begin(), filename.end(),
'/',
'_');
259 std::replace(filename.begin(), filename.end(),
'\\',
'_');
261 return absl::StrFormat(
"%s.yaze", filename);
265 if (filename.empty()) {
269 std::string extension = std::filesystem::path(filename).extension().string();
273 if (extension ==
".yazeproj") {
274#ifndef __EMSCRIPTEN__
275 return std::filesystem::is_directory(filename);
281#ifndef __EMSCRIPTEN__
283 const std::string bundle_root =
285 if (!bundle_root.empty()) {
289 if (!std::filesystem::exists(filename)) {
294 return extension ==
".yaze" || extension ==
".zsproj";
298 const std::string& project_path) {
301 return absl::OkStatus();
304 std::filesystem::create_directories(project_path);
305 std::filesystem::create_directories(project_path +
"/assets");
306 std::filesystem::create_directories(project_path +
"/scripts");
307 std::filesystem::create_directories(project_path +
"/output");
308 return absl::OkStatus();
309 }
catch (
const std::exception& e) {
310 return absl::InternalError(
311 absl::StrFormat(
"Failed to create project structure: %s", e.what()));
321 if (rom_path.empty()) {
322 return absl::InvalidArgumentError(
"ROM path cannot be empty");
325#ifndef __EMSCRIPTEN__
326 if (!std::filesystem::exists(rom_path)) {
327 return absl::NotFoundError(
328 absl::StrFormat(
"ROM file not found: %s", rom_path));
336 absl::StrFormat(
"ROM set for project: %s",
337 std::filesystem::path(rom_path).filename().
string()),
341 return absl::OkStatus();
345 const std::string& project_name,
const std::string& project_path)
const {
346 if (!project_path.empty()) {
347#ifndef __EMSCRIPTEN__
348 const std::filesystem::path requested_path(project_path);
349 std::error_code directory_error;
350 if (requested_path.extension() !=
".yazeproj" &&
351 std::filesystem::is_directory(requested_path, directory_error)) {
366 const std::string& project_name,
const std::string& project_path)
const {
367 if (project_name.empty()) {
368 return absl::InvalidArgumentError(
"Project name cannot be empty");
371 const std::string target_filepath =
374#ifndef __EMSCRIPTEN__
375 std::error_code exists_error;
376 const bool target_exists =
377 std::filesystem::exists(target_filepath, exists_error);
379 return absl::InternalError(
380 absl::StrFormat(
"Could not inspect project file %s: %s",
381 target_filepath, exists_error.message()));
384 return absl::AlreadyExistsError(
385 absl::StrFormat(
"Project file already exists: %s", target_filepath));
389 return absl::OkStatus();
393 const std::string& project_name,
const std::string& project_path) {
395 const std::string target_filepath =
401 std::string project_dir;
402#ifndef __EMSCRIPTEN__
405 if (!project_dir.empty()) {
406 std::error_code directory_error;
407 std::filesystem::create_directories(project_dir, directory_error);
408 if (directory_error) {
409 return absl::InternalError(
410 absl::StrFormat(
"Could not create project directory %s: %s",
411 project_dir, directory_error.message()));
422 if (!project_dir.empty()) {
440 return absl::OkStatus();
465std::vector<project::ProjectManager::ProjectTemplate>
467 std::vector<project::ProjectManager::ProjectTemplate> templates;
472 t.
name =
"Vanilla ROM Hack";
474 "Standard ROM editing without custom ASM patches. "
475 "Limited to vanilla game features.";
476 t.
icon =
"MD_GAMEPAD";
479 templates.push_back(t);
485 t.
name =
"ZSCustomOverworld v2";
487 "Basic overworld expansion with custom BG colors, "
488 "main palettes, and parent system.";
493 templates.push_back(t);
499 t.
name =
"ZSCustomOverworld v3";
501 "Full overworld expansion: wide/tall areas, animated GFX, "
502 "subscreen overlays, and all custom features.";
503 t.
icon =
"MD_TERRAIN";
513 templates.push_back(t);
519 t.
name =
"Randomizer Compatible";
521 "Minimal editing preset compatible with ALttP Randomizer. "
522 "Avoids changes that break randomizer compatibility.";
523 t.
icon =
"MD_SHUFFLE";
526 templates.push_back(t);
535 for (
const auto& t : templates) {
536 if (t.name == preset_name) {
545 return absl::OkStatus();
549 return absl::NotFoundError(
550 absl::StrFormat(
"Unknown preset: %s", preset_name));
std::string GenerateProjectFilename(const std::string &project_name) const
absl::Status FinalizeProjectCreation(const std::string &project_name, const std::string &project_path)
Complete project creation after ROM is loaded.
absl::Status SaveProjectAs(const std::string &filename="")
absl::Status ExportProject(const std::string &export_path)
absl::Status RepairCurrentProject()
std::vector< std::string > GetAvailableTemplates() const
absl::Status ValidateProjectCreationTarget(const std::string &project_name, const std::string &project_path=std::string()) const
ToastManager * toast_manager_
bool HasActiveProject() const
std::string GetProjectPath() const
std::string ResolveProjectCreationPath(const std::string &project_name, const std::string &project_path) const
absl::Status ApplyZsoPreset(const std::string &preset_name)
Apply a ZSO preset to the current project.
absl::Status ValidateProject()
bool pending_rom_selection_
bool IsValidProjectFile(const std::string &filename) const
absl::Status SaveProject()
absl::Status SetProjectRom(const std::string &rom_path)
Set the ROM for the current project.
absl::Status CreateNewProject(const std::string &template_name="")
project::YazeProject current_project_
absl::Status OpenProject(const std::string &filename="")
void RequestRomSelection()
Request ROM selection (triggers callback)
static std::vector< project::ProjectManager::ProjectTemplate > GetZsoTemplates()
Get ZSO-specific project templates.
void CancelPendingProject()
Cancel pending project creation.
ProjectManager(ToastManager *toast_manager)
absl::Status ImportProject(const std::string &project_path)
std::function< void()> rom_selection_callback_
absl::Status LoadProjectFromFile(const std::string &filename)
std::string pending_template_name_
absl::Status InitializeProjectStructure(const std::string &project_path)
absl::Status CreateFromTemplate(const std::string &template_name, const std::string &project_name)
absl::Status SaveProjectToFile(const std::string &filename)
std::string GetProjectName() const
void Show(const std::string &message, ToastType type=ToastType::kInfo, float ttl_seconds=3.0f)
#define RETURN_IF_ERROR(expr)
bool kSaveOverworldProperties
bool kLoadCustomOverworld
bool kSaveOverworldEntrances
struct yaze::core::FeatureFlags::Flags::Overworld overworld
YazeProject template_project
Modern project structure with comprehensive settings consolidation.
static std::string ResolveBundleRoot(const std::string &path)
absl::Status ImportZScreamProject(const std::string &zscream_project_path)
std::string GetDisplayName() const
absl::Status SaveAs(const std::string &new_path)
absl::Status Open(const std::string &project_path)
absl::Status Validate() const
core::FeatureFlags::Flags feature_flags