147 lines
6.0 KiB
C++
147 lines
6.0 KiB
C++
#ifndef PKMNLIB_IPKMNBINARYSTREAM_HPP
|
|
#define PKMNLIB_IPKMNBINARYSTREAM_HPP
|
|
|
|
#include <Arbutils/Collections/Dictionary.hpp>
|
|
#include <Arbutils/StringView.hpp>
|
|
#include <CreatureLib/Battling/ScriptHandling/ScriptCategory.hpp>
|
|
#include <angelscript.h>
|
|
|
|
class IPkmnBinaryStream : public asIBinaryStream {
|
|
protected:
|
|
size_t _angelScriptBound;
|
|
|
|
IPkmnBinaryStream(size_t angelScriptBound) : _angelScriptBound(angelScriptBound) {}
|
|
|
|
public:
|
|
virtual void WriteTypes(
|
|
const ArbUt::Dictionary<ScriptCategory, ArbUt::Dictionary<ArbUt::StringView, AngelScriptTypeInfo* non_null>>& types,
|
|
const ArbUt::Dictionary<ArbUt::StringView, asITypeInfo* non_null>& itemUseTypes,
|
|
const ArbUt::Dictionary<ArbUt::StringView, asITypeInfo* non_null>& evolutionTypes) {
|
|
// We serialize our types in the format
|
|
// "[category(byte)][name(str)]\2[decl(str)]\2[name(str)]\2[decl(str)]\1[category(byte)]...."
|
|
|
|
i16 categoryArr[1];
|
|
for (const auto& dic : types) {
|
|
// Write the category
|
|
categoryArr[0] = (i16)dic.first;
|
|
Write(categoryArr, sizeof(i16));
|
|
for (const auto& inner : dic.second) {
|
|
// Write the script name
|
|
Write(inner.first.c_str(), sizeof(char) * inner.first.Length());
|
|
// Write the divider
|
|
Write("\2", sizeof(char));
|
|
// Write the declaration of the script
|
|
auto decl = inner.second->GetDecl();
|
|
Write(decl, sizeof(char) * strlen(decl));
|
|
// Write another divider.
|
|
Write("\2", sizeof(char));
|
|
}
|
|
// Write the divider between categories.
|
|
Write("\1", sizeof(char));
|
|
}
|
|
|
|
categoryArr[0] = (i16)-1;
|
|
Write(categoryArr, sizeof(i16));
|
|
for (const auto& inner : itemUseTypes) {
|
|
// Write the script name
|
|
Write(inner.first.c_str(), sizeof(char) * inner.first.Length());
|
|
// Write the divider
|
|
Write("\2", sizeof(char));
|
|
// Write the declaration of the script
|
|
auto decl = inner.second->GetName();
|
|
Write(decl, sizeof(char) * strlen(decl));
|
|
// Write another divider.
|
|
Write("\2", sizeof(char));
|
|
}
|
|
// Write the divider between categories.
|
|
Write("\1", sizeof(char));
|
|
|
|
categoryArr[0] = (i16)-2;
|
|
Write(categoryArr, sizeof(i16));
|
|
for (const auto& inner : evolutionTypes) {
|
|
// Write the script name
|
|
Write(inner.first.c_str(), sizeof(char) * inner.first.Length());
|
|
// Write the divider
|
|
Write("\2", sizeof(char));
|
|
// Write the declaration of the script
|
|
auto decl = inner.second->GetName();
|
|
Write(decl, sizeof(char) * strlen(decl));
|
|
// Write another divider.
|
|
Write("\2", sizeof(char));
|
|
}
|
|
// Write the divider between categories.
|
|
Write("\1", sizeof(char));
|
|
}
|
|
|
|
virtual ArbUt::Dictionary<i16, ArbUt::Dictionary<ArbUt::StringView, u32>> ReadTypes() {
|
|
_angelScriptBound = SIZE_MAX;
|
|
ArbUt::Dictionary<i16, ArbUt::Dictionary<ArbUt::StringView, uint32_t>> types;
|
|
i16 categoryArr[1];
|
|
while (true) {
|
|
// Every inner database starts with the category, of known size. Read that.
|
|
auto read = Read(categoryArr, sizeof(i16));
|
|
// If we haven't read anything, we are finished.
|
|
if (read == 0) {
|
|
break;
|
|
}
|
|
ArbUt::Dictionary<ArbUt::StringView, uint32_t> innerDb;
|
|
|
|
// We don't know the sizes of the name and decl. Allocate 128 characters for them, as that should be enough.
|
|
char name[128];
|
|
char decl[128];
|
|
size_t pos = 0;
|
|
bool isDecl = false;
|
|
|
|
while (true) {
|
|
// Keep reading characters
|
|
char cArr[1];
|
|
Read(cArr, sizeof(char));
|
|
auto c = cArr[0];
|
|
// If we find a '\1' separator
|
|
if (c == '\1') {
|
|
// and if we were reading the decl
|
|
if (isDecl) {
|
|
// Insert the name and decl into the dictionary. Close off the decl with eof as well.
|
|
decl[pos] = '\0';
|
|
|
|
innerDb.Set(ArbUt::StringView(name), ArbUt::StringView::CalculateHash(decl));
|
|
}
|
|
// If we have found \1, we are done with the current category, so break.
|
|
break;
|
|
}
|
|
// If we find a '\2' separator, we need to toggle between writing to name and writing to decl. If we
|
|
// were writing a decl, also insert the name and decl into the dictionary.
|
|
if (c == '\2') {
|
|
if (isDecl) {
|
|
// Insert the name and decl into the dictionary. Close off the decl with eof as well.
|
|
decl[pos] = '\0';
|
|
innerDb.Set(ArbUt::StringView(name), ArbUt::StringView::CalculateHash(decl));
|
|
// Reset our position and toggle back to name.
|
|
pos = 0;
|
|
isDecl = false;
|
|
continue;
|
|
} else {
|
|
// Close of the name with eof, reset position and toggle to decl.
|
|
name[pos] = '\0';
|
|
pos = 0;
|
|
isDecl = true;
|
|
continue;
|
|
}
|
|
} else {
|
|
// If we haven't found any control character, just add the character to the thing we are writing to,
|
|
// and increment the position.
|
|
if (isDecl) {
|
|
decl[pos++] = c;
|
|
} else {
|
|
name[pos++] = c;
|
|
}
|
|
}
|
|
}
|
|
types.Set(categoryArr[0], innerDb);
|
|
}
|
|
return types;
|
|
}
|
|
};
|
|
|
|
#endif // PKMNLIB_IPKMNBINARYSTREAM_HPP
|