1#ifndef YAZE_APP_EDITOR_SPRITE_ZSPRITE_H
2#define YAZE_APP_EDITOR_SPRITE_ZSPRITE_H
13#include "absl/status/status.h"
36 is.read(
reinterpret_cast<char*
>(&
byte), 1);
39 length |= (
byte & 0x7F) << shift;
41 }
while (
byte & 0x80);
43 std::string result(length,
'\0');
45 is.read(&result[0], length);
54 uint32_t length =
static_cast<uint32_t
>(str.size());
58 uint8_t
byte = length & 0x7F;
63 os.write(
reinterpret_cast<const char*
>(&
byte), 1);
68 os.write(str.data(), str.size());
74 OamTile(uint8_t
x, uint8_t
y,
bool mx,
bool my, uint16_t
id, uint8_t pal,
118 :
name(std::move(n)),
code(std::move(c)) {}
139 absl::Status
Load(
const std::string& filename) {
140 std::ifstream input(filename, std::ios::binary);
141 if (!input.is_open()) {
142 return absl::NotFoundError(
"File not found: " + filename);
145 std::string content(8 * 1024 * 1024 + 1,
'\0');
146 input.read(content.data(), content.size());
147 content.resize(
static_cast<size_t>(input.gcount()));
149 return absl::DataLossError(
"Cannot read ZSM asset");
151 std::istringstream fs(content, std::ios::binary);
157 int32_t animation_count = 0;
158 fs.read(
reinterpret_cast<char*
>(&animation_count),
sizeof(int32_t));
161 for (
int i = 0; i < animation_count; i++) {
163 uint8_t afs, afe, afspeed;
164 fs.read(
reinterpret_cast<char*
>(&afs),
sizeof(uint8_t));
165 fs.read(
reinterpret_cast<char*
>(&afe),
sizeof(uint8_t));
166 fs.read(
reinterpret_cast<char*
>(&afspeed),
sizeof(uint8_t));
167 animations.emplace_back(afs, afe, afspeed, aname);
171 int32_t frame_count = 0;
172 fs.read(
reinterpret_cast<char*
>(&frame_count),
sizeof(int32_t));
175 for (
int i = 0; i < frame_count; i++) {
178 int32_t tile_count = 0;
179 fs.read(
reinterpret_cast<char*
>(&tile_count),
sizeof(int32_t));
181 for (
int j = 0; j < tile_count; j++) {
183 uint8_t tpal, tprior, tx, ty, tz;
184 bool tmx, tmy, tsize;
186 fs.read(
reinterpret_cast<char*
>(&tid),
sizeof(uint16_t));
187 fs.read(
reinterpret_cast<char*
>(&tpal),
sizeof(uint8_t));
188 fs.read(
reinterpret_cast<char*
>(&tmx),
sizeof(
bool));
189 fs.read(
reinterpret_cast<char*
>(&tmy),
sizeof(
bool));
190 fs.read(
reinterpret_cast<char*
>(&tprior),
sizeof(uint8_t));
191 fs.read(
reinterpret_cast<char*
>(&tsize),
sizeof(
bool));
192 fs.read(
reinterpret_cast<char*
>(&tx),
sizeof(uint8_t));
193 fs.read(
reinterpret_cast<char*
>(&ty),
sizeof(uint8_t));
194 fs.read(
reinterpret_cast<char*
>(&tz),
sizeof(uint8_t));
196 OamTile tile(tx, ty, tmx, tmy, tid, tpal, tsize, tprior);
225 uint8_t prize, palette, oamnbr, hitbox, health, damage;
226 fs.read(
reinterpret_cast<char*
>(&prize),
sizeof(uint8_t));
227 fs.read(
reinterpret_cast<char*
>(&palette),
sizeof(uint8_t));
228 fs.read(
reinterpret_cast<char*
>(&oamnbr),
sizeof(uint8_t));
229 fs.read(
reinterpret_cast<char*
>(&hitbox),
sizeof(uint8_t));
230 fs.read(
reinterpret_cast<char*
>(&health),
sizeof(uint8_t));
231 fs.read(
reinterpret_cast<char*
>(&damage),
sizeof(uint8_t));
241 if (fs.peek() != EOF) {
245 int32_t routine_count = 0;
246 fs.read(
reinterpret_cast<char*
>(&routine_count),
sizeof(int32_t));
248 for (
int i = 0; i < routine_count; i++) {
256 if (fs.peek() != EOF) {
260 return absl::OkStatus();
266 absl::Status
Save(
const std::string& filename) {
269 return absl::InvalidArgumentError(
270 "ZSM asset exceeds supported authoring counts");
272 if (frame.Tiles.size() > 128)
273 return absl::InvalidArgumentError(
"ZSM frame exceeds 128 tiles");
274 for (
const auto& value :
281 std::from_chars(value.data(), value.data() + value.size(), number);
282 if (parsed.ec != std::errc{} ||
283 parsed.ptr != value.data() + value.size() || number < 0 ||
285 return absl::InvalidArgumentError(
"ZSM stats must be decimal bytes");
288 std::ostringstream fs(std::ios::binary);
291 int32_t anim_count =
static_cast<int32_t
>(
animations.size());
292 fs.write(
reinterpret_cast<const char*
>(&anim_count),
sizeof(int32_t));
297 fs.write(
reinterpret_cast<const char*
>(&anim.frame_start),
299 fs.write(
reinterpret_cast<const char*
>(&anim.frame_end),
sizeof(uint8_t));
300 fs.write(
reinterpret_cast<const char*
>(&anim.frame_speed),
305 int32_t frame_count =
static_cast<int32_t
>(
editor.
Frames.size());
306 fs.write(
reinterpret_cast<const char*
>(&frame_count),
sizeof(int32_t));
310 int32_t tile_count =
static_cast<int32_t
>(frame.Tiles.size());
311 fs.write(
reinterpret_cast<const char*
>(&tile_count),
sizeof(int32_t));
313 for (
const auto& tile : frame.Tiles) {
314 fs.write(
reinterpret_cast<const char*
>(&tile.id),
sizeof(uint16_t));
315 fs.write(
reinterpret_cast<const char*
>(&tile.palette),
sizeof(uint8_t));
316 fs.write(
reinterpret_cast<const char*
>(&tile.mirror_x),
sizeof(bool));
317 fs.write(
reinterpret_cast<const char*
>(&tile.mirror_y),
sizeof(bool));
318 fs.write(
reinterpret_cast<const char*
>(&tile.priority),
320 fs.write(
reinterpret_cast<const char*
>(&tile.size),
sizeof(bool));
321 fs.write(
reinterpret_cast<const char*
>(&tile.x),
sizeof(uint8_t));
322 fs.write(
reinterpret_cast<const char*
>(&tile.y),
sizeof(uint8_t));
323 fs.write(
reinterpret_cast<const char*
>(&tile.z),
sizeof(uint8_t));
356 uint8_t prize =
static_cast<uint8_t
>(
358 uint8_t palette =
static_cast<uint8_t
>(
360 uint8_t oamnbr =
static_cast<uint8_t
>(
362 uint8_t hitbox =
static_cast<uint8_t
>(
364 uint8_t health =
static_cast<uint8_t
>(
366 uint8_t damage =
static_cast<uint8_t
>(
369 fs.write(
reinterpret_cast<const char*
>(&prize),
sizeof(uint8_t));
370 fs.write(
reinterpret_cast<const char*
>(&palette),
sizeof(uint8_t));
371 fs.write(
reinterpret_cast<const char*
>(&oamnbr),
sizeof(uint8_t));
372 fs.write(
reinterpret_cast<const char*
>(&hitbox),
sizeof(uint8_t));
373 fs.write(
reinterpret_cast<const char*
>(&health),
sizeof(uint8_t));
374 fs.write(
reinterpret_cast<const char*
>(&damage),
sizeof(uint8_t));
380 int32_t routine_count =
static_cast<int32_t
>(
userRoutines.size());
381 fs.write(
reinterpret_cast<const char*
>(&routine_count),
sizeof(int32_t));
390 const std::string content = fs.str();
392 std::ofstream output(filename, std::ios::binary);
394 return absl::InternalError(
"Failed to open ZSM for writing: " + filename);
395 output.write(content.data(), content.size());
398 return absl::DataLossError(
"Failed to write ZSM asset: " + filename);
399 return absl::OkStatus();
absl::Status ValidateZsmBytes(std::string_view data)
std::string ReadDotNetString(std::istream &is)
Read a .NET BinaryReader format string (7-bit encoded length prefix).
void WriteDotNetString(std::ostream &os, const std::string &str)
Write a .NET BinaryWriter format string (7-bit encoded length prefix).
#define RETURN_IF_ERROR(expr)
std::vector< OamTile > Tiles
AnimationGroup(uint8_t fs, uint8_t fe, uint8_t fsp, std::string fn)
std::vector< OamTile > Tiles
OamTile(uint8_t x, uint8_t y, bool mx, bool my, uint16_t id, uint8_t pal, bool s, uint8_t p)
std::vector< Frame > Frames
std::vector< UserRoutine > user_routines
UserRoutine(std::string n, std::string c)
std::vector< UserRoutine > userRoutines
void Reset()
Reset all sprite data to defaults.
SpriteProperty property_persist
absl::Status Save(const std::string &filename)
Save a ZSM file to disk.
SpriteProperty property_hitbox
SpriteProperty property_isboss
SpriteProperty property_impervious
SpriteProperty property_collisionlayer
SpriteProperty property_prize
SpriteProperty property_imperviousarrow
SpriteProperty property_smallshadow
SpriteProperty property_blockable
SpriteProperty property_shadow
absl::Status Load(const std::string &filename)
Load a ZSM file from disk.
SpriteProperty property_deflectarrows
SpriteProperty property_customdeath
SpriteProperty property_imperviousmelee
SpriteProperty property_fast
SpriteProperty property_oamnbr
SpriteProperty property_interaction
SpriteProperty property_watersprite
SpriteProperty property_statue
SpriteProperty property_sprname
SpriteProperty property_damagesound
SpriteProperty property_damage
std::vector< AnimationGroup > animations
SpriteProperty property_palette
SpriteProperty property_harmless
SpriteProperty property_health
SpriteProperty property_canfall
SpriteProperty property_statis
SpriteProperty property_deflectprojectiles
SpriteProperty property_sprid