Olympe Engine 2.0
2D Game Engine with ECS Architecture
Loading...
Searching...
No Matches
EditorAutosaveManager.cpp
Go to the documentation of this file.
1/*
2 * Olympe Engine - EditorAutosaveManager implementation
3 */
4
6#include <iostream>
7#include <fstream>
8#include <chrono>
9
10namespace Olympe
11{
12
21
23{
24 m_dirty = true;
25 m_debounceDeadline = nowSec + static_cast<double>(m_debounceSec);
26}
27
29 std::function<std::string()> serializeFn,
30 std::string filePath,
31 std::string fallbackPrefix)
32{
33 m_dirty = true;
34 m_debounceDeadline = nowSec + static_cast<double>(m_debounceSec);
36 m_pendingFilePath = std::move(filePath);
38}
39
41{
42 // Require at least one save path to be configured.
44 return;
45
46 // If a previous async task is still running, do not start another one.
47 if (m_future.valid() &&
48 m_future.wait_for(std::chrono::seconds(0)) != std::future_status::ready)
49 return;
50
51 bool shouldSave = false;
52
53 // Debounce: fire once the deadline has passed and there is a pending change.
55 {
56 shouldSave = true;
57 m_debounceDeadline = -1.0;
58 }
59
60 // Periodic flush.
61 if (!shouldSave && m_dirty && m_periodicIntervalSec > 0.0f && m_lastSaveTime >= 0.0)
62 {
63 double elapsed = nowSec - m_lastSaveTime;
64 if (elapsed >= static_cast<double>(m_periodicIntervalSec))
65 shouldSave = true;
66 }
67
68 if (shouldSave)
69 {
70 m_dirty = false;
72
74 {
75 // Serialize on the calling (UI) thread before handing off to background.
76 // The serializer is cleared after a single invocation: callers are
77 // expected to supply a fresh lambda with each ScheduleSave() call.
78 // If the serializer returns an empty string (e.g. tree has validation
79 // errors, or nothing is dirty), this save cycle is silently skipped;
80 // the next ScheduleSave() will provide a new serializer to retry.
81 std::string data = m_pendingSerializeFn();
82 m_pendingSerializeFn = nullptr;
83
84 if (!data.empty())
85 {
86 std::string path = m_pendingFilePath;
87 if (path.empty())
88 {
89 path = m_pendingFallbackPrefix.empty()
90 ? "GameData/AI/autosave_"
92 path += std::to_string(++m_fallbackCounter);
93 }
94 m_pendingFilePath = std::string();
95 LaunchAsyncWrite(std::move(data), std::move(path));
96 }
97 }
98 else
99 {
100 LaunchAsync();
101 }
102 }
103}
104
106{
107 if (m_future.valid())
108 {
109 m_future.get(); // wait for completion
110 }
111}
112
114{
115 // Capture a copy of the save function so the lambda is self-contained.
116 auto fn = m_saveFn;
117 m_future = std::async(std::launch::async, [fn]()
118 {
119 try
120 {
121 fn();
122 }
123 catch (const std::exception& e)
124 {
125 std::cerr << "[EditorAutosaveManager] Save failed: " << e.what() << std::endl;
126 }
127 catch (...)
128 {
129 std::cerr << "[EditorAutosaveManager] Save failed with unknown error." << std::endl;
130 }
131 });
132}
133
134void EditorAutosaveManager::LaunchAsyncWrite(std::string data, std::string path)
135{
136 m_future = std::async(std::launch::async, [data = std::move(data), path = std::move(path)]()
137 {
138 try
139 {
140 std::ofstream out(path, std::ios::out | std::ios::trunc);
141 if (!out.is_open())
142 {
143 std::cerr << "[EditorAutosaveManager] Cannot open: " << path << std::endl;
144 return;
145 }
146 out << data;
147 }
148 catch (const std::exception& e)
149 {
150 std::cerr << "[EditorAutosaveManager] Write failed: " << e.what() << std::endl;
151 }
152 catch (...)
153 {
154 std::cerr << "[EditorAutosaveManager] Write failed with unknown error." << std::endl;
155 }
156 });
157}
158
159} // namespace Olympe
ComponentTypeID GetComponentTypeID_Static()
Definition ECS_Entity.h:56
void Init(std::function< void()> saveFn, float debounceSec=1.5f, float periodicIntervalSec=60.0f)
Set the timing parameters and an optional legacy save callback.
void Flush()
Block until any running async save finishes.
void LaunchAsyncWrite(std::string data, std::string path)
void ScheduleSave(double nowSec)
Notify the manager that a change occurred (legacy overload).
std::function< std::string()> m_pendingSerializeFn
void Tick(double nowSec)
Must be called once per frame to advance timers and launch saves.
< Provides AssetID and INVALID_ASSET_ID