1375 lines
50 KiB
C++

#include "ZoneLoadTemplate.h"
#include "Domain/Computations/MemberComputations.h"
#include "Domain/Computations/StructureComputations.h"
#include "Internal/BaseTemplate.h"
#include <cassert>
#include <iostream>
#include <sstream>
namespace
{
constexpr int TAG_HEADER = 1;
constexpr int TAG_SOURCE = 2;
class Template final : BaseTemplate
{
public:
Template(std::ostream& stream, RenderingContext* context)
: BaseTemplate(stream, context)
{
}
void Header()
{
LINE("// ====================================================================")
LINE("// This file has been generated by ZoneCodeGenerator.")
LINE("// Do not modify.")
LINE("// Any changes will be discarded when regenerating.")
LINE("// ====================================================================")
LINE("")
LINE("#pragma once")
LINE("")
LINE("#include \"Loading/AssetLoader.h\"")
LINEF("#include \"Game/{0}/{0}.h\"", m_env.m_game)
if (m_env.m_has_actions)
{
LINEF("#include \"Game/{0}/XAssets/{1}/{1}_actions.h\"", m_env.m_game, Lower(m_env.m_asset->m_definition->m_name))
}
LINE("#include <string>")
LINE("")
LINEF("namespace {0}", m_env.m_game)
LINE("{")
m_intendation++;
LINEF("class {0} final : public AssetLoader", LoaderClassName(m_env.m_asset))
LINE("{")
m_intendation++;
LINEF("XAssetInfo<{0}>* m_asset_info;", m_env.m_asset->m_definition->GetFullName())
if (m_env.m_has_actions)
{
LINEF("Actions_{0} m_actions;", m_env.m_asset->m_definition->m_name)
}
LINE(VariableDecl(m_env.m_asset->m_definition))
LINE(PointerVariableDecl(m_env.m_asset->m_definition))
LINE("")
// Variable Declarations: type varType;
for (auto* type : m_env.m_used_types)
{
if (type->m_info && !type->m_info->m_definition->m_anonymous && !type->m_info->m_is_leaf && !StructureComputations(type->m_info).IsAsset())
{
LINE(VariableDecl(type->m_type))
}
}
for (auto* type : m_env.m_used_types)
{
if (type->m_pointer_array_reference_exists && !type->m_is_context_asset)
{
LINE(PointerVariableDecl(type->m_type))
}
}
LINE("")
// Method Declarations
for (auto* type : m_env.m_used_types)
{
if (type->m_pointer_array_reference_exists)
{
PrintHeaderPtrArrayLoadMethodDeclaration(type->m_type);
}
}
for (auto* type : m_env.m_used_types)
{
if (type->m_array_reference_exists && type->m_info && !type->m_info->m_is_leaf && type->m_non_runtime_reference_exists)
{
PrintHeaderArrayLoadMethodDeclaration(type->m_type);
}
}
for (auto* type : m_env.m_used_structures)
{
if (type->m_non_runtime_reference_exists && !type->m_info->m_is_leaf && !StructureComputations(type->m_info).IsAsset())
{
PrintHeaderLoadMethodDeclaration(type->m_info);
}
}
PrintHeaderLoadMethodDeclaration(m_env.m_asset);
PrintHeaderTempPtrLoadMethodDeclaration(m_env.m_asset);
PrintHeaderAssetLoadMethodDeclaration(m_env.m_asset);
LINE("")
m_intendation--;
LINE("public:")
m_intendation++;
PrintHeaderConstructor();
PrintHeaderMainLoadMethodDeclaration(m_env.m_asset);
PrintHeaderGetNameMethodDeclaration(m_env.m_asset);
m_intendation--;
LINE("};")
m_intendation--;
LINE("}")
}
void Source()
{
LINE("// ====================================================================")
LINE("// This file has been generated by ZoneCodeGenerator.")
LINE("// Do not modify.")
LINE("// Any changes will be discarded when regenerating.")
LINE("// ====================================================================")
LINE("")
LINEF("#include \"{0}_load_db.h\"", Lower(m_env.m_asset->m_definition->m_name))
LINEF("#include \"{0}_mark_db.h\"", Lower(m_env.m_asset->m_definition->m_name))
LINE("#include <cassert>")
LINE("#include <cstring>")
LINE("")
if (!m_env.m_referenced_assets.empty())
{
LINE("// Referenced Assets:")
for (const auto* type : m_env.m_referenced_assets)
{
LINEF("#include \"../{0}/{0}_load_db.h\"", Lower(type->m_type->m_name))
}
LINE("")
}
LINEF("using namespace {0};", m_env.m_game)
LINE("")
PrintConstructorMethod();
for (const auto* type : m_env.m_used_types)
{
if (type->m_pointer_array_reference_exists)
{
LINE("")
PrintLoadPtrArrayMethod(type->m_type, type->m_info, type->m_pointer_array_reference_is_reusable);
}
}
for (const auto* type : m_env.m_used_types)
{
if (type->m_array_reference_exists && type->m_info && !type->m_info->m_is_leaf && type->m_non_runtime_reference_exists)
{
LINE("")
PrintLoadArrayMethod(type->m_type, type->m_info);
}
}
for (const auto* type : m_env.m_used_structures)
{
if (type->m_non_runtime_reference_exists && !type->m_info->m_is_leaf && !StructureComputations(type->m_info).IsAsset())
{
LINE("")
PrintLoadMethod(type->m_info);
}
}
LINE("")
PrintLoadMethod(m_env.m_asset);
LINE("")
PrintLoadPtrMethod(m_env.m_asset);
LINE("")
PrintLoadAssetMethod(m_env.m_asset);
LINE("")
PrintMainLoadMethod();
LINE("")
PrintGetNameMethod();
}
private:
enum class MemberLoadType : std::uint8_t
{
ARRAY_POINTER,
DYNAMIC_ARRAY,
EMBEDDED,
EMBEDDED_ARRAY,
POINTER_ARRAY,
SINGLE_POINTER
};
static std::string LoaderClassName(const StructureInformation* asset)
{
return std::format("Loader_{0}", asset->m_definition->m_name);
}
static std::string MarkerClassName(const StructureInformation* asset)
{
return std::format("Marker_{0}", asset->m_definition->m_name);
}
static std::string VariableDecl(const DataDefinition* def)
{
return std::format("{0}* var{1};", def->GetFullName(), MakeSafeTypeName(def));
}
static std::string PointerVariableDecl(const DataDefinition* def)
{
return std::format("{0}** var{1}Ptr;", def->GetFullName(), MakeSafeTypeName(def));
}
void PrintHeaderPtrArrayLoadMethodDeclaration(const DataDefinition* def) const
{
LINEF("void LoadPtrArray_{0}(bool atStreamStart, size_t count);", MakeSafeTypeName(def))
}
void PrintHeaderArrayLoadMethodDeclaration(const DataDefinition* def) const
{
LINEF("void LoadArray_{0}(bool atStreamStart, size_t count);", MakeSafeTypeName(def))
}
void PrintHeaderLoadMethodDeclaration(const StructureInformation* info) const
{
LINEF("void Load_{0}(bool atStreamStart);", MakeSafeTypeName(info->m_definition))
}
void PrintHeaderTempPtrLoadMethodDeclaration(const StructureInformation* info) const
{
LINEF("void LoadPtr_{0}(bool atStreamStart);", MakeSafeTypeName(info->m_definition))
}
void PrintHeaderAssetLoadMethodDeclaration(const StructureInformation* info) const
{
LINEF("void LoadAsset_{0}({1}** pAsset);", MakeSafeTypeName(info->m_definition), info->m_definition->GetFullName())
}
void PrintHeaderGetNameMethodDeclaration(const StructureInformation* info) const
{
LINEF("static std::string GetAssetName({0}* pAsset);", info->m_definition->GetFullName())
}
void PrintHeaderMainLoadMethodDeclaration(const StructureInformation* info) const
{
LINEF("XAssetInfo<{0}>* Load({0}** pAsset);", info->m_definition->GetFullName())
}
void PrintHeaderConstructor() const
{
LINEF("{0}(Zone* zone, IZoneInputStream* stream);", LoaderClassName(m_env.m_asset))
}
void PrintVariableInitialization(const DataDefinition* def) const
{
LINEF("var{0} = nullptr;", def->m_name)
}
void PrintPointerVariableInitialization(const DataDefinition* def) const
{
LINEF("var{0}Ptr = nullptr;", def->m_name)
}
void PrintConstructorMethod()
{
LINEF("{0}::{0}(Zone* zone, IZoneInputStream* stream)", LoaderClassName(m_env.m_asset))
m_intendation++;
LINE_STARTF(": AssetLoader({0}, zone, stream)", m_env.m_asset->m_asset_enum_entry->m_name)
if (m_env.m_has_actions)
{
LINE_MIDDLE(", m_actions(zone)")
}
LINE_END("")
m_intendation--;
LINE("{")
m_intendation++;
LINE("m_asset_info = nullptr;")
PrintVariableInitialization(m_env.m_asset->m_definition);
PrintPointerVariableInitialization(m_env.m_asset->m_definition);
LINE("")
for (const auto* type : m_env.m_used_types)
{
if (type->m_info && !type->m_info->m_definition->m_anonymous && !type->m_info->m_is_leaf && !StructureComputations(type->m_info).IsAsset())
{
PrintVariableInitialization(type->m_type);
}
}
for (const auto* type : m_env.m_used_types)
{
if (type->m_info && type->m_pointer_array_reference_exists && !type->m_is_context_asset)
{
PrintPointerVariableInitialization(type->m_type);
}
}
m_intendation--;
LINE("}")
}
void PrintLoadPtrArrayMethod_Loading(const DataDefinition* def, const StructureInformation* info) const
{
LINEF("*{0} = m_stream->Alloc<{1}>({2});", MakeTypePtrVarName(def), def->GetFullName(), def->GetAlignment())
if (info && !info->m_is_leaf)
{
LINEF("{0} = *{1};", MakeTypeVarName(info->m_definition), MakeTypePtrVarName(def))
LINEF("Load_{0}(true);", MakeSafeTypeName(def))
}
else
{
LINEF("m_stream->Load<{0}>(*{1});", def->GetFullName(), MakeTypePtrVarName(def))
}
}
void PrintLoadPtrArrayMethod_PointerCheck(const DataDefinition* def, StructureInformation* info, const bool reusable)
{
LINEF("if (*{0})", MakeTypePtrVarName(def))
LINE("{")
m_intendation++;
if (info && StructureComputations(info).IsAsset())
{
LINEF("{0} loader(m_zone, m_stream);", LoaderClassName(info))
LINEF("loader.Load({0});", MakeTypePtrVarName(def))
}
else
{
if (reusable)
{
LINEF("if (*{0} == PTR_FOLLOWING)", MakeTypePtrVarName(def))
LINE("{")
m_intendation++;
PrintLoadPtrArrayMethod_Loading(def, info);
m_intendation--;
LINE("}")
LINE("else")
LINE("{")
m_intendation++;
LINEF("*{0} = m_stream->ConvertOffsetToPointer(*{0});", MakeTypePtrVarName(def))
m_intendation--;
LINE("}")
}
else
{
PrintLoadPtrArrayMethod_Loading(def, info);
}
}
m_intendation--;
LINE("}")
}
void PrintLoadPtrArrayMethod(const DataDefinition* def, StructureInformation* info, const bool reusable)
{
LINEF("void {0}::LoadPtrArray_{1}(const bool atStreamStart, const size_t count)", LoaderClassName(m_env.m_asset), MakeSafeTypeName(def))
LINE("{")
m_intendation++;
LINEF("assert({0} != nullptr);", MakeTypePtrVarName(def))
LINE("")
LINE("if (atStreamStart)")
m_intendation++;
LINEF("m_stream->Load<{0}*>({1}, count);", def->GetFullName(), MakeTypePtrVarName(def))
m_intendation--;
LINE("")
LINEF("{0}** var = {1};", def->GetFullName(), MakeTypePtrVarName(def))
LINE("for(size_t index = 0; index < count; index++)")
LINE("{")
m_intendation++;
LINEF("{0} = var;", MakeTypePtrVarName(def))
PrintLoadPtrArrayMethod_PointerCheck(def, info, reusable);
LINE("")
LINE("var++;")
m_intendation--;
LINE("}")
m_intendation--;
LINE("}")
}
void PrintLoadArrayMethod(const DataDefinition* def, const StructureInformation* info)
{
LINEF("void {0}::LoadArray_{1}(const bool atStreamStart, const size_t count)", LoaderClassName(m_env.m_asset), MakeSafeTypeName(def))
LINE("{")
m_intendation++;
LINEF("assert({0} != nullptr);", MakeTypeVarName(def))
LINE("")
LINE("if (atStreamStart)")
m_intendation++;
LINEF("m_stream->Load<{0}>({1}, count);", def->GetFullName(), MakeTypeVarName(def))
m_intendation--;
LINE("")
LINEF("{0}* var = {1};", def->GetFullName(), MakeTypeVarName(def))
LINE("for(size_t index = 0; index < count; index++)")
LINE("{")
m_intendation++;
LINEF("{0} = var;", MakeTypeVarName(info->m_definition))
LINEF("Load_{0}(false);", info->m_definition->m_name)
LINE("var++;")
m_intendation--;
LINE("}")
m_intendation--;
LINE("}")
}
void LoadMember_Asset(const StructureInformation* info,
const MemberInformation* member,
const DeclarationModifierComputations& modifier,
const MemberLoadType loadType) const
{
if (loadType == MemberLoadType::SINGLE_POINTER)
{
LINEF("{0} loader(m_zone, m_stream);", LoaderClassName(member->m_type))
LINEF("loader.Load(&{0});", MakeMemberAccess(info, member, modifier))
}
else if (loadType == MemberLoadType::POINTER_ARRAY)
{
LoadMember_PointerArray(info, member, modifier);
}
else
{
assert(false);
LINEF("#error unsupported loadType {0} for asset", static_cast<int>(loadType))
}
}
void LoadMember_String(const StructureInformation* info,
const MemberInformation* member,
const DeclarationModifierComputations& modifier,
const MemberLoadType loadType) const
{
if (loadType == MemberLoadType::SINGLE_POINTER)
{
if (member->m_member->m_type_declaration->m_is_const)
{
LINEF("varXString = &{0};", MakeMemberAccess(info, member, modifier))
}
else
{
LINEF("varXString = const_cast<const char**>(&{0});", MakeMemberAccess(info, member, modifier))
}
LINE("LoadXString(false);")
}
else if (loadType == MemberLoadType::POINTER_ARRAY)
{
LINEF("varXString = {0};", MakeMemberAccess(info, member, modifier))
if (modifier.IsArray())
{
LINEF("LoadXStringArray(false, {0});", modifier.GetArraySize())
}
else
{
LINEF("LoadXStringArray(true, {0});", MakeEvaluation(modifier.GetPointerArrayCountEvaluation()))
}
}
else
{
assert(false);
LINEF("#error unsupported loadType {0} for string", static_cast<int>(loadType))
}
}
void LoadMember_ArrayPointer(const StructureInformation* info, const MemberInformation* member, const DeclarationModifierComputations& modifier) const
{
const MemberComputations computations(member);
if (member->m_type && !member->m_type->m_is_leaf && !computations.IsInRuntimeBlock())
{
LINEF("{0} = {1};", MakeTypeVarName(member->m_member->m_type_declaration->m_type), MakeMemberAccess(info, member, modifier))
LINEF("LoadArray_{0}(true, {1});",
MakeSafeTypeName(member->m_member->m_type_declaration->m_type),
MakeEvaluation(modifier.GetArrayPointerCountEvaluation()))
if (member->m_type->m_post_load_action)
{
LINE("")
LINE(MakeCustomActionCall(member->m_type->m_post_load_action.get()))
}
if (member->m_post_load_action)
{
LINE("")
LINE(MakeCustomActionCall(member->m_post_load_action.get()))
}
}
else
{
LINEF("m_stream->Load<{0}{1}>({2}, {3});",
MakeTypeDecl(member->m_member->m_type_declaration.get()),
MakeFollowingReferences(modifier.GetFollowingDeclarationModifiers()),
MakeMemberAccess(info, member, modifier),
MakeEvaluation(modifier.GetArrayPointerCountEvaluation()))
}
}
void LoadMember_PointerArray(const StructureInformation* info, const MemberInformation* member, const DeclarationModifierComputations& modifier) const
{
LINEF("{0} = {1};", MakeTypePtrVarName(member->m_member->m_type_declaration->m_type), MakeMemberAccess(info, member, modifier))
if (modifier.IsArray())
{
LINEF("LoadPtrArray_{0}(false, {1});", MakeSafeTypeName(member->m_member->m_type_declaration->m_type), modifier.GetArraySize())
}
else
{
LINEF("LoadPtrArray_{0}(true, {1});",
MakeSafeTypeName(member->m_member->m_type_declaration->m_type),
MakeEvaluation(modifier.GetPointerArrayCountEvaluation()))
}
}
void LoadMember_EmbeddedArray(const StructureInformation* info, const MemberInformation* member, const DeclarationModifierComputations& modifier) const
{
const MemberComputations computations(member);
std::string arraySizeStr;
if (modifier.HasDynamicArrayCount())
arraySizeStr = MakeEvaluation(modifier.GetDynamicArrayCountEvaluation());
else
arraySizeStr = std::to_string(modifier.GetArraySize());
if (!member->m_is_leaf)
{
LINEF("{0} = {1};", MakeTypeVarName(member->m_member->m_type_declaration->m_type), MakeMemberAccess(info, member, modifier))
if (computations.IsAfterPartialLoad())
{
LINEF("LoadArray_{0}(true, {1});", MakeSafeTypeName(member->m_member->m_type_declaration->m_type), arraySizeStr)
}
else
{
LINEF("LoadArray_{0}(false, {1});", MakeSafeTypeName(member->m_member->m_type_declaration->m_type), arraySizeStr)
}
if (member->m_type->m_post_load_action)
{
LINE("")
LINE(MakeCustomActionCall(member->m_type->m_post_load_action.get()))
}
if (member->m_post_load_action)
{
LINE("")
LINE(MakeCustomActionCall(member->m_post_load_action.get()))
}
}
else if (computations.IsAfterPartialLoad())
{
LINEF("m_stream->Load<{0}{1}>({2}, {3});",
MakeTypeDecl(member->m_member->m_type_declaration.get()),
MakeFollowingReferences(modifier.GetFollowingDeclarationModifiers()),
MakeMemberAccess(info, member, modifier),
arraySizeStr)
}
}
void LoadMember_DynamicArray(const StructureInformation* info, const MemberInformation* member, const DeclarationModifierComputations& modifier) const
{
if (member->m_type && !member->m_type->m_is_leaf)
{
LINEF("{0} = {1};", MakeTypeVarName(member->m_member->m_type_declaration->m_type), MakeMemberAccess(info, member, modifier))
LINEF("LoadArray_{0}(true, {1});",
MakeSafeTypeName(member->m_member->m_type_declaration->m_type),
MakeEvaluation(modifier.GetDynamicArraySizeEvaluation()))
}
else
{
LINEF("m_stream->Load<{0}{1}>({2}, {3});",
MakeTypeDecl(member->m_member->m_type_declaration.get()),
MakeFollowingReferences(modifier.GetFollowingDeclarationModifiers()),
MakeMemberAccess(info, member, modifier),
MakeEvaluation(modifier.GetDynamicArraySizeEvaluation()))
}
}
void LoadMember_Embedded(const StructureInformation* info, const MemberInformation* member, const DeclarationModifierComputations& modifier) const
{
const MemberComputations computations(member);
if (!member->m_is_leaf)
{
LINEF("{0} = &{1};", MakeTypeVarName(member->m_member->m_type_declaration->m_type), MakeMemberAccess(info, member, modifier))
if (computations.IsAfterPartialLoad())
{
LINEF("Load_{0}(true);", MakeSafeTypeName(member->m_member->m_type_declaration->m_type))
}
else
{
LINEF("Load_{0}(false);", MakeSafeTypeName(member->m_member->m_type_declaration->m_type))
}
if (member->m_type->m_post_load_action)
{
LINE("")
LINE(MakeCustomActionCall(member->m_type->m_post_load_action.get()))
}
if (member->m_post_load_action)
{
LINE("")
LINE(MakeCustomActionCall(member->m_post_load_action.get()))
}
}
else if (computations.IsAfterPartialLoad())
{
LINEF("m_stream->Load<{0}{1}>(&{2});",
MakeTypeDecl(member->m_member->m_type_declaration.get()),
MakeFollowingReferences(modifier.GetFollowingDeclarationModifiers()),
MakeMemberAccess(info, member, modifier))
}
}
void LoadMember_SinglePointer(const StructureInformation* info, const MemberInformation* member, const DeclarationModifierComputations& modifier) const
{
const MemberComputations computations(member);
if (member->m_type && !member->m_type->m_is_leaf && !computations.IsInRuntimeBlock())
{
LINEF("{0} = {1};", MakeTypeVarName(member->m_member->m_type_declaration->m_type), MakeMemberAccess(info, member, modifier))
LINEF("Load_{0}(true);", MakeSafeTypeName(member->m_type->m_definition))
if (member->m_type->m_post_load_action)
{
LINE("")
LINE(MakeCustomActionCall(member->m_type->m_post_load_action.get()))
}
if (member->m_post_load_action)
{
LINE("")
LINE(MakeCustomActionCall(member->m_post_load_action.get()))
}
}
else
{
LINEF("m_stream->Load<{0}{1}>({2});",
MakeTypeDecl(member->m_member->m_type_declaration.get()),
MakeFollowingReferences(modifier.GetFollowingDeclarationModifiers()),
MakeMemberAccess(info, member, modifier))
}
}
void LoadMember_TypeCheck(const StructureInformation* info,
const MemberInformation* member,
const DeclarationModifierComputations& modifier,
const MemberLoadType loadType) const
{
if (member->m_is_string)
{
LoadMember_String(info, member, modifier, loadType);
}
else if (member->m_type && StructureComputations(member->m_type).IsAsset())
{
LoadMember_Asset(info, member, modifier, loadType);
}
else
{
switch (loadType)
{
case MemberLoadType::ARRAY_POINTER:
LoadMember_ArrayPointer(info, member, modifier);
break;
case MemberLoadType::SINGLE_POINTER:
LoadMember_SinglePointer(info, member, modifier);
break;
case MemberLoadType::EMBEDDED:
LoadMember_Embedded(info, member, modifier);
break;
case MemberLoadType::POINTER_ARRAY:
LoadMember_PointerArray(info, member, modifier);
break;
case MemberLoadType::DYNAMIC_ARRAY:
LoadMember_DynamicArray(info, member, modifier);
break;
case MemberLoadType::EMBEDDED_ARRAY:
LoadMember_EmbeddedArray(info, member, modifier);
break;
default:
LINEF("// t={0}", static_cast<int>(loadType))
break;
}
}
}
static bool LoadMember_ShouldMakeAlloc(const MemberInformation* member, const DeclarationModifierComputations& modifier, const MemberLoadType loadType)
{
if (loadType != MemberLoadType::ARRAY_POINTER && loadType != MemberLoadType::POINTER_ARRAY && loadType != MemberLoadType::SINGLE_POINTER)
{
return false;
}
if (loadType == MemberLoadType::POINTER_ARRAY)
{
return !modifier.IsArray();
}
if (member->m_is_string)
{
return false;
}
if (member->m_type && StructureComputations(member->m_type).IsAsset())
{
return false;
}
return true;
}
void LoadMember_Alloc(const StructureInformation* info,
const MemberInformation* member,
const DeclarationModifierComputations& modifier,
const MemberLoadType loadType)
{
if (!LoadMember_ShouldMakeAlloc(member, modifier, loadType))
{
LoadMember_TypeCheck(info, member, modifier, loadType);
return;
}
const MemberComputations computations(member);
if (computations.IsInTempBlock())
{
LINEF("{0}* ptr = {1};", member->m_member->m_type_declaration->m_type->GetFullName(), MakeMemberAccess(info, member, modifier))
}
const auto typeDecl = MakeTypeDecl(member->m_member->m_type_declaration.get());
const auto followingReferences = MakeFollowingReferences(modifier.GetFollowingDeclarationModifiers());
// This used to use `alignof()` to calculate alignment but due to inconsistencies between compilers and bugs discovered in MSVC
// (Alignment specified via `__declspec(align())` showing as correct via intellisense but is incorrect when compiled for types that have a larger
// alignment than the specified value) this was changed to make ZoneCodeGenerator calculate what is supposed to be used as alignment when
// allocating. This is more reliable when being used with different compilers and the value used can be seen in the source code directly
if (member->m_alloc_alignment)
{
LINEF("{0} = m_stream->Alloc<{0}{1}>({2});",
MakeMemberAccess(info, member, modifier),
typeDecl,
followingReferences,
MakeEvaluation(member->m_alloc_alignment.get()))
}
else
{
LINEF("{0} = m_stream->Alloc<{0}{1}>({2});", MakeMemberAccess(info, member, modifier), typeDecl, followingReferences, modifier.GetAlignment())
}
if (computations.IsInTempBlock())
{
LINE("")
LINEF("{0}** toInsert = nullptr;", member->m_member->m_type_declaration->m_type->GetFullName())
LINE("if (ptr == PTR_INSERT)")
m_intendation++;
LINEF("toInsert = m_stream->InsertPointer<{0}>();", member->m_member->m_type_declaration->m_type->GetFullName())
m_intendation--;
LINE("")
}
LoadMember_TypeCheck(info, member, modifier, loadType);
if (computations.IsInTempBlock())
{
LINE("")
LINE("if (toInsert != nullptr)")
m_intendation++;
LINEF("*toInsert = {0}->{1};", MakeTypeVarName(info->m_definition), member->m_member->m_name)
m_intendation--;
}
}
static bool LoadMember_ShouldMakeReuse(const DeclarationModifierComputations& modifier, const MemberLoadType loadType)
{
if (loadType != MemberLoadType::ARRAY_POINTER && loadType != MemberLoadType::SINGLE_POINTER && loadType != MemberLoadType::POINTER_ARRAY)
{
return false;
}
if (loadType == MemberLoadType::POINTER_ARRAY && modifier.IsArray())
{
return false;
}
return true;
}
void LoadMember_Reuse(const StructureInformation* info,
const MemberInformation* member,
const DeclarationModifierComputations& modifier,
const MemberLoadType loadType)
{
if (!LoadMember_ShouldMakeReuse(modifier, loadType) || !member->m_is_reusable)
{
LoadMember_Alloc(info, member, modifier, loadType);
return;
}
const MemberComputations computations(member);
if (computations.IsInTempBlock())
{
LINEF("if ({0} == PTR_FOLLOWING || {0} == PTR_INSERT)", MakeMemberAccess(info, member, modifier))
LINE("{")
m_intendation++;
LoadMember_Alloc(info, member, modifier, loadType);
m_intendation--;
LINE("}")
LINE("else")
LINE("{")
m_intendation++;
LINEF("{0} = m_stream->ConvertOffsetToAlias({0});", MakeMemberAccess(info, member, modifier))
m_intendation--;
LINE("}")
}
else
{
LINEF("if ({0} == PTR_FOLLOWING)", MakeMemberAccess(info, member, modifier))
LINE("{")
m_intendation++;
LoadMember_Alloc(info, member, modifier, loadType);
m_intendation--;
LINE("}")
LINE("else")
LINE("{")
m_intendation++;
LINEF("{0} = m_stream->ConvertOffsetToPointer({0});", MakeMemberAccess(info, member, modifier))
m_intendation--;
LINE("}")
}
}
static bool
LoadMember_ShouldMakePointerCheck(const MemberInformation* member, const DeclarationModifierComputations& modifier, const MemberLoadType loadType)
{
if (loadType != MemberLoadType::ARRAY_POINTER && loadType != MemberLoadType::POINTER_ARRAY && loadType != MemberLoadType::SINGLE_POINTER)
return false;
if (loadType == MemberLoadType::POINTER_ARRAY)
return !modifier.IsArray();
if (member->m_is_string)
return false;
return true;
}
void LoadMember_PointerCheck(const StructureInformation* info,
const MemberInformation* member,
const DeclarationModifierComputations& modifier,
const MemberLoadType loadType)
{
if (LoadMember_ShouldMakePointerCheck(member, modifier, loadType))
{
LINEF("if ({0})", MakeMemberAccess(info, member, modifier))
LINE("{")
m_intendation++;
LoadMember_Reuse(info, member, modifier, loadType);
m_intendation--;
LINE("}")
}
else
{
LoadMember_Reuse(info, member, modifier, loadType);
}
}
void LoadMember_Block(const StructureInformation* info,
const MemberInformation* member,
const DeclarationModifierComputations& modifier,
const MemberLoadType loadType)
{
const MemberComputations computations(member);
const auto notInDefaultNormalBlock = computations.IsNotInDefaultNormalBlock();
if (notInDefaultNormalBlock)
{
LINEF("m_stream->PushBlock({0});", member->m_fast_file_block->m_name)
}
LoadMember_PointerCheck(info, member, modifier, loadType);
if (notInDefaultNormalBlock)
{
LINE("m_stream->PopBlock();")
}
}
void LoadMember_ReferenceArray(StructureInformation* info, MemberInformation* member, const DeclarationModifierComputations& modifier)
{
auto first = true;
for (const auto& entry : modifier.GetArrayEntries())
{
if (first)
{
first = false;
}
else
{
LINE("")
}
LoadMember_Reference(info, member, entry);
}
}
void LoadMember_Reference(StructureInformation* info, MemberInformation* member, const DeclarationModifierComputations& modifier)
{
if (modifier.IsDynamicArray())
{
LoadMember_Block(info, member, modifier, MemberLoadType::DYNAMIC_ARRAY);
}
else if (modifier.IsSinglePointer())
{
LoadMember_Block(info, member, modifier, MemberLoadType::SINGLE_POINTER);
}
else if (modifier.IsArrayPointer())
{
LoadMember_Block(info, member, modifier, MemberLoadType::ARRAY_POINTER);
}
else if (modifier.IsPointerArray())
{
LoadMember_Block(info, member, modifier, MemberLoadType::POINTER_ARRAY);
}
else if (modifier.IsArray() && modifier.GetNextDeclarationModifier() == nullptr)
{
LoadMember_Block(info, member, modifier, MemberLoadType::EMBEDDED_ARRAY);
}
else if (modifier.GetDeclarationModifier() == nullptr)
{
LoadMember_Block(info, member, modifier, MemberLoadType::EMBEDDED);
}
else if (modifier.IsArray())
{
LoadMember_ReferenceArray(info, member, modifier);
}
else
{
assert(false);
LINEF("#error LoadMemberReference failed @ {0}", member->m_member->m_name)
}
}
void LoadMember_Condition_Struct(StructureInformation* info, MemberInformation* member)
{
LINE("")
if (member->m_condition)
{
LINEF("if ({0})", MakeEvaluation(member->m_condition.get()))
LINE("{")
m_intendation++;
LoadMember_Reference(info, member, DeclarationModifierComputations(member));
m_intendation--;
LINE("}")
}
else
{
LoadMember_Reference(info, member, DeclarationModifierComputations(member));
}
}
void LoadMember_Condition_Union(StructureInformation* info, MemberInformation* member)
{
const MemberComputations computations(member);
if (computations.IsFirstMember())
{
LINE("")
if (member->m_condition)
{
LINEF("if ({0})", MakeEvaluation(member->m_condition.get()))
LINE("{")
m_intendation++;
LoadMember_Reference(info, member, DeclarationModifierComputations(member));
m_intendation--;
LINE("}")
}
else
{
LoadMember_Reference(info, member, DeclarationModifierComputations(member));
}
}
else if (computations.IsLastMember())
{
if (member->m_condition)
{
LINEF("else if ({0})", MakeEvaluation(member->m_condition.get()))
LINE("{")
m_intendation++;
LoadMember_Reference(info, member, DeclarationModifierComputations(member));
m_intendation--;
LINE("}")
}
else
{
LINE("else")
LINE("{")
m_intendation++;
LoadMember_Reference(info, member, DeclarationModifierComputations(member));
m_intendation--;
LINE("}")
}
}
else
{
if (member->m_condition)
{
LINEF("else if ({0})", MakeEvaluation(member->m_condition.get()))
LINE("{")
m_intendation++;
LoadMember_Reference(info, member, DeclarationModifierComputations(member));
m_intendation--;
LINE("}")
}
else
{
LINEF("#error Middle member of union must have condition ({0})", member->m_member->m_name)
}
}
}
void PrintLoadMemberIfNeedsTreatment(StructureInformation* info, MemberInformation* member)
{
const MemberComputations computations(member);
if (computations.ShouldIgnore())
return;
if (member->m_is_string || computations.ContainsNonEmbeddedReference() || member->m_type && !member->m_type->m_is_leaf
|| computations.IsAfterPartialLoad())
{
if (info->m_definition->GetType() == DataDefinitionType::UNION)
LoadMember_Condition_Union(info, member);
else
LoadMember_Condition_Struct(info, member);
}
}
void PrintLoadMethod(StructureInformation* info)
{
const StructureComputations computations(info);
LINEF("void {0}::Load_{1}(const bool atStreamStart)", LoaderClassName(m_env.m_asset), info->m_definition->m_name)
LINE("{")
m_intendation++;
LINEF("assert({0} != nullptr);", MakeTypeVarName(info->m_definition))
const auto* dynamicMember = computations.GetDynamicMember();
if (!(info->m_definition->GetType() == DataDefinitionType::UNION && dynamicMember))
{
LINE("")
LINE("if (atStreamStart)")
m_intendation++;
if (dynamicMember == nullptr)
{
LINEF("m_stream->Load<{0}>({1}); // Size: {2}",
info->m_definition->GetFullName(),
MakeTypeVarName(info->m_definition),
info->m_definition->GetSize())
}
else
{
LINEF("m_stream->LoadPartial<{0}>({1}, offsetof({0}, {2}));",
info->m_definition->GetFullName(),
MakeTypeVarName(info->m_definition),
dynamicMember->m_member->m_name)
}
m_intendation--;
}
else
{
LINE("assert(atStreamStart);")
}
if (computations.IsAsset())
{
LINE("")
LINEF("m_stream->PushBlock({0});", m_env.m_default_normal_block->m_name)
}
else if (info->m_block)
{
LINE("")
LINEF("m_stream->PushBlock({0});", info->m_block->m_name)
}
for (const auto& member : info->m_ordered_members)
{
PrintLoadMemberIfNeedsTreatment(info, member.get());
}
if (info->m_block || computations.IsAsset())
{
LINE("")
LINE("m_stream->PopBlock();")
}
m_intendation--;
LINE("}")
}
void PrintLoadPtrMethod(StructureInformation* info)
{
const bool inTemp = info->m_block && info->m_block->m_type == FastFileBlockType::TEMP;
LINEF("void {0}::LoadPtr_{1}(const bool atStreamStart)", LoaderClassName(m_env.m_asset), MakeSafeTypeName(info->m_definition))
LINE("{")
m_intendation++;
LINEF("assert({0} != nullptr);", MakeTypePtrVarName(info->m_definition))
LINE("")
LINE("if (atStreamStart)")
m_intendation++;
LINEF("m_stream->Load<{0}*>({1});", info->m_definition->GetFullName(), MakeTypePtrVarName(info->m_definition))
m_intendation--;
LINE("")
if (inTemp)
{
LINEF("m_stream->PushBlock({0});", m_env.m_default_temp_block->m_name)
LINE("")
}
LINEF("if (*{0} != nullptr)", MakeTypePtrVarName(info->m_definition))
LINE("{")
m_intendation++;
if (inTemp)
{
LINEF("if (*{0} == PTR_FOLLOWING || *{0} == PTR_INSERT)", MakeTypePtrVarName(info->m_definition))
}
else
{
LINEF("if (*{0} == PTR_FOLLOWING)", MakeTypePtrVarName(info->m_definition))
}
LINE("{")
m_intendation++;
if (inTemp)
{
LINEF("{0}* ptr = *{1};", info->m_definition->GetFullName(), MakeTypePtrVarName(info->m_definition))
}
LINEF("*{0} = m_stream->Alloc<{1}>({2});",
MakeTypePtrVarName(info->m_definition),
info->m_definition->GetFullName(),
info->m_definition->GetAlignment())
if (inTemp)
{
LINE("")
LINEF("{0}** toInsert = nullptr;", info->m_definition->GetFullName())
LINE("if (ptr == PTR_INSERT)")
m_intendation++;
LINEF("toInsert = m_stream->InsertPointer<{0}>();", info->m_definition->GetFullName())
m_intendation--;
}
auto startLoadSection = true;
if (!info->m_is_leaf)
{
if (startLoadSection)
{
startLoadSection = false;
LINE("")
}
LINEF("{0} = *{1};", MakeTypeVarName(info->m_definition), MakeTypePtrVarName(info->m_definition))
LINEF("Load_{0}(true);", MakeSafeTypeName(info->m_definition))
}
else
{
LINE("#error Ptr method cannot have leaf type")
}
if (info->m_post_load_action)
{
LINE("")
LINE(MakeCustomActionCall(info->m_post_load_action.get()))
}
if (StructureComputations(info).IsAsset())
{
LINE("")
LINEF("LoadAsset_{0}({1});", MakeSafeTypeName(info->m_definition), MakeTypePtrVarName(info->m_definition))
}
if (inTemp)
{
if (!startLoadSection)
{
LINE("")
}
LINE("if (toInsert != nullptr)")
m_intendation++;
LINEF("*toInsert = *{0};", MakeTypePtrVarName(info->m_definition))
m_intendation--;
}
m_intendation--;
LINE("}")
LINE("else")
LINE("{")
m_intendation++;
if (inTemp)
{
LINEF("*{0} = m_stream->ConvertOffsetToAlias(*{0});", MakeTypePtrVarName(info->m_definition))
}
else
{
LINEF("*{0} = m_stream->ConvertOffsetToPointer(*{0});", MakeTypePtrVarName(info->m_definition))
}
m_intendation--;
LINE("}")
m_intendation--;
LINE("}")
if (inTemp)
{
LINE("")
LINE("m_stream->PopBlock();")
}
m_intendation--;
LINE("}")
}
void PrintLoadAssetMethod(const StructureInformation* info)
{
LINEF("void {0}::LoadAsset_{1}({2}** pAsset)",
LoaderClassName(m_env.m_asset),
MakeSafeTypeName(info->m_definition),
info->m_definition->GetFullName())
LINE("{")
m_intendation++;
LINE("assert(pAsset != nullptr);")
LINE("")
LINEF("{0} marker(m_zone);", MarkerClassName(m_env.m_asset))
LINE("marker.Mark(*pAsset);")
LINE("")
LINEF("auto* reallocatedAsset = m_zone->GetMemory()->Alloc<{0}>();", info->m_definition->GetFullName())
LINEF("std::memcpy(reallocatedAsset, *pAsset, sizeof({0}));", info->m_definition->GetFullName())
LINE("")
LINEF("m_asset_info = reinterpret_cast<XAssetInfo<{0}>*>(LinkAsset(GetAssetName(*pAsset), reallocatedAsset, marker.GetDependencies(), "
"marker.GetUsedScriptStrings(), marker.GetIndirectAssetReferences()));",
info->m_definition->GetFullName())
LINE("*pAsset = m_asset_info->Asset();")
m_intendation--;
LINE("}")
}
void PrintMainLoadMethod()
{
LINEF("XAssetInfo<{0}>* {1}::Load({0}** pAsset)", m_env.m_asset->m_definition->GetFullName(), LoaderClassName(m_env.m_asset))
LINE("{")
m_intendation++;
LINE("assert(pAsset != nullptr);")
LINE("")
LINE("m_asset_info = nullptr;")
LINE("")
LINEF("{0} = pAsset;", MakeTypePtrVarName(m_env.m_asset->m_definition))
LINEF("LoadPtr_{0}(false);", MakeSafeTypeName(m_env.m_asset->m_definition))
LINE("")
LINE("if (m_asset_info == nullptr && *pAsset != nullptr)")
m_intendation++;
LINEF("m_asset_info = reinterpret_cast<XAssetInfo<{0}>*>(GetAssetInfo(GetAssetName(*pAsset)));", m_env.m_asset->m_definition->GetFullName())
m_intendation--;
LINE("")
LINE("return m_asset_info;")
m_intendation--;
LINE("}")
}
void PrintGetNameMethod()
{
LINEF("std::string {0}::GetAssetName({1}* pAsset)", LoaderClassName(m_env.m_asset), m_env.m_asset->m_definition->GetFullName())
LINE("{")
m_intendation++;
if (!m_env.m_asset->m_name_chain.empty())
{
LINE_START("return pAsset")
auto first = true;
for (const auto* member : m_env.m_asset->m_name_chain)
{
if (first)
{
first = false;
LINE_MIDDLEF("->{0}", member->m_member->m_name)
}
else
{
LINE_MIDDLEF(".{0}", member->m_member->m_name)
}
}
LINE_END(";")
}
else
{
LINEF("return \"{0}\";", m_env.m_asset->m_definition->m_name)
}
m_intendation--;
LINE("}")
}
};
} // namespace
std::vector<CodeTemplateFile> ZoneLoadTemplate::GetFilesToRender(RenderingContext* context)
{
std::vector<CodeTemplateFile> files;
auto assetName = context->m_asset->m_definition->m_name;
for (auto& c : assetName)
c = static_cast<char>(tolower(c));
files.emplace_back(std::format("{0}/{0}_load_db.h", assetName), TAG_HEADER);
files.emplace_back(std::format("{0}/{0}_load_db.cpp", assetName), TAG_SOURCE);
return files;
}
void ZoneLoadTemplate::RenderFile(std::ostream& stream, const int fileTag, RenderingContext* context)
{
Template t(stream, context);
if (fileTag == TAG_HEADER)
{
t.Header();
}
else
{
assert(fileTag == TAG_SOURCE);
t.Source();
}
}