Toast Engine
Loading...
Searching...
No Matches
prefab.hpp
1
10
11#pragma once
12#include "core_types.hpp"
13
14#include <any>
15#include <array>
16#include <cstdint>
17#include <iosfwd>
18#include <optional>
19#include <span>
20#include <string>
21#include <string_view>
22#include <toast/reflect/reflect.hpp>
23#include <unordered_set>
24#include <vector>
25
26namespace toast {
27class Node;
28}
29
30namespace assets {
31
32namespace _detail {
33constexpr std::string_view array_str = "array_";
34constexpr std::string_view bool_str = "bool";
35constexpr std::string_view int_str = "int";
36constexpr std::string_view float_str = "float";
37constexpr std::string_view string_str = "string";
38constexpr std::string_view double_str = "double";
39constexpr std::string_view uid_str = "uid";
40constexpr std::string_view vec2_str = "vec2";
41constexpr std::string_view vec3_str = "vec3";
42constexpr std::string_view vec4_str = "vec4";
43constexpr std::string_view quaternion_str = "quat";
44
45constexpr uint16_t format_version = 4;
46
47struct TOAST_API NodeFileBinaryHeader {
48 const std::array<uint8_t, 6> magic = {'T', 'N', 'O', 'D', 'E', '\0'};
49 uint16_t version = format_version;
50 uint32_t node_count;
51};
52}
53
54class TOAST_API Prefab final : public Asset, public ISaveable {
55public:
56 enum class Purpose : uint8_t {
57 asset_definition,
58 instance_copy,
59 editor_snapshot
60 };
66 Prefab(std::istream& file);
67
73 Prefab(std::span<const uint8_t> bytes);
74
81 explicit Prefab(const toast::Node& node, toast::UID self_uid = toast::UID(0), Purpose purpose = Purpose::asset_definition);
82
83 Prefab() = default;
84 Prefab(const Prefab& other);
85 Prefab(Prefab&& other) noexcept;
86 auto operator=(const Prefab& other) -> Prefab&;
87 auto operator=(Prefab&& other) noexcept -> Prefab&;
88
89 [[nodiscard]]
90 auto type() const -> std::string_view override {
91 return "node";
92 }
93
99 auto serialize(SaveMode mode) const -> std::vector<uint8_t> override;
100
105 auto toFile() const -> std::string;
106
111 auto toBinary() const -> std::vector<uint8_t>;
112
117 auto validate() const -> bool;
118
127 static auto stringifyValue(toast::FieldType type, bool is_array, const std::any& value) -> std::string;
128
136 static auto valueFromString(toast::FieldType type, bool is_array, std::string_view value) -> std::optional<std::any>;
137
144 struct Field {
145 std::string name;
146 toast::FieldType type;
147 bool is_array;
148 std::any value;
149
150 template<typename T>
151 [[nodiscard]]
152 auto as() const -> T {
153 return std::any_cast<T>(value);
154 }
155 };
156
163 struct Subgroup {
164 std::string name;
165 std::vector<Field> fields;
166
167 [[nodiscard]]
168 auto find(std::string_view name) const -> std::optional<Field> {
169 auto it = std::ranges::find_if(fields, [name](const auto& field) { return field.name == name; });
170 if (it != fields.end()) {
171 return *it;
172 }
173 return {};
174 }
175 };
176
183 struct Group {
184 std::string name;
185 std::vector<Field> fields;
186 std::vector<Subgroup> subgroups;
187
188 [[nodiscard]]
189 auto find(std::string_view name) const -> std::optional<Field> {
190 auto it = std::ranges::find_if(fields, [&name](const auto& field) { return field.name == name; });
191 if (it != fields.end()) {
192 return *it;
193 }
194 for (const auto& g : subgroups) {
195 auto g_it = g.find(name);
196 if (g_it.has_value()) {
197 return g_it;
198 }
199 }
200
201 return {};
202 }
203 };
204
209 std::string path;
210 std::string value;
211 };
212
215 toast::UID target;
216 std::string function;
217 };
218
220 struct Signal {
221 std::string name;
222 std::vector<SignalConnection> connections;
223 };
224
232 struct BasicNode {
233 std::string name;
234 std::string type;
235
236 std::vector<Field> fields;
237 std::vector<Group> groups;
238 std::vector<LuaVarOverride> lua_vars;
239 std::vector<Signal> signals;
240
241 [[nodiscard]]
242 auto find(std::string_view name) const -> std::optional<Field> {
243 auto it = std::ranges::find_if(fields, [&name](const auto& field) { return field.name == name; });
244 if (it != fields.end()) {
245 return *it;
246 }
247 for (const auto& g : groups) {
248 auto g_it = g.find(name);
249 if (g_it.has_value()) {
250 return g_it;
251 }
252 }
253
254 return {};
255 }
256
257 [[nodiscard]]
258 auto findLuaVar(std::string_view path) const -> const LuaVarOverride* {
259 auto it = std::ranges::find_if(lua_vars, [&](const auto& v) { return v.path == path; });
260 return it != lua_vars.end() ? &*it : nullptr;
261 }
262 };
263
264 std::vector<Field> global_fields;
265 std::vector<BasicNode> nodes;
266
267private:
268 auto parseField(std::string_view line) -> std::optional<Field>;
269 auto parseLuaVarOverride(std::string_view line) -> std::optional<LuaVarOverride>;
270 auto parseSignal(std::string_view line) -> std::optional<Signal>;
271 auto parseType(std::string_view type, bool& is_array) -> std::optional<toast::FieldType>;
272 auto parseValue(toast::FieldType type, std::string_view value, bool& is_array) -> std::optional<std::any>;
273
274 auto parseNodeChunk(std::span<const std::string> lines) -> std::optional<BasicNode>;
275 auto parseGroupChunk(std::span<const std::string> lines) -> std::optional<Group>;
276 auto parseSubgroupChunk(std::span<const std::string> lines) -> std::optional<Subgroup>;
277
278 void serializeNode(const toast::Node& node, bool is_root);
279
280 void writeNode(const BasicNode& node, std::stringstream& ss) const;
281 void writeGroup(const Group& group, std::stringstream& ss) const;
282 void writeSubgroup(const Subgroup& subgroup, std::stringstream& ss) const;
283 void writeField(const Field& field, std::stringstream& ss, std::string offset = "") const;
284 void writeSignal(const Signal& signal, std::stringstream& ss) const;
285 auto writeType(toast::FieldType type, bool is_array = false) const -> std::string;
286
287 auto fieldEquals(toast::FieldType type, bool is_array, const std::any& a, const std::any& b) const -> bool;
288 auto flattenedRootFields(const Handle<Prefab>& source) const -> std::optional<BasicNode>;
289
290 toast::UID m_self_uid;
291 Purpose m_purpose = Purpose::asset_definition;
292 std::unordered_set<uint64_t>
293 m_allowed_uids;
294};
295
296}
Inherit from this class to allow an asset to be saved.
Definition core_types.hpp:33
auto toBinary() const -> std::vector< uint8_t >
Serializes to the compact binary format.
Definition prefab.cpp:1121
static auto valueFromString(toast::FieldType type, bool is_array, std::string_view value) -> std::optional< std::any >
Parses a text value back into a typed std::any for a reflected field.
Definition prefab.cpp:776
auto toFile() const -> std::string
Serializes to the human-readable text format.
Definition prefab.cpp:418
Prefab(std::istream &file)
Parses a prefab from a text (.tnode) stream.
Definition prefab.cpp:329
auto serialize(SaveMode mode) const -> std::vector< uint8_t > override
Convenience wrapper that delegates to toFile() or toBinary() based on mode.
Definition prefab.cpp:409
static auto stringifyValue(toast::FieldType type, bool is_array, const std::any &value) -> std::string
Converts a reflected field value to its text representation.
Definition prefab.cpp:1014
auto validate() const -> bool
Checks structural invariants.
Definition prefab.cpp:1791
Definition node.hpp:81
Base types for the asset system.
SaveMode
Definition core_types.hpp:25
One node entry in a prefab file.
Definition prefab.hpp:232
std::vector< LuaVarOverride > lua_vars
empty for old files or nodes with no edited Lua vars
Definition prefab.hpp:238
std::vector< Signal > signals
empty for old files or nodes with no signal connections
Definition prefab.hpp:239
One field value read from a prefab file.
Definition prefab.hpp:144
A named group of fields and optional subgroups.
Definition prefab.hpp:183
Inspector Lua script variable that differs from its declared default.
Definition prefab.hpp:208
Definition prefab.hpp:214
Definition prefab.hpp:220
A named sub-section of fields within a group.
Definition prefab.hpp:163
Definition uid.hpp:20