PkmnLib/src/ScriptResolving/AngelScript/ByteCodeHandling/IPkmnBinaryStream.hpp

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