10#include <Tempest/MemReader>
11#include <Tempest/MemWriter>
13#include <Tempest/Application>
15size_t Serialize::writeFunc(
void* pOpaque, uint64_t file_ofs,
const void* pBuf,
size_t n) {
16 auto& self = *
reinterpret_cast<Serialize*
>(pOpaque);
17 file_ofs += mz_zip_get_archive_file_start_offset(&self.impl);
18 if(file_ofs!=self.curOffset) {
19 self.impl.m_last_error = MZ_ZIP_FILE_SEEK_FAILED;
22 size_t ret = self.fout->write(pBuf,n);
27size_t Serialize::readFunc(
void* pOpaque, uint64_t file_ofs,
void* pBuf,
size_t n) {
28 auto& self = *
reinterpret_cast<Serialize*
>(pOpaque);
29 file_ofs += mz_zip_get_archive_file_start_offset(&self.impl);
30 if(self.curOffset<file_ofs) {
31 size_t diff = size_t(file_ofs-self.curOffset);
32 size_t mv = self.fin->seek(diff);
33 self.curOffset += uint64_t(mv);
35 self.impl.m_last_error = MZ_ZIP_FILE_SEEK_FAILED;
39 if(self.curOffset>file_ofs) {
40 size_t diff = size_t(self.curOffset-file_ofs);
41 size_t mv = self.fin->unget(diff);
42 self.curOffset -= uint64_t(mv);
44 self.impl.m_last_error = MZ_ZIP_FILE_SEEK_FAILED;
48 size_t ret = self.fin->read(pBuf,n);
59 entryBuf .reserve(1*1024*1024);
60 entryName.reserve(256);
62 impl.m_pWrite = Serialize::writeFunc;
63 impl.m_pIO_opaque =
this;
64 impl.m_zip_type = MZ_ZIP_TYPE_USER;
65 mz_zip_writer_init_v2(&impl, 0, 0);
69 entryBuf .resize(1*1024*1024);
70 entryName.reserve(256);
72 impl.m_pRead = Serialize::readFunc;
73 impl.m_pIO_opaque =
this;
74 impl.m_zip_type = MZ_ZIP_TYPE_USER;
75 mz_zip_reader_init(&impl, fin.size(), 0);
81 mz_zip_writer_finalize_archive(&impl);
82 mz_zip_writer_end(&impl);
93void Serialize::closeEntry() {
99 mz_uint level = entryBuf.size()>256 ? MZ_BEST_SPEED : MZ_NO_COMPRESSION;
100 mz_bool status = mz_zip_writer_add_mem(&impl, entryName.c_str(), entryBuf.data(), entryBuf.size(), level);
104 throw std::runtime_error(
"unable to write entry in game archive");
107bool Serialize::implSetEntry(std::string_view fname) {
110 while(prefix<fname.size() && prefix<entryName.size()) {
111 if(entryName[prefix]!=fname[prefix])
119 for(
size_t i=prefix; i<entryName.size(); ++i) {
120 if(entryName[i]==
'/' && i+1<entryName.size()) {
121 const char prev = entryName[i+1];
122 entryName[i+1] =
'\0';
123 const auto it = outFileList.insert(entryName.c_str());
125 mz_bool status = mz_zip_writer_add_mem(&impl, entryName.c_str(), NULL, 0, MZ_NO_COMPRESSION);
127 throw std::runtime_error(
"unable to allocate entry in game archive");
129 entryName[i+1] = prev;
135 mz_uint32
id = mz_uint32(-1);
136 if(mz_zip_reader_locate_file_v2(&impl, entryName.c_str(),
nullptr, 0, &
id)) {
137 mz_zip_archive_file_stat stat = {};
138 mz_zip_reader_file_stat(&impl,
id,&stat);
139 entryBuf.resize(
size_t(stat.m_uncomp_size));
140 mz_zip_reader_extract_file_to_mem(&impl,entryName.c_str(),entryBuf.data(),entryBuf.size(),0);
145 return !entryBuf.empty();
150uint32_t Serialize::implDirectorySize(std::string_view e) {
153 for(mz_uint i = 0; i<mz_zip_reader_get_num_files(&impl); i++) {
154 mz_zip_archive_file_stat stat = {};
155 if(!mz_zip_reader_file_stat(&impl, i, &stat))
156 throw std::runtime_error(
"unable to locate entry in game archive");
157 auto len = std::strlen(stat.m_filename);
158 if(len>e.size() && std::memcmp(e.data(),stat.m_filename,e.size())==0) {
159 auto sep = std::strchr(stat.m_filename+e.size(),
'/');
160 if(sep==
nullptr || (sep+1)==(stat.m_filename+len))
170 size_t at = entryBuf.size();
171 entryBuf.resize(entryBuf.size()+sz);
172 std::memcpy(&entryBuf[at],buf,sz);
176 if(fin==
nullptr || readOffset+sz>entryBuf.size())
177 throw std::runtime_error(
"unable to read save-game file");
178 std::memcpy(buf,&entryBuf[
size_t(readOffset)],sz);
182void Serialize::implWrite(
const std::string& s) {
183 uint32_t sz=uint32_t(s.size());
188void Serialize::implRead(std::string& s) {
196void Serialize::implWrite(std::string_view s) {
197 uint32_t sz=uint32_t(s.size());
203 implWrite(uint8_t(w));
207 implRead(
reinterpret_cast<uint8_t&
>(w));
210void Serialize::implWrite(
const WayPoint* wptr) {
211 implWrite(wptr ? wptr->
name :
"");
214void Serialize::implRead(
const WayPoint*& wptr) {
216 wptr = ctx==
nullptr ? nullptr : ctx->
findPoint(tmpStr,
false);
219void Serialize::implWrite(
const ScriptFn& fn) {
220 uint32_t v = uint32_t(-1);
221 if(fn.
ptr<uint64_t(std::numeric_limits<uint32_t>::max()))
222 v = uint32_t(fn.
ptr);
226void Serialize::implRead(
ScriptFn& fn) {
229 if(v==std::numeric_limits<uint32_t>::max())
230 fn.
ptr = size_t(-1);
else
234void Serialize::implWrite(
const Npc* npc) {
235 uint32_t
id = ctx==
nullptr ? uint32_t(-1) : ctx->npcId(npc);
239void Serialize::implRead(
const Npc *&npc) {
240 uint32_t
id=uint32_t(-1);
242 npc = ctx==
nullptr ? nullptr : ctx->
npcById(
id);
245void Serialize::implWrite(
Npc *npc) {
246 uint32_t
id = ctx==
nullptr ? uint32_t(-1) : ctx->npcId(npc);
250void Serialize::implRead(
Npc *&npc) {
251 uint32_t
id=uint32_t(-1);
253 npc = ctx==
nullptr ? nullptr : ctx->
npcById(
id);
257 uint32_t
id = ctx==
nullptr ? uint32_t(-1) : ctx->mobsiId(mobsi);
262 uint32_t
id=uint32_t(-1);
264 mobsi = ctx==
nullptr ? nullptr : ctx->
mobsiById(
id);
275void Serialize::implWrite(
const Tempest::Pixmap& p) {
276 std::vector<uint8_t> tmp;
277 tmp.reserve(4*1024*1024);
278 Tempest::MemWriter w{tmp};
283void Serialize::implRead(Tempest::Pixmap& p) {
284 Tempest::MemReader r{&entryBuf[size_t(readOffset)],size_t(entryBuf.size()-readOffset)};
285 p = Tempest::Pixmap(r);
286 readOffset += r.cursorPosition();
289void Serialize::implWrite(
const zenkit::INpc& h) {
290 write(uint32_t(h.symbol_index()));
291 write(h.id,h.name,h.slot,h.effect,int32_t(h.type));
292 write(int32_t(h.flags));
293 write(h.attribute,h.hitchance,h.protection,h.damage);
294 write(h.damage_type,h.guild,h.level);
296 write(h.fight_tactic,h.weapon,h.voice,h.voice_pitch,h.body_mass);
297 write(h.daily_routine,h.start_aistate);
298 write(h.spawnpoint,h.spawn_delay,h.senses,h.senses_range);
300 write(h.wp,h.exp,h.exp_next,h.lp,h.bodystate_interruptable_override,h.no_focus);
304 uint32_t instanceSymbol=0;
305 read(instanceSymbol);
307 auto sym = vm.find_symbol_by_index(instanceSymbol);
309 if (sym !=
nullptr) {
310 vm.allocate_instance(h, sym);
312 Tempest::Log::e(
"Cannot load serialized NPC ", instanceSymbol,
": Symbol not found.");
315 read(h->id,h->name,h->slot,h->effect,
reinterpret_cast<int32_t&
>(h->type));
316 read(
reinterpret_cast<int32_t&
>(h->flags));
317 read(h->attribute,h->hitchance,h->protection,h->damage);
318 read(h->damage_type,h->guild,h->level);
320 read(h->fight_tactic,h->weapon,h->voice,h->voice_pitch,h->body_mass);
321 read(h->daily_routine,h->start_aistate);
322 read(h->spawnpoint,h->spawn_delay,h->senses,h->senses_range);
324 read(h->wp,h->exp,h->exp_next,h->lp,h->bodystate_interruptable_override,h->no_focus);
327void Serialize::implWrite(
const FpLock &fp) {
331void Serialize::implRead(
FpLock &fp) {
335void Serialize::implWrite(
const zenkit::AnimationSample& i) {
339void Serialize::implRead(zenkit::AnimationSample& i) {
341 read(i.position.x,i.position.y,i.position.z);
342 read(i.rotation.x,i.rotation.y,i.rotation.z,i.rotation.w);
void save(Serialize &fout) const
void load(Serialize &fin)
void readNpc(zenkit::DaedalusVm &vm, std::shared_ptr< zenkit::INpc > &npc)
void write(const Arg &... a)
void writeBytes(const void *v, size_t sz)
void readBytes(void *v, size_t sz)
std::string_view worldName() const
Serialize(Tempest::ODevice &fout)
const WayPoint * findPoint(std::string_view name, bool inexact=true) const
Npc * npcById(uint32_t id)
std::string_view name() const
Interactive * mobsiById(uint32_t id)