mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2026-05-17 07:21:43 +00:00
chore: fix loading and writing code for T6
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
#include "GdtLoaderAttachmentT6.h"
|
||||
|
||||
#include "Game/T6/ObjConstantsT6.h"
|
||||
#include "Game/T6/T6.h"
|
||||
#include "InfoString/InfoString.h"
|
||||
#include "InfoStringLoaderAttachmentT6.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <format>
|
||||
#include <iostream>
|
||||
|
||||
using namespace T6;
|
||||
|
||||
namespace
|
||||
{
|
||||
class GdtLoaderAttachment final : public AssetCreator<AssetAttachment>
|
||||
{
|
||||
public:
|
||||
GdtLoaderAttachment(MemoryManager& memory, ISearchPath& searchPath, IGdtQueryable& gdt, Zone& zone)
|
||||
: m_gdt(gdt),
|
||||
m_info_string_loader(memory, searchPath, zone)
|
||||
{
|
||||
}
|
||||
|
||||
AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override
|
||||
{
|
||||
const auto* gdtEntry = m_gdt.GetGdtEntryByGdfAndName(ObjConstants::GDF_FILENAME_WEAPON_ATTACHMENT, assetName);
|
||||
if (gdtEntry == nullptr)
|
||||
return AssetCreationResult::NoAction();
|
||||
|
||||
InfoString infoString;
|
||||
if (!infoString.FromGdtProperties(*gdtEntry))
|
||||
{
|
||||
std::cerr << std::format("Failed to read attachment gdt entry: \"{}\"\n", assetName);
|
||||
return AssetCreationResult::Failure();
|
||||
}
|
||||
|
||||
return m_info_string_loader.CreateAsset(assetName, infoString, context);
|
||||
}
|
||||
|
||||
private:
|
||||
IGdtQueryable& m_gdt;
|
||||
InfoStringLoaderAttachment m_info_string_loader;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
namespace T6
|
||||
{
|
||||
std::unique_ptr<AssetCreator<AssetAttachment>> CreateGdtAttachmentLoader(MemoryManager& memory, ISearchPath& searchPath, IGdtQueryable& gdt, Zone& zone)
|
||||
{
|
||||
return std::make_unique<GdtLoaderAttachment>(memory, searchPath, gdt, zone);
|
||||
}
|
||||
} // namespace T6
|
||||
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "Asset/IAssetCreator.h"
|
||||
#include "Game/T6/T6.h"
|
||||
#include "Gdt/IGdtQueryable.h"
|
||||
#include "SearchPath/ISearchPath.h"
|
||||
#include "Utils/MemoryManager.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace T6
|
||||
{
|
||||
std::unique_ptr<AssetCreator<AssetAttachment>> CreateGdtAttachmentLoader(MemoryManager& memory, ISearchPath& searchPath, IGdtQueryable& gdt, Zone& zone);
|
||||
} // namespace T6
|
||||
@@ -0,0 +1,54 @@
|
||||
#include "GdtLoaderAttachmentUniqueT6.h"
|
||||
|
||||
#include "Game/T6/ObjConstantsT6.h"
|
||||
#include "Game/T6/T6.h"
|
||||
#include "InfoString/InfoString.h"
|
||||
#include "InfoStringLoaderAttachmentUniqueT6.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <format>
|
||||
#include <iostream>
|
||||
|
||||
using namespace T6;
|
||||
|
||||
namespace
|
||||
{
|
||||
class GdtLoaderAttachmentUnique final : public AssetCreator<AssetAttachmentUnique>
|
||||
{
|
||||
public:
|
||||
GdtLoaderAttachmentUnique(MemoryManager& memory, ISearchPath& searchPath, IGdtQueryable& gdt, Zone& zone)
|
||||
: m_gdt(gdt),
|
||||
m_info_string_loader(memory, searchPath, zone)
|
||||
{
|
||||
}
|
||||
|
||||
AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override
|
||||
{
|
||||
const auto* gdtEntry = m_gdt.GetGdtEntryByGdfAndName(ObjConstants::GDF_FILENAME_WEAPON_ATTACHMENT_UNIQUE, assetName);
|
||||
if (gdtEntry == nullptr)
|
||||
return AssetCreationResult::NoAction();
|
||||
|
||||
InfoString infoString;
|
||||
if (!infoString.FromGdtProperties(*gdtEntry))
|
||||
{
|
||||
std::cerr << std::format("Failed to read attachment unique gdt entry: \"{}\"\n", assetName);
|
||||
return AssetCreationResult::Failure();
|
||||
}
|
||||
|
||||
return m_info_string_loader.CreateAsset(assetName, infoString, context);
|
||||
}
|
||||
|
||||
private:
|
||||
IGdtQueryable& m_gdt;
|
||||
InfoStringLoaderAttachmentUnique m_info_string_loader;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
namespace T6
|
||||
{
|
||||
std::unique_ptr<AssetCreator<AssetAttachmentUnique>>
|
||||
CreateGdtAttachmentUniqueLoader(MemoryManager& memory, ISearchPath& searchPath, IGdtQueryable& gdt, Zone& zone)
|
||||
{
|
||||
return std::make_unique<GdtLoaderAttachmentUnique>(memory, searchPath, gdt, zone);
|
||||
}
|
||||
} // namespace T6
|
||||
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include "Asset/IAssetCreator.h"
|
||||
#include "Game/T6/T6.h"
|
||||
#include "Gdt/IGdtQueryable.h"
|
||||
#include "SearchPath/ISearchPath.h"
|
||||
#include "Utils/MemoryManager.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace T6
|
||||
{
|
||||
std::unique_ptr<AssetCreator<AssetAttachmentUnique>>
|
||||
CreateGdtAttachmentUniqueLoader(MemoryManager& memory, ISearchPath& searchPath, IGdtQueryable& gdt, Zone& zone);
|
||||
} // namespace T6
|
||||
@@ -0,0 +1,53 @@
|
||||
#include "GdtLoaderWeaponT6.h"
|
||||
|
||||
#include "Game/T6/ObjConstantsT6.h"
|
||||
#include "Game/T6/T6.h"
|
||||
#include "InfoString/InfoString.h"
|
||||
#include "InfoStringLoaderWeaponT6.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <format>
|
||||
#include <iostream>
|
||||
|
||||
using namespace T6;
|
||||
|
||||
namespace
|
||||
{
|
||||
class GdtLoaderWeapon final : public AssetCreator<AssetWeapon>
|
||||
{
|
||||
public:
|
||||
GdtLoaderWeapon(MemoryManager& memory, ISearchPath& searchPath, IGdtQueryable& gdt, Zone& zone)
|
||||
: m_gdt(gdt),
|
||||
m_info_string_loader(memory, searchPath, zone)
|
||||
{
|
||||
}
|
||||
|
||||
AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override
|
||||
{
|
||||
const auto* gdtEntry = m_gdt.GetGdtEntryByGdfAndName(ObjConstants::GDF_FILENAME_WEAPON, assetName);
|
||||
if (gdtEntry == nullptr)
|
||||
return AssetCreationResult::NoAction();
|
||||
|
||||
InfoString infoString;
|
||||
if (!infoString.FromGdtProperties(*gdtEntry))
|
||||
{
|
||||
std::cerr << std::format("Failed to read weapon gdt entry: \"{}\"\n", assetName);
|
||||
return AssetCreationResult::Failure();
|
||||
}
|
||||
|
||||
return m_info_string_loader.CreateAsset(assetName, infoString, context);
|
||||
}
|
||||
|
||||
private:
|
||||
IGdtQueryable& m_gdt;
|
||||
InfoStringLoaderWeapon m_info_string_loader;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
namespace T6
|
||||
{
|
||||
std::unique_ptr<AssetCreator<AssetWeapon>> CreateGdtWeaponLoader(MemoryManager& memory, ISearchPath& searchPath, IGdtQueryable& gdt, Zone& zone)
|
||||
{
|
||||
return std::make_unique<GdtLoaderWeapon>(memory, searchPath, gdt, zone);
|
||||
}
|
||||
} // namespace T6
|
||||
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "Asset/IAssetCreator.h"
|
||||
#include "Game/T6/T6.h"
|
||||
#include "Gdt/IGdtQueryable.h"
|
||||
#include "SearchPath/ISearchPath.h"
|
||||
#include "Utils/MemoryManager.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace T6
|
||||
{
|
||||
std::unique_ptr<AssetCreator<AssetWeapon>> CreateGdtWeaponLoader(MemoryManager& memory, ISearchPath& searchPath, IGdtQueryable& gdt, Zone& zone);
|
||||
} // namespace T6
|
||||
@@ -0,0 +1,121 @@
|
||||
#include "InfoStringLoaderAttachmentT6.h"
|
||||
|
||||
#include "Game/T6/InfoString/InfoStringToStructConverter.h"
|
||||
#include "Game/T6/T6.h"
|
||||
#include "Game/T6/Weapon/AttachmentFields.h"
|
||||
#include "Game/T6/Weapon/WeaponStrings.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <format>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
|
||||
using namespace T6;
|
||||
|
||||
namespace
|
||||
{
|
||||
eAttachmentPoint attachmentPointByAttachmentTable[]{
|
||||
ATTACHMENT_POINT_NONE, // none
|
||||
ATTACHMENT_POINT_TOP, // acog
|
||||
ATTACHMENT_POINT_TRIGGER, // dualclip
|
||||
ATTACHMENT_POINT_TOP, // dualoptic
|
||||
ATTACHMENT_POINT_BOTTOM, // dw
|
||||
ATTACHMENT_POINT_MUZZLE, // extbarrel
|
||||
ATTACHMENT_POINT_TRIGGER, // extclip
|
||||
ATTACHMENT_POINT_TRIGGER, // extramags
|
||||
ATTACHMENT_POINT_GUNPERK, // fastads
|
||||
ATTACHMENT_POINT_TOP, // fastreload
|
||||
ATTACHMENT_POINT_TRIGGER, // fmj
|
||||
ATTACHMENT_POINT_BOTTOM, // gl
|
||||
ATTACHMENT_POINT_BOTTOM, // grip
|
||||
ATTACHMENT_POINT_TOP, // holo
|
||||
ATTACHMENT_POINT_BOTTOM, // ir
|
||||
ATTACHMENT_POINT_BOTTOM, // is
|
||||
ATTACHMENT_POINT_GUNPERK, // longbreath
|
||||
ATTACHMENT_POINT_BOTTOM, // mk
|
||||
ATTACHMENT_POINT_TOP, // mms
|
||||
ATTACHMENT_POINT_TOP, // rangefinder
|
||||
ATTACHMENT_POINT_TOP, // reflex
|
||||
ATTACHMENT_POINT_MUZZLE, // rf
|
||||
ATTACHMENT_POINT_BOTTOM, // sf
|
||||
ATTACHMENT_POINT_MUZZLE, // silencer
|
||||
ATTACHMENT_POINT_TRIGGER, // stackfire
|
||||
ATTACHMENT_POINT_GUNPERK, // stalker
|
||||
ATTACHMENT_POINT_GUNPERK, // steadyaim
|
||||
ATTACHMENT_POINT_GUNPERK, // swayreduc
|
||||
ATTACHMENT_POINT_TOP, // tacknife
|
||||
ATTACHMENT_POINT_TOP, // vzoom
|
||||
};
|
||||
static_assert(std::extent_v<decltype(attachmentPointByAttachmentTable)> == ATTACHMENT_TYPE_COUNT);
|
||||
|
||||
class InfoStringToAttachmentConverter final : public InfoStringToStructConverter
|
||||
{
|
||||
protected:
|
||||
bool ConvertExtensionField(const cspField_t& field, const std::string& value) override
|
||||
{
|
||||
switch (static_cast<attachmentFieldType_t>(field.iFieldType))
|
||||
{
|
||||
case AFT_ATTACHMENTTYPE:
|
||||
return ConvertEnumInt(field.szName, value, field.iOffset, szAttachmentTypeNames, std::extent_v<decltype(szAttachmentTypeNames)>);
|
||||
|
||||
case AFT_PENETRATE_TYPE:
|
||||
return ConvertEnumInt(field.szName, value, field.iOffset, penetrateTypeNames, std::extent_v<decltype(penetrateTypeNames)>);
|
||||
|
||||
case AFT_FIRETYPE:
|
||||
return ConvertEnumInt(field.szName, value, field.iOffset, szWeapFireTypeNames, std::extent_v<decltype(szWeapFireTypeNames)>);
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
InfoStringToAttachmentConverter(const InfoString& infoString,
|
||||
WeaponAttachment& attachment,
|
||||
ZoneScriptStrings& zoneScriptStrings,
|
||||
MemoryManager& memory,
|
||||
AssetCreationContext& context,
|
||||
AssetRegistration<AssetAttachment>& registration,
|
||||
const cspField_t* fields,
|
||||
const size_t fieldCount)
|
||||
: InfoStringToStructConverter(infoString, &attachment, zoneScriptStrings, memory, context, registration, fields, fieldCount)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
void CalculateAttachmentFields(WeaponAttachment& attachment)
|
||||
{
|
||||
assert(static_cast<unsigned>(attachment.attachmentType) < ATTACHMENT_TYPE_COUNT);
|
||||
if (static_cast<unsigned>(attachment.attachmentType) < ATTACHMENT_TYPE_COUNT)
|
||||
attachment.attachmentPoint = attachmentPointByAttachmentTable[attachment.attachmentType];
|
||||
}
|
||||
} // namespace
|
||||
|
||||
InfoStringLoaderAttachment::InfoStringLoaderAttachment(MemoryManager& memory, ISearchPath& searchPath, Zone& zone)
|
||||
: m_memory(memory),
|
||||
m_search_path(searchPath),
|
||||
m_zone(zone)
|
||||
{
|
||||
}
|
||||
|
||||
AssetCreationResult InfoStringLoaderAttachment::CreateAsset(const std::string& assetName, const InfoString& infoString, AssetCreationContext& context)
|
||||
{
|
||||
auto* attachment = m_memory.Alloc<WeaponAttachment>();
|
||||
attachment->szInternalName = m_memory.Dup(assetName.c_str());
|
||||
|
||||
AssetRegistration<AssetAttachment> registration(assetName, attachment);
|
||||
|
||||
InfoStringToAttachmentConverter converter(
|
||||
infoString, *attachment, m_zone.m_script_strings, m_memory, context, registration, attachment_fields, std::extent_v<decltype(attachment_fields)>);
|
||||
if (!converter.Convert())
|
||||
{
|
||||
std::cerr << std::format("Failed to parse attachment: \"{}\"\n", assetName);
|
||||
return AssetCreationResult::Failure();
|
||||
}
|
||||
|
||||
CalculateAttachmentFields(*attachment);
|
||||
|
||||
return AssetCreationResult::Success(context.AddAsset(std::move(registration)));
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include "Asset/AssetCreationContext.h"
|
||||
#include "Asset/AssetCreationResult.h"
|
||||
#include "InfoString/InfoString.h"
|
||||
|
||||
namespace T6
|
||||
{
|
||||
class InfoStringLoaderAttachment
|
||||
{
|
||||
public:
|
||||
InfoStringLoaderAttachment(MemoryManager& memory, ISearchPath& searchPath, Zone& zone);
|
||||
|
||||
AssetCreationResult CreateAsset(const std::string& assetName, const InfoString& infoString, AssetCreationContext& context);
|
||||
|
||||
private:
|
||||
MemoryManager& m_memory;
|
||||
ISearchPath& m_search_path;
|
||||
Zone& m_zone;
|
||||
};
|
||||
} // namespace T6
|
||||
@@ -0,0 +1,242 @@
|
||||
#include "InfoStringLoaderAttachmentUniqueT6.h"
|
||||
|
||||
#include "Game/T6/InfoString/InfoStringToStructConverter.h"
|
||||
#include "Game/T6/T6.h"
|
||||
#include "Game/T6/Weapon/AttachmentUniqueFields.h"
|
||||
#include "Game/T6/Weapon/WeaponStrings.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <format>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
|
||||
using namespace T6;
|
||||
|
||||
namespace
|
||||
{
|
||||
class InfoStringToAttachmentUniqueConverter final : public InfoStringToStructConverter
|
||||
{
|
||||
protected:
|
||||
bool ConvertExtensionField(const cspField_t& field, const std::string& value) override
|
||||
{
|
||||
switch (static_cast<attachmentUniqueFieldType_t>(field.iFieldType))
|
||||
{
|
||||
case AUFT_ATTACHMENTTYPE:
|
||||
return ConvertEnumInt(field.szName, value, field.iOffset, szAttachmentTypeNames, std::extent_v<decltype(szAttachmentTypeNames)>);
|
||||
|
||||
case AUFT_HIDETAGS:
|
||||
return ConvertHideTags(field, value);
|
||||
|
||||
case AUFT_OVERLAYRETICLE:
|
||||
return ConvertEnumInt(field.szName, value, field.iOffset, szWeapOverlayReticleNames, std::extent_v<decltype(szWeapOverlayReticleNames)>);
|
||||
|
||||
case AUFT_CAMO:
|
||||
return ConvertWeaponCamo(field, value);
|
||||
|
||||
case AUFT_ANIM_NAME:
|
||||
return ConvertAnimName(field, value);
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ConvertHideTags(const cspField_t& field, const std::string& value)
|
||||
{
|
||||
std::vector<std::string> valueArray;
|
||||
if (!ParseAsArray(value, valueArray))
|
||||
{
|
||||
std::cerr << "Failed to parse hide tags as array\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (valueArray.size() > std::extent_v<decltype(WeaponFullDef::hideTags)>)
|
||||
{
|
||||
std::cerr << std::format("Cannot have more than {} hide tags!\n", std::extent_v<decltype(WeaponFullDef::hideTags)>);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* hideTags = reinterpret_cast<scr_string_t*>(reinterpret_cast<uintptr_t>(m_structure) + field.iOffset);
|
||||
|
||||
if (valueArray.size() < std::extent_v<decltype(WeaponFullDef::hideTags)>)
|
||||
m_registration.AddScriptString(m_zone_script_strings.AddOrGetScriptString(nullptr));
|
||||
|
||||
auto currentHideTag = 0u;
|
||||
for (; currentHideTag < valueArray.size(); currentHideTag++)
|
||||
{
|
||||
const auto& currentValue = valueArray[currentHideTag];
|
||||
const auto scrString =
|
||||
!currentValue.empty() ? m_zone_script_strings.AddOrGetScriptString(currentValue) : m_zone_script_strings.AddOrGetScriptString(nullptr);
|
||||
hideTags[currentHideTag] = scrString;
|
||||
m_registration.AddScriptString(scrString);
|
||||
}
|
||||
|
||||
for (; currentHideTag < std::extent_v<decltype(WeaponFullDef::hideTags)>; currentHideTag++)
|
||||
{
|
||||
hideTags[currentHideTag] = m_zone_script_strings.GetScriptString(nullptr);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool ConvertWeaponCamo(const cspField_t& field, const std::string& value)
|
||||
{
|
||||
if (value.empty())
|
||||
{
|
||||
*reinterpret_cast<WeaponCamo**>(reinterpret_cast<uintptr_t>(m_structure) + field.iOffset) = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
auto* camo = m_context.LoadDependency<AssetWeaponCamo>(value);
|
||||
|
||||
if (camo == nullptr)
|
||||
{
|
||||
std::cerr << std::format("Failed to load camo asset \"{}\"\n", value);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_registration.AddDependency(camo);
|
||||
*reinterpret_cast<WeaponCamo**>(reinterpret_cast<uintptr_t>(m_structure) + field.iOffset) = camo->Asset();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ConvertAnimName(const cspField_t& field, const std::string& value)
|
||||
{
|
||||
if (ConvertString(value, field.iOffset))
|
||||
{
|
||||
if (!value.empty())
|
||||
m_registration.AddIndirectAssetReference(m_context.LoadIndirectAssetReference<AssetXAnim>(value));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public:
|
||||
InfoStringToAttachmentUniqueConverter(const InfoString& infoString,
|
||||
WeaponAttachmentUniqueFull& attachmentUniqueFull,
|
||||
ZoneScriptStrings& zoneScriptStrings,
|
||||
MemoryManager& memory,
|
||||
AssetCreationContext& context,
|
||||
AssetRegistration<AssetAttachmentUnique>& registration,
|
||||
const cspField_t* fields,
|
||||
const size_t fieldCount)
|
||||
: InfoStringToStructConverter(infoString, &attachmentUniqueFull, zoneScriptStrings, memory, context, registration, fields, fieldCount)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
void LinkAttachmentUniqueFullSubStructs(WeaponAttachmentUniqueFull& attachmentUnique)
|
||||
{
|
||||
attachmentUnique.attachment.hideTags = attachmentUnique.hideTags;
|
||||
attachmentUnique.attachment.szXAnims = attachmentUnique.szXAnims;
|
||||
attachmentUnique.attachment.locationDamageMultipliers = attachmentUnique.locationDamageMultipliers;
|
||||
}
|
||||
|
||||
bool CalculateAttachmentUniqueFields(const std::string& assetName, WeaponAttachmentUniqueFull& attachmentUnique)
|
||||
{
|
||||
// combinedAttachmentTypeMask
|
||||
std::vector<eAttachment> attachmentsFromName;
|
||||
if (!InfoStringLoaderAttachmentUnique::ExtractAttachmentsFromAssetName(assetName, attachmentsFromName))
|
||||
{
|
||||
std::cerr << std::format("Failed to determine attachments from attachment unique name \"{}\"\n", assetName);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (attachmentsFromName.size() > 1)
|
||||
{
|
||||
for (const auto attachment : attachmentsFromName)
|
||||
{
|
||||
attachmentUnique.attachment.combinedAttachmentTypeMask |= 1 << attachment;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
bool InfoStringLoaderAttachmentUnique::ExtractAttachmentsFromAssetName(const std::string& assetName, std::vector<eAttachment>& attachmentList)
|
||||
{
|
||||
std::vector<std::string> parts;
|
||||
|
||||
auto attachCount = 1u;
|
||||
auto partStart = 0u;
|
||||
for (auto ci = 0u; ci < assetName.size(); ci++)
|
||||
{
|
||||
if (assetName[ci] == '_')
|
||||
{
|
||||
parts.emplace_back(assetName, partStart, ci - partStart);
|
||||
partStart = ci + 1;
|
||||
}
|
||||
else if (assetName[ci] == '+')
|
||||
{
|
||||
attachCount++;
|
||||
parts.emplace_back(assetName, partStart, ci - partStart);
|
||||
partStart = ci + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (partStart < assetName.size())
|
||||
parts.emplace_back(assetName, partStart, assetName.size() - partStart);
|
||||
|
||||
for (auto attachPartOffset = parts.size() - attachCount; attachPartOffset < parts.size(); attachPartOffset++)
|
||||
{
|
||||
auto& specifiedAttachName = parts[attachPartOffset];
|
||||
|
||||
for (auto& c : specifiedAttachName)
|
||||
c = static_cast<char>(tolower(c));
|
||||
|
||||
auto foundAttachment = false;
|
||||
for (auto attachIndex = 0u; attachIndex < std::extent_v<decltype(szAttachmentTypeNames)>; attachIndex++)
|
||||
{
|
||||
if (specifiedAttachName == szAttachmentTypeNames[attachIndex])
|
||||
{
|
||||
attachmentList.push_back(static_cast<eAttachment>(attachIndex));
|
||||
foundAttachment = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundAttachment)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
InfoStringLoaderAttachmentUnique::InfoStringLoaderAttachmentUnique(MemoryManager& memory, ISearchPath& searchPath, Zone& zone)
|
||||
: m_memory(memory),
|
||||
m_search_path(searchPath),
|
||||
m_zone(zone)
|
||||
{
|
||||
}
|
||||
|
||||
AssetCreationResult InfoStringLoaderAttachmentUnique::CreateAsset(const std::string& assetName, const InfoString& infoString, AssetCreationContext& context)
|
||||
{
|
||||
auto* attachmentUniqueFull = m_memory.Alloc<WeaponAttachmentUniqueFull>();
|
||||
attachmentUniqueFull->attachment.szInternalName = m_memory.Dup(assetName.c_str());
|
||||
|
||||
LinkAttachmentUniqueFullSubStructs(*attachmentUniqueFull);
|
||||
|
||||
AssetRegistration<AssetAttachmentUnique> registration(assetName, &attachmentUniqueFull->attachment);
|
||||
|
||||
InfoStringToAttachmentUniqueConverter converter(infoString,
|
||||
*attachmentUniqueFull,
|
||||
m_zone.m_script_strings,
|
||||
m_memory,
|
||||
context,
|
||||
registration,
|
||||
attachment_unique_fields,
|
||||
std::extent_v<decltype(attachment_unique_fields)>);
|
||||
if (!converter.Convert())
|
||||
{
|
||||
std::cerr << std::format("Failed to parse attachment unique: \"{}\"\n", assetName);
|
||||
return AssetCreationResult::Failure();
|
||||
}
|
||||
|
||||
return AssetCreationResult::Success(context.AddAsset(std::move(registration)));
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include "Asset/AssetCreationContext.h"
|
||||
#include "Asset/AssetCreationResult.h"
|
||||
#include "Game/T6/T6.h"
|
||||
#include "InfoString/InfoString.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace T6
|
||||
{
|
||||
class InfoStringLoaderAttachmentUnique
|
||||
{
|
||||
public:
|
||||
InfoStringLoaderAttachmentUnique(MemoryManager& memory, ISearchPath& searchPath, Zone& zone);
|
||||
|
||||
AssetCreationResult CreateAsset(const std::string& assetName, const InfoString& infoString, AssetCreationContext& context);
|
||||
|
||||
static bool ExtractAttachmentsFromAssetName(const std::string& assetName, std::vector<eAttachment>& attachmentList);
|
||||
|
||||
private:
|
||||
MemoryManager& m_memory;
|
||||
ISearchPath& m_search_path;
|
||||
Zone& m_zone;
|
||||
};
|
||||
} // namespace T6
|
||||
@@ -0,0 +1,633 @@
|
||||
#include "InfoStringLoaderWeaponT6.h"
|
||||
|
||||
#include "Game/T6/InfoString/InfoStringToStructConverter.h"
|
||||
#include "Game/T6/T6.h"
|
||||
#include "Game/T6/Weapon/WeaponFields.h"
|
||||
#include "Game/T6/Weapon/WeaponStrings.h"
|
||||
#include "InfoStringLoaderAttachmentUniqueT6.h"
|
||||
#include "Weapon/AccuracyGraphLoader.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <format>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
|
||||
using namespace T6;
|
||||
|
||||
namespace
|
||||
{
|
||||
class InfoStringToWeaponConverter final : public InfoStringToStructConverter
|
||||
{
|
||||
protected:
|
||||
bool ConvertExtensionField(const cspField_t& field, const std::string& value) override
|
||||
{
|
||||
switch (static_cast<weapFieldType_t>(field.iFieldType))
|
||||
{
|
||||
case WFT_WEAPONTYPE:
|
||||
return ConvertEnumInt(field.szName, value, field.iOffset, szWeapTypeNames, std::extent_v<decltype(szWeapTypeNames)>);
|
||||
|
||||
case WFT_WEAPONCLASS:
|
||||
return ConvertEnumInt(field.szName, value, field.iOffset, szWeapClassNames, std::extent_v<decltype(szWeapClassNames)>);
|
||||
|
||||
case WFT_OVERLAYRETICLE:
|
||||
return ConvertEnumInt(field.szName, value, field.iOffset, szWeapOverlayReticleNames, std::extent_v<decltype(szWeapOverlayReticleNames)>);
|
||||
|
||||
case WFT_PENETRATE_TYPE:
|
||||
return ConvertEnumInt(field.szName, value, field.iOffset, penetrateTypeNames, std::extent_v<decltype(penetrateTypeNames)>);
|
||||
|
||||
case WFT_IMPACT_TYPE:
|
||||
return ConvertEnumInt(field.szName, value, field.iOffset, impactTypeNames, std::extent_v<decltype(impactTypeNames)>);
|
||||
|
||||
case WFT_STANCE:
|
||||
return ConvertEnumInt(field.szName, value, field.iOffset, szWeapStanceNames, std::extent_v<decltype(szWeapStanceNames)>);
|
||||
|
||||
case WFT_PROJ_EXPLOSION:
|
||||
return ConvertEnumInt(field.szName, value, field.iOffset, szProjectileExplosionNames, std::extent_v<decltype(szProjectileExplosionNames)>);
|
||||
|
||||
case WFT_OFFHAND_CLASS:
|
||||
return ConvertEnumInt(field.szName, value, field.iOffset, offhandClassNames, std::extent_v<decltype(offhandClassNames)>);
|
||||
|
||||
case WFT_OFFHAND_SLOT:
|
||||
return ConvertEnumInt(field.szName, value, field.iOffset, offhandSlotNames, std::extent_v<decltype(offhandSlotNames)>);
|
||||
|
||||
case WFT_ANIMTYPE:
|
||||
return ConvertEnumInt(field.szName, value, field.iOffset, playerAnimTypeNames, std::extent_v<decltype(playerAnimTypeNames)>);
|
||||
|
||||
case WFT_ACTIVE_RETICLE_TYPE:
|
||||
return ConvertEnumInt(field.szName, value, field.iOffset, activeReticleNames, std::extent_v<decltype(activeReticleNames)>);
|
||||
|
||||
case WFT_GUIDED_MISSILE_TYPE:
|
||||
return ConvertEnumInt(field.szName, value, field.iOffset, guidedMissileNames, std::extent_v<decltype(guidedMissileNames)>);
|
||||
|
||||
case WFT_BOUNCE_SOUND:
|
||||
return ConvertBounceSounds(field, value);
|
||||
|
||||
case WFT_STICKINESS:
|
||||
return ConvertEnumInt(field.szName, value, field.iOffset, stickinessNames, std::extent_v<decltype(stickinessNames)>);
|
||||
|
||||
case WFT_ROTATETYPE:
|
||||
return ConvertEnumInt(field.szName, value, field.iOffset, rotateTypeNames, std::extent_v<decltype(rotateTypeNames)>);
|
||||
|
||||
case WFT_OVERLAYINTERFACE:
|
||||
return ConvertEnumInt(field.szName, value, field.iOffset, overlayInterfaceNames, std::extent_v<decltype(overlayInterfaceNames)>);
|
||||
|
||||
case WFT_INVENTORYTYPE:
|
||||
return ConvertEnumInt(field.szName, value, field.iOffset, szWeapInventoryTypeNames, std::extent_v<decltype(szWeapInventoryTypeNames)>);
|
||||
|
||||
case WFT_FIRETYPE:
|
||||
return ConvertEnumInt(field.szName, value, field.iOffset, szWeapFireTypeNames, std::extent_v<decltype(szWeapFireTypeNames)>);
|
||||
|
||||
case WFT_CLIPTYPE:
|
||||
return ConvertEnumInt(field.szName, value, field.iOffset, szWeapClipTypeNames, std::extent_v<decltype(szWeapClipTypeNames)>);
|
||||
|
||||
case WFT_AMMOCOUNTER_CLIPTYPE:
|
||||
return ConvertEnumInt(field.szName, value, field.iOffset, ammoCounterClipNames, std::extent_v<decltype(ammoCounterClipNames)>);
|
||||
|
||||
case WFT_ICONRATIO_HUD:
|
||||
case WFT_ICONRATIO_AMMOCOUNTER:
|
||||
case WFT_ICONRATIO_KILL:
|
||||
case WFT_ICONRATIO_DPAD:
|
||||
case WFT_ICONRATIO_INDICATOR:
|
||||
return ConvertEnumInt(field.szName, value, field.iOffset, weapIconRatioNames, std::extent_v<decltype(weapIconRatioNames)>);
|
||||
|
||||
case WFT_BARRELTYPE:
|
||||
return ConvertEnumInt(field.szName, value, field.iOffset, barrelTypeNames, std::extent_v<decltype(barrelTypeNames)>);
|
||||
|
||||
case WFT_HIDETAGS:
|
||||
return ConvertHideTags(field, value);
|
||||
|
||||
case WFT_EXPLOSION_TAG:
|
||||
return ConvertScriptString(value, field.iOffset);
|
||||
|
||||
case WFT_NOTETRACKSOUNDMAP:
|
||||
return ConvertNotetrackSoundMap(field, value);
|
||||
|
||||
case WFT_WEAPON_CAMO:
|
||||
return ConvertWeaponCamo(field, value);
|
||||
|
||||
case WFT_ATTACHMENTS:
|
||||
return ConvertAttachments(field, value);
|
||||
|
||||
case WFT_ATTACHMENT_UNIQUES:
|
||||
return ConvertAttachmentUniques(field, value);
|
||||
|
||||
case WFT_ANIM_NAME:
|
||||
return ConvertAnimName(field, value);
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ConvertHideTags(const cspField_t& field, const std::string& value)
|
||||
{
|
||||
std::vector<std::string> valueArray;
|
||||
if (!ParseAsArray(value, valueArray))
|
||||
{
|
||||
std::cerr << "Failed to parse hide tags as array\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (valueArray.size() > std::extent_v<decltype(WeaponFullDef::hideTags)>)
|
||||
{
|
||||
std::cerr << std::format("Cannot have more than {} hide tags!\n", std::extent_v<decltype(WeaponFullDef::hideTags)>);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* hideTags = reinterpret_cast<scr_string_t*>(reinterpret_cast<uintptr_t>(m_structure) + field.iOffset);
|
||||
|
||||
if (valueArray.size() < std::extent_v<decltype(WeaponFullDef::hideTags)>)
|
||||
m_registration.AddScriptString(m_zone_script_strings.AddOrGetScriptString(nullptr));
|
||||
|
||||
auto currentHideTag = 0u;
|
||||
for (; currentHideTag < valueArray.size(); currentHideTag++)
|
||||
{
|
||||
const auto& currentValue = valueArray[currentHideTag];
|
||||
const auto scrString =
|
||||
!currentValue.empty() ? m_zone_script_strings.AddOrGetScriptString(currentValue) : m_zone_script_strings.AddOrGetScriptString(nullptr);
|
||||
hideTags[currentHideTag] = scrString;
|
||||
m_registration.AddScriptString(scrString);
|
||||
}
|
||||
|
||||
for (; currentHideTag < std::extent_v<decltype(WeaponFullDef::hideTags)>; currentHideTag++)
|
||||
{
|
||||
hideTags[currentHideTag] = m_zone_script_strings.GetScriptString(nullptr);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
_NODISCARD bool ConvertBounceSounds(const cspField_t& field, const std::string& value) const
|
||||
{
|
||||
auto*** bounceSound = reinterpret_cast<const char***>(reinterpret_cast<uintptr_t>(m_structure) + field.iOffset);
|
||||
if (value.empty())
|
||||
{
|
||||
*bounceSound = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
assert(std::extent_v<decltype(bounceSoundSuffixes)> == SURF_TYPE_NUM);
|
||||
*bounceSound = m_memory.Alloc<const char*>(SURF_TYPE_NUM);
|
||||
for (auto i = 0u; i < SURF_TYPE_NUM; i++)
|
||||
{
|
||||
const auto currentBounceSound = value + bounceSoundSuffixes[i];
|
||||
(*bounceSound)[i] = m_memory.Dup(currentBounceSound.c_str());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
_NODISCARD bool ConvertNotetrackSoundMap(const cspField_t& field, const std::string& value)
|
||||
{
|
||||
std::vector<std::array<std::string, 2>> pairs;
|
||||
if (!ParseAsArray(value, pairs))
|
||||
{
|
||||
std::cerr << "Failed to parse notetracksoundmap as pairs\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pairs.size() > std::extent_v<decltype(WeaponFullDef::notetrackSoundMapKeys)>)
|
||||
{
|
||||
std::cerr << "Cannot have more than " << std::extent_v<decltype(WeaponFullDef::notetrackSoundMapKeys)> << " notetracksoundmap entries!\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* keys = reinterpret_cast<scr_string_t*>(reinterpret_cast<uintptr_t>(m_structure) + field.iOffset);
|
||||
auto* values = &keys[std::extent_v<decltype(WeaponFullDef::notetrackSoundMapKeys)>];
|
||||
auto currentEntryNum = 0u;
|
||||
|
||||
if (pairs.size() < std::extent_v<decltype(WeaponFullDef::notetrackSoundMapKeys)>)
|
||||
{
|
||||
m_registration.AddScriptString(m_zone_script_strings.AddOrGetScriptString(nullptr));
|
||||
}
|
||||
|
||||
for (; currentEntryNum < pairs.size(); currentEntryNum++)
|
||||
{
|
||||
const auto& currentValue = pairs[currentEntryNum];
|
||||
const auto keyScriptString = !currentValue[0].empty() ? m_zone_script_strings.AddOrGetScriptString(currentValue[0])
|
||||
: m_zone_script_strings.AddOrGetScriptString(nullptr);
|
||||
const auto valueScriptString = !currentValue[1].empty() ? m_zone_script_strings.AddOrGetScriptString(currentValue[1])
|
||||
: m_zone_script_strings.AddOrGetScriptString(nullptr);
|
||||
|
||||
keys[currentEntryNum] = keyScriptString;
|
||||
m_registration.AddScriptString(keyScriptString);
|
||||
|
||||
values[currentEntryNum] = valueScriptString;
|
||||
m_registration.AddScriptString(valueScriptString);
|
||||
}
|
||||
|
||||
for (; currentEntryNum < std::extent_v<decltype(WeaponFullDef::notetrackSoundMapKeys)>; currentEntryNum++)
|
||||
{
|
||||
const auto emptyScr = m_zone_script_strings.GetScriptString(nullptr);
|
||||
keys[currentEntryNum] = emptyScr;
|
||||
values[currentEntryNum] = emptyScr;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
_NODISCARD bool ConvertWeaponCamo(const cspField_t& field, const std::string& value)
|
||||
{
|
||||
if (value.empty())
|
||||
{
|
||||
*reinterpret_cast<WeaponCamo**>(reinterpret_cast<uintptr_t>(m_structure) + field.iOffset) = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
auto* camo = m_context.LoadDependency<AssetWeaponCamo>(value);
|
||||
|
||||
if (camo == nullptr)
|
||||
{
|
||||
std::cerr << std::format("Failed to load camo asset \"{}\"\n", value);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_registration.AddDependency(camo);
|
||||
*reinterpret_cast<WeaponCamo**>(reinterpret_cast<uintptr_t>(m_structure) + field.iOffset) = camo->Asset();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
_NODISCARD bool ConvertAttachments(const cspField_t& field, const std::string& value)
|
||||
{
|
||||
std::vector<std::string> valueArray;
|
||||
if (!ParseAsArray(value, valueArray))
|
||||
{
|
||||
std::cerr << "Failed to parse attachments as array\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
auto** attachments = reinterpret_cast<WeaponAttachment**>(reinterpret_cast<uintptr_t>(m_structure) + field.iOffset);
|
||||
|
||||
for (const auto& attachmentName : valueArray)
|
||||
{
|
||||
auto* attachmentAssetInfo = m_context.LoadDependency<AssetAttachment>(attachmentName);
|
||||
if (attachmentAssetInfo == nullptr)
|
||||
{
|
||||
std::cerr << std::format("Failed to load attachment asset \"{}\"\n", attachmentName);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* attachmentAsset = attachmentAssetInfo->Asset();
|
||||
|
||||
if (static_cast<unsigned>(attachmentAsset->attachmentType) >= ATTACHMENT_TYPE_COUNT)
|
||||
{
|
||||
std::cerr << std::format(
|
||||
"Invalid attachment type {} for attachment asset \"{}\"\n", static_cast<unsigned>(attachmentAsset->attachmentType), attachmentName);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (attachments[attachmentAsset->attachmentType] != nullptr)
|
||||
{
|
||||
std::cerr << std::format("Already loaded attachment with same type {}: \"{}\", \"{}\"\n",
|
||||
static_cast<unsigned>(attachmentAsset->attachmentType),
|
||||
attachments[attachmentAsset->attachmentType]->szInternalName,
|
||||
attachmentName);
|
||||
return false;
|
||||
}
|
||||
|
||||
attachments[attachmentAsset->attachmentType] = attachmentAsset;
|
||||
m_registration.AddDependency(attachmentAssetInfo);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
_NODISCARD static bool HasMoreThanOneAttachmentSetInMask(const int mask)
|
||||
{
|
||||
// Check if int has more than 1 bit set
|
||||
return (mask & (mask - 1)) != 0;
|
||||
}
|
||||
|
||||
_NODISCARD bool ConvertAttachmentUniques(const cspField_t& field, const std::string& value)
|
||||
{
|
||||
std::vector<std::string> valueArray;
|
||||
if (!ParseAsArray(value, valueArray))
|
||||
{
|
||||
std::cerr << "Failed to parse attachment uniques as array\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
auto** attachmentUniques = reinterpret_cast<WeaponAttachmentUnique**>(reinterpret_cast<uintptr_t>(m_structure) + field.iOffset);
|
||||
auto attachmentCombinationIndex = std::extent_v<decltype(WeaponFullDef::attachments)>;
|
||||
|
||||
for (const auto& attachmentUniqueName : valueArray)
|
||||
{
|
||||
auto* attachmentUniqueAssetInfo = m_context.LoadDependency<AssetAttachmentUnique>(attachmentUniqueName);
|
||||
if (attachmentUniqueAssetInfo == nullptr)
|
||||
{
|
||||
std::cerr << std::format("Failed to load attachment unique asset \"{}\"\n", attachmentUniqueName);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* attachmentUniqueAsset = attachmentUniqueAssetInfo->Asset();
|
||||
|
||||
if (HasMoreThanOneAttachmentSetInMask(attachmentUniqueAsset->combinedAttachmentTypeMask))
|
||||
{
|
||||
if (attachmentCombinationIndex >= std::extent_v<decltype(WeaponFullDef::attachmentUniques)>)
|
||||
{
|
||||
std::cerr << std::format(
|
||||
"Cannot have more than {} combined attachment attachment unique entries!\n",
|
||||
(std::extent_v<decltype(WeaponFullDef::attachmentUniques)> - std::extent_v<decltype(WeaponFullDef::attachments)>));
|
||||
return false;
|
||||
}
|
||||
|
||||
attachmentUniques[attachmentCombinationIndex++] = attachmentUniqueAsset;
|
||||
m_registration.AddDependency(attachmentUniqueAssetInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (static_cast<unsigned>(attachmentUniqueAsset->attachmentType) >= ATTACHMENT_TYPE_COUNT)
|
||||
{
|
||||
std::cerr << std::format("Invalid attachment type {} for attachment unique asset \"{}\"\n",
|
||||
static_cast<unsigned>(attachmentUniqueAsset->attachmentType),
|
||||
attachmentUniqueName);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (attachmentUniques[attachmentUniqueAsset->attachmentType] != nullptr)
|
||||
{
|
||||
std::cerr << std::format("Already loaded attachment unique with same type {}: \"{}\", \"{}\"\n",
|
||||
static_cast<unsigned>(attachmentUniqueAsset->attachmentType),
|
||||
attachmentUniques[attachmentUniqueAsset->attachmentType]->szInternalName,
|
||||
attachmentUniqueName);
|
||||
return false;
|
||||
}
|
||||
|
||||
attachmentUniques[attachmentUniqueAsset->attachmentType] = attachmentUniqueAsset;
|
||||
m_registration.AddDependency(attachmentUniqueAssetInfo);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ConvertAnimName(const cspField_t& field, const std::string& value)
|
||||
{
|
||||
if (ConvertString(value, field.iOffset))
|
||||
{
|
||||
if (!value.empty())
|
||||
m_registration.AddIndirectAssetReference(m_context.LoadIndirectAssetReference<AssetXAnim>(value));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public:
|
||||
InfoStringToWeaponConverter(const InfoString& infoString,
|
||||
WeaponFullDef& weaponFullDef,
|
||||
ZoneScriptStrings& zoneScriptStrings,
|
||||
MemoryManager& memory,
|
||||
AssetCreationContext& context,
|
||||
AssetRegistration<AssetWeapon>& registration,
|
||||
const cspField_t* fields,
|
||||
const size_t fieldCount)
|
||||
: InfoStringToStructConverter(infoString, &weaponFullDef, zoneScriptStrings, memory, context, registration, fields, fieldCount)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
void ConvertAccuracyGraph(
|
||||
const GenericGraph2D& graph, vec2_t*& originalGraphKnots, int& originalGraphKnotCount, vec2_t*& graphKnots, int& graphKnotCount, MemoryManager& memory)
|
||||
{
|
||||
originalGraphKnotCount = static_cast<int>(graph.knots.size());
|
||||
originalGraphKnots = memory.Alloc<vec2_t>(originalGraphKnotCount);
|
||||
|
||||
for (auto i = 0; i < originalGraphKnotCount; i++)
|
||||
{
|
||||
const auto& commonKnot = graph.knots[i];
|
||||
originalGraphKnots[i].x = static_cast<float>(commonKnot.x);
|
||||
originalGraphKnots[i].y = static_cast<float>(commonKnot.y);
|
||||
}
|
||||
|
||||
graphKnots = originalGraphKnots;
|
||||
graphKnotCount = originalGraphKnotCount;
|
||||
}
|
||||
|
||||
bool LoadAccuracyGraphs(WeaponFullDef& weaponFullDef, MemoryManager& memory, ISearchPath& searchPath, AssetCreationContext& context)
|
||||
{
|
||||
auto* accuracyGraphLoader = context.GetZoneAssetLoaderState<AccuracyGraphLoader>();
|
||||
|
||||
if (weaponFullDef.weapDef.aiVsAiAccuracyGraphName && weaponFullDef.weapDef.aiVsAiAccuracyGraphName[0])
|
||||
{
|
||||
const auto* graph = accuracyGraphLoader->LoadAiVsAiGraph(searchPath, weaponFullDef.weapDef.aiVsAiAccuracyGraphName);
|
||||
if (!graph)
|
||||
return false;
|
||||
|
||||
ConvertAccuracyGraph(*graph,
|
||||
weaponFullDef.weapDef.originalAiVsAiAccuracyGraphKnots,
|
||||
weaponFullDef.weapDef.originalAiVsAiAccuracyGraphKnotCount,
|
||||
weaponFullDef.weapDef.aiVsAiAccuracyGraphKnots,
|
||||
weaponFullDef.weapDef.aiVsAiAccuracyGraphKnotCount,
|
||||
memory);
|
||||
}
|
||||
|
||||
if (weaponFullDef.weapDef.aiVsPlayerAccuracyGraphName && weaponFullDef.weapDef.aiVsPlayerAccuracyGraphName[0])
|
||||
{
|
||||
const auto* graph = accuracyGraphLoader->LoadAiVsPlayerGraph(searchPath, weaponFullDef.weapDef.aiVsPlayerAccuracyGraphName);
|
||||
if (!graph)
|
||||
return false;
|
||||
|
||||
ConvertAccuracyGraph(*graph,
|
||||
weaponFullDef.weapDef.originalAiVsPlayerAccuracyGraphKnots,
|
||||
weaponFullDef.weapDef.originalAiVsPlayerAccuracyGraphKnotCount,
|
||||
weaponFullDef.weapDef.aiVsPlayerAccuracyGraphKnots,
|
||||
weaponFullDef.weapDef.aiVsPlayerAccuracyGraphKnotCount,
|
||||
memory);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void LinkWeaponFullDefSubStructs(WeaponFullDef& weapon)
|
||||
{
|
||||
weapon.weapVariantDef.weapDef = &weapon.weapDef;
|
||||
weapon.weapVariantDef.attachments = weapon.attachments;
|
||||
weapon.weapVariantDef.attachmentUniques = weapon.attachmentUniques;
|
||||
weapon.weapDef.gunXModel = weapon.gunXModel;
|
||||
weapon.weapVariantDef.szXAnims = weapon.szXAnims;
|
||||
weapon.weapVariantDef.hideTags = weapon.hideTags;
|
||||
weapon.weapDef.notetrackSoundMapKeys = weapon.notetrackSoundMapKeys;
|
||||
weapon.weapDef.notetrackSoundMapValues = weapon.notetrackSoundMapValues;
|
||||
weapon.weapDef.worldModel = weapon.worldModel;
|
||||
weapon.weapVariantDef.attachViewModel = weapon.attachViewModel;
|
||||
weapon.weapVariantDef.attachWorldModel = weapon.attachWorldModel;
|
||||
weapon.weapVariantDef.attachViewModelTag = weapon.attachViewModelTag;
|
||||
weapon.weapVariantDef.attachWorldModelTag = weapon.attachWorldModelTag;
|
||||
weapon.weapDef.parallelBounce = weapon.parallelBounce;
|
||||
weapon.weapDef.perpendicularBounce = weapon.perpendicularBounce;
|
||||
weapon.weapDef.locationDamageMultipliers = weapon.locationDamageMultipliers;
|
||||
}
|
||||
|
||||
void CalculateWeaponFields(WeaponFullDef& weapon)
|
||||
{
|
||||
// iAttachments
|
||||
weapon.weapVariantDef.iAttachments = 0;
|
||||
for (auto i = 1u; i < sizeof(WeaponVariantDef::iAttachments) * 8; i++) // Bit for default attachment always 0
|
||||
{
|
||||
if (weapon.attachments[i])
|
||||
weapon.weapVariantDef.iAttachments |= 1 << i;
|
||||
}
|
||||
|
||||
if (weapon.weapVariantDef.iAdsTransInTime <= 0)
|
||||
weapon.weapVariantDef.fOOPosAnimLength[0] = 0.0033333334f;
|
||||
else
|
||||
weapon.weapVariantDef.fOOPosAnimLength[0] = 1.0f / static_cast<float>(weapon.weapVariantDef.iAdsTransInTime);
|
||||
|
||||
if (weapon.weapVariantDef.iAdsTransOutTime <= 0)
|
||||
weapon.weapVariantDef.fOOPosAnimLength[1] = 0.0020000001f;
|
||||
else
|
||||
weapon.weapVariantDef.fOOPosAnimLength[1] = 1.0f / static_cast<float>(weapon.weapVariantDef.iAdsTransOutTime);
|
||||
}
|
||||
|
||||
bool IsStringOverride(const char* baseString, const char* overrideString)
|
||||
{
|
||||
if (overrideString == nullptr || overrideString[0] == '\0')
|
||||
return false;
|
||||
|
||||
if (baseString == nullptr || baseString[0] == '\0')
|
||||
return true;
|
||||
|
||||
return strcmp(baseString, overrideString) != 0;
|
||||
}
|
||||
|
||||
bool IsFxOverride(const FxEffectDef* baseEffect, const FxEffectDef* overrideEffect)
|
||||
{
|
||||
if (overrideEffect == nullptr)
|
||||
return false;
|
||||
|
||||
if (baseEffect == nullptr)
|
||||
return true;
|
||||
|
||||
return strcmp(baseEffect->name, overrideEffect->name) != 0;
|
||||
}
|
||||
|
||||
void HandleSoundOverride(WeaponAttachmentUnique& attachmentUnique, const char* snd1, const char* snd2, const eAttachmentOverrideSounds sndOverrideIndex)
|
||||
{
|
||||
if (IsStringOverride(snd1, snd2))
|
||||
attachmentUnique.soundOverrides |= 1 << static_cast<unsigned>(sndOverrideIndex);
|
||||
}
|
||||
|
||||
void HandleFxOverride(WeaponAttachmentUnique& attachmentUnique,
|
||||
const FxEffectDef* effect1,
|
||||
const FxEffectDef* effect2,
|
||||
const eAttachmentOverrideEffects fxOverrideIndex)
|
||||
{
|
||||
if (IsFxOverride(effect1, effect2))
|
||||
attachmentUnique.effectOverrides |= 1 << static_cast<unsigned>(fxOverrideIndex);
|
||||
}
|
||||
|
||||
void CalculateAttachmentFields(const WeaponFullDef& weapon, unsigned attachmentIndex, WeaponAttachmentUnique& attachmentUnique)
|
||||
{
|
||||
for (auto& val : attachmentUnique.animationOverrides)
|
||||
val = 0;
|
||||
|
||||
for (auto animIndex = 0u; animIndex < std::extent_v<decltype(WeaponFullDef::szXAnims)>; animIndex++)
|
||||
{
|
||||
if (IsStringOverride(weapon.szXAnims[animIndex], attachmentUnique.szXAnims[animIndex]))
|
||||
attachmentUnique.animationOverrides[animIndex / 32] |= 1 << (animIndex % 32);
|
||||
}
|
||||
|
||||
attachmentUnique.soundOverrides = 0;
|
||||
HandleSoundOverride(attachmentUnique, weapon.weapDef.fireSound, attachmentUnique.fireSound, ATTACHMENT_OVERRIDE_SOUND_FIRE);
|
||||
HandleSoundOverride(attachmentUnique, weapon.weapDef.fireSoundPlayer, attachmentUnique.fireSoundPlayer, ATTACHMENT_OVERRIDE_SOUND_FIRE_PLAYER);
|
||||
HandleSoundOverride(attachmentUnique, weapon.weapDef.fireLoopSound, attachmentUnique.fireLoopSound, ATTACHMENT_OVERRIDE_SOUND_FIRE_LOOP);
|
||||
HandleSoundOverride(
|
||||
attachmentUnique, weapon.weapDef.fireLoopSoundPlayer, attachmentUnique.fireLoopSoundPlayer, ATTACHMENT_OVERRIDE_SOUND_FIRE_LOOP_PLAYER);
|
||||
HandleSoundOverride(attachmentUnique, weapon.weapDef.fireLoopEndSound, attachmentUnique.fireLoopEndSound, ATTACHMENT_OVERRIDE_SOUND_FIRE_LOOP_END);
|
||||
HandleSoundOverride(
|
||||
attachmentUnique, weapon.weapDef.fireLoopEndSoundPlayer, attachmentUnique.fireLoopEndSoundPlayer, ATTACHMENT_OVERRIDE_SOUND_FIRE_LOOP_END_PLAYER);
|
||||
HandleSoundOverride(attachmentUnique, weapon.weapDef.fireStartSound, attachmentUnique.fireStartSound, ATTACHMENT_OVERRIDE_SOUND_FIRE_START);
|
||||
HandleSoundOverride(attachmentUnique, weapon.weapDef.fireStopSound, attachmentUnique.fireStopSound, ATTACHMENT_OVERRIDE_SOUND_FIRE_STOP);
|
||||
HandleSoundOverride(
|
||||
attachmentUnique, weapon.weapDef.fireStartSoundPlayer, attachmentUnique.fireStartSoundPlayer, ATTACHMENT_OVERRIDE_SOUND_FIRE_START_PLAYER);
|
||||
HandleSoundOverride(
|
||||
attachmentUnique, weapon.weapDef.fireStopSoundPlayer, attachmentUnique.fireStopSoundPlayer, ATTACHMENT_OVERRIDE_SOUND_FIRE_STOP_PLAYER);
|
||||
HandleSoundOverride(attachmentUnique, weapon.weapDef.fireLastSound, attachmentUnique.fireLastSound, ATTACHMENT_OVERRIDE_SOUND_FIRE_LAST);
|
||||
HandleSoundOverride(
|
||||
attachmentUnique, weapon.weapDef.fireLastSoundPlayer, attachmentUnique.fireLastSoundPlayer, ATTACHMENT_OVERRIDE_SOUND_FIRE_LAST_PLAYER);
|
||||
|
||||
attachmentUnique.effectOverrides = 0;
|
||||
HandleFxOverride(attachmentUnique, weapon.weapDef.viewFlashEffect, attachmentUnique.viewFlashEffect, ATTACHMENT_OVERRIDE_EFFECT_VIEW_FLASH);
|
||||
HandleFxOverride(attachmentUnique, weapon.weapDef.worldFlashEffect, attachmentUnique.worldFlashEffect, ATTACHMENT_OVERRIDE_EFFECT_WORLD_FLASH);
|
||||
|
||||
attachmentUnique.childLink = 0;
|
||||
if (attachmentUnique.combinedAttachmentTypeMask == 0)
|
||||
{
|
||||
WeaponAttachmentUnique* lastSibling = nullptr;
|
||||
for (auto attachmentUniqueIndex = std::extent_v<decltype(WeaponFullDef::attachments)>;
|
||||
attachmentUniqueIndex < std::extent_v<decltype(WeaponFullDef::attachmentUniques)>;
|
||||
attachmentUniqueIndex++)
|
||||
{
|
||||
if (weapon.attachmentUniques[attachmentUniqueIndex] != nullptr
|
||||
&& weapon.attachmentUniques[attachmentUniqueIndex]->combinedAttachmentTypeMask
|
||||
& (1 << static_cast<unsigned>(attachmentUnique.attachmentType))
|
||||
&& weapon.attachmentUniques[attachmentUniqueIndex]->attachmentType != attachmentUnique.attachmentType)
|
||||
{
|
||||
std::vector<eAttachment> attachments;
|
||||
if (InfoStringLoaderAttachmentUnique::ExtractAttachmentsFromAssetName(weapon.attachmentUniques[attachmentUniqueIndex]->szInternalName,
|
||||
attachments)
|
||||
&& attachments.front() == attachmentUnique.attachmentType)
|
||||
{
|
||||
if (lastSibling == nullptr)
|
||||
{
|
||||
attachmentUnique.childLink = attachmentUniqueIndex;
|
||||
lastSibling = weapon.attachmentUniques[attachmentUniqueIndex];
|
||||
}
|
||||
else
|
||||
{
|
||||
lastSibling->siblingLink = attachmentUniqueIndex;
|
||||
lastSibling = weapon.attachmentUniques[attachmentUniqueIndex];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CalculateAttachmentFields(const WeaponFullDef& weapon)
|
||||
{
|
||||
for (auto attachmentUniqueIndex = 0u; attachmentUniqueIndex < std::extent_v<decltype(WeaponFullDef::attachmentUniques)>; attachmentUniqueIndex++)
|
||||
{
|
||||
if (weapon.attachmentUniques[attachmentUniqueIndex] == nullptr)
|
||||
continue;
|
||||
|
||||
CalculateAttachmentFields(weapon, attachmentUniqueIndex, *weapon.attachmentUniques[attachmentUniqueIndex]);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
InfoStringLoaderWeapon::InfoStringLoaderWeapon(MemoryManager& memory, ISearchPath& searchPath, Zone& zone)
|
||||
: m_memory(memory),
|
||||
m_search_path(searchPath),
|
||||
m_zone(zone)
|
||||
{
|
||||
}
|
||||
|
||||
AssetCreationResult InfoStringLoaderWeapon::CreateAsset(const std::string& assetName, const InfoString& infoString, AssetCreationContext& context)
|
||||
{
|
||||
auto* weaponFullDef = m_memory.Alloc<WeaponFullDef>();
|
||||
weaponFullDef->weapVariantDef.szInternalName = m_memory.Dup(assetName.c_str());
|
||||
|
||||
LinkWeaponFullDefSubStructs(*weaponFullDef);
|
||||
|
||||
AssetRegistration<AssetWeapon> registration(assetName, &weaponFullDef->weapVariantDef);
|
||||
|
||||
InfoStringToWeaponConverter converter(
|
||||
infoString, *weaponFullDef, m_zone.m_script_strings, m_memory, context, registration, weapon_fields, std::extent_v<decltype(weapon_fields)>);
|
||||
if (!converter.Convert())
|
||||
{
|
||||
std::cerr << std::format("Failed to parse weapon: \"{}\"\n", assetName);
|
||||
return AssetCreationResult::Failure();
|
||||
}
|
||||
|
||||
CalculateWeaponFields(*weaponFullDef);
|
||||
CalculateAttachmentFields(*weaponFullDef);
|
||||
|
||||
LoadAccuracyGraphs(*weaponFullDef, m_memory, m_search_path, context);
|
||||
|
||||
return AssetCreationResult::Success(context.AddAsset(std::move(registration)));
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include "Asset/AssetCreationContext.h"
|
||||
#include "Asset/AssetCreationResult.h"
|
||||
#include "InfoString/InfoString.h"
|
||||
|
||||
namespace T6
|
||||
{
|
||||
class InfoStringLoaderWeapon
|
||||
{
|
||||
public:
|
||||
InfoStringLoaderWeapon(MemoryManager& memory, ISearchPath& searchPath, Zone& zone);
|
||||
|
||||
AssetCreationResult CreateAsset(const std::string& assetName, const InfoString& infoString, AssetCreationContext& context);
|
||||
|
||||
private:
|
||||
MemoryManager& m_memory;
|
||||
ISearchPath& m_search_path;
|
||||
Zone& m_zone;
|
||||
};
|
||||
} // namespace T6
|
||||
@@ -0,0 +1,251 @@
|
||||
#include "JsonWeaponCamoLoaderT6.h"
|
||||
|
||||
#include "Game/T6/CommonT6.h"
|
||||
#include "Game/T6/Json/JsonWeaponCamo.h"
|
||||
|
||||
#include <format>
|
||||
#include <iostream>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using namespace nlohmann;
|
||||
using namespace T6;
|
||||
|
||||
namespace
|
||||
{
|
||||
class JsonLoader
|
||||
{
|
||||
public:
|
||||
JsonLoader(std::istream& stream, MemoryManager& memory, AssetCreationContext& context, AssetRegistration<AssetWeaponCamo>& registration)
|
||||
: m_stream(stream),
|
||||
m_memory(memory),
|
||||
m_context(context),
|
||||
m_registration(registration)
|
||||
|
||||
{
|
||||
}
|
||||
|
||||
bool Load(WeaponCamo& weaponCamo) const
|
||||
{
|
||||
const auto jRoot = json::parse(m_stream);
|
||||
std::string type;
|
||||
unsigned version;
|
||||
|
||||
jRoot.at("_type").get_to(type);
|
||||
jRoot.at("_version").get_to(version);
|
||||
|
||||
if (type != "weaponCamo" || version != 1u)
|
||||
{
|
||||
std::cerr << std::format("Tried to load weapon camo \"{}\" but did not find expected type weaponCamo of version {}\n", weaponCamo.name, 1u);
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
const auto jWeaponCamo = jRoot.get<JsonWeaponCamo>();
|
||||
return CreateWeaponCamoFromJson(jWeaponCamo, weaponCamo);
|
||||
}
|
||||
catch (const json::exception& e)
|
||||
{
|
||||
std::cerr << std::format("Failed to parse json of weapon camo: {}\n", e.what());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
static void PrintError(const WeaponCamo& weaponCamo, const std::string& message)
|
||||
{
|
||||
std::cerr << "Cannot load weapon camo \"" << weaponCamo.name << "\": " << message << "\n";
|
||||
}
|
||||
|
||||
bool CreateWeaponCamoSetFromJson(const JsonWeaponCamoSet& jWeaponCamoSet, WeaponCamoSet& weaponCamoSet, const WeaponCamo& weaponCamo) const
|
||||
{
|
||||
if (jWeaponCamoSet.solidCamoImage)
|
||||
{
|
||||
auto* image = m_context.LoadDependency<AssetImage>(jWeaponCamoSet.solidCamoImage.value());
|
||||
if (!image)
|
||||
{
|
||||
PrintError(weaponCamo, "Could not find solidCamoImage");
|
||||
return false;
|
||||
}
|
||||
m_registration.AddDependency(image);
|
||||
weaponCamoSet.solidCamoImage = image->Asset();
|
||||
}
|
||||
|
||||
if (jWeaponCamoSet.patternCamoImage)
|
||||
{
|
||||
auto* image = m_context.LoadDependency<AssetImage>(jWeaponCamoSet.patternCamoImage.value());
|
||||
if (!image)
|
||||
{
|
||||
PrintError(weaponCamo, "Could not find patternCamoImage");
|
||||
return false;
|
||||
}
|
||||
m_registration.AddDependency(image);
|
||||
weaponCamoSet.patternCamoImage = image->Asset();
|
||||
}
|
||||
|
||||
weaponCamoSet.patternOffset.x = jWeaponCamoSet.patternOffset.x;
|
||||
weaponCamoSet.patternOffset.y = jWeaponCamoSet.patternOffset.y;
|
||||
weaponCamoSet.patternScale = jWeaponCamoSet.patternScale;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CreateWeaponCamoMaterialFromJson(const JsonWeaponCamoMaterial& jWeaponCamoMaterial,
|
||||
WeaponCamoMaterial& weaponCamoMaterial,
|
||||
const WeaponCamo& weaponCamo) const
|
||||
{
|
||||
if (jWeaponCamoMaterial.useColorMap)
|
||||
weaponCamoMaterial.replaceFlags |= WCM_REPLACE_COLOR;
|
||||
if (jWeaponCamoMaterial.useNormalMap)
|
||||
weaponCamoMaterial.replaceFlags |= WCM_REPLACE_NORMAL;
|
||||
if (jWeaponCamoMaterial.useSpecularMap)
|
||||
weaponCamoMaterial.replaceFlags |= WCM_REPLACE_SPECULAR;
|
||||
|
||||
weaponCamoMaterial.numBaseMaterials = static_cast<uint16_t>(jWeaponCamoMaterial.materialOverrides.size());
|
||||
if (!jWeaponCamoMaterial.materialOverrides.empty())
|
||||
{
|
||||
weaponCamoMaterial.baseMaterials = m_memory.Alloc<Material*>(weaponCamoMaterial.numBaseMaterials);
|
||||
weaponCamoMaterial.camoMaterials = m_memory.Alloc<Material*>(weaponCamoMaterial.numBaseMaterials);
|
||||
|
||||
for (auto i = 0u; i < weaponCamoMaterial.numBaseMaterials; i++)
|
||||
{
|
||||
const auto& materialOverride = jWeaponCamoMaterial.materialOverrides[i];
|
||||
auto* baseMaterial = m_context.LoadDependency<AssetMaterial>(materialOverride.baseMaterial);
|
||||
auto* camoMaterial = m_context.LoadDependency<AssetMaterial>(materialOverride.camoMaterial);
|
||||
|
||||
if (!baseMaterial)
|
||||
{
|
||||
PrintError(weaponCamo, "Could not find baseMaterial");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!camoMaterial)
|
||||
{
|
||||
PrintError(weaponCamo, "Could not find camoMaterial");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_registration.AddDependency(baseMaterial);
|
||||
m_registration.AddDependency(camoMaterial);
|
||||
|
||||
weaponCamoMaterial.baseMaterials[i] = baseMaterial->Asset();
|
||||
weaponCamoMaterial.camoMaterials[i] = camoMaterial->Asset();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
weaponCamoMaterial.baseMaterials = nullptr;
|
||||
weaponCamoMaterial.camoMaterials = nullptr;
|
||||
}
|
||||
|
||||
for (auto i = 0u; i < std::extent_v<decltype(WeaponCamoMaterial::shaderConsts)>; i++)
|
||||
weaponCamoMaterial.shaderConsts[i] = jWeaponCamoMaterial.shaderConsts[i];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CreateWeaponCamoMaterialSetFromJson(const JsonWeaponCamoMaterialSet& jWeaponCamoMaterialSet,
|
||||
WeaponCamoMaterialSet& weaponCamoMaterialSet,
|
||||
const WeaponCamo& weaponCamo) const
|
||||
{
|
||||
if (!jWeaponCamoMaterialSet.materials.empty())
|
||||
{
|
||||
weaponCamoMaterialSet.numMaterials = jWeaponCamoMaterialSet.materials.size();
|
||||
weaponCamoMaterialSet.materials = m_memory.Alloc<WeaponCamoMaterial>(weaponCamoMaterialSet.numMaterials);
|
||||
|
||||
for (auto i = 0u; i < weaponCamoMaterialSet.numMaterials; i++)
|
||||
{
|
||||
if (!CreateWeaponCamoMaterialFromJson(jWeaponCamoMaterialSet.materials[i], weaponCamoMaterialSet.materials[i], weaponCamo))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
weaponCamoMaterialSet.numMaterials = 0;
|
||||
weaponCamoMaterialSet.materials = nullptr;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CreateWeaponCamoFromJson(const JsonWeaponCamo& jWeaponCamo, WeaponCamo& weaponCamo) const
|
||||
{
|
||||
if (jWeaponCamo.solidBaseImage)
|
||||
{
|
||||
auto* image = m_context.LoadDependency<AssetImage>(jWeaponCamo.solidBaseImage.value());
|
||||
if (!image)
|
||||
{
|
||||
PrintError(weaponCamo, "Could not find solidBaseImage");
|
||||
return false;
|
||||
}
|
||||
m_registration.AddDependency(image);
|
||||
weaponCamo.solidBaseImage = image->Asset();
|
||||
}
|
||||
|
||||
if (jWeaponCamo.patternBaseImage)
|
||||
{
|
||||
auto* image = m_context.LoadDependency<AssetImage>(jWeaponCamo.patternBaseImage.value());
|
||||
if (!image)
|
||||
{
|
||||
PrintError(weaponCamo, "Could not find patternBaseImage");
|
||||
return false;
|
||||
}
|
||||
m_registration.AddDependency(image);
|
||||
weaponCamo.patternBaseImage = image->Asset();
|
||||
}
|
||||
|
||||
if (!jWeaponCamo.camoSets.empty())
|
||||
{
|
||||
weaponCamo.numCamoSets = jWeaponCamo.camoSets.size();
|
||||
weaponCamo.camoSets = m_memory.Alloc<WeaponCamoSet>(weaponCamo.numCamoSets);
|
||||
|
||||
for (auto i = 0u; i < weaponCamo.numCamoSets; i++)
|
||||
{
|
||||
if (!CreateWeaponCamoSetFromJson(jWeaponCamo.camoSets[i], weaponCamo.camoSets[i], weaponCamo))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
weaponCamo.numCamoSets = 0;
|
||||
weaponCamo.camoSets = nullptr;
|
||||
}
|
||||
|
||||
if (!jWeaponCamo.camoMaterials.empty())
|
||||
{
|
||||
weaponCamo.numCamoMaterials = jWeaponCamo.camoMaterials.size();
|
||||
weaponCamo.camoMaterials = m_memory.Alloc<WeaponCamoMaterialSet>(weaponCamo.numCamoMaterials);
|
||||
|
||||
for (auto i = 0u; i < weaponCamo.numCamoMaterials; i++)
|
||||
{
|
||||
if (!CreateWeaponCamoMaterialSetFromJson(jWeaponCamo.camoMaterials[i], weaponCamo.camoMaterials[i], weaponCamo))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
weaponCamo.numCamoMaterials = 0;
|
||||
weaponCamo.camoMaterials = nullptr;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::istream& m_stream;
|
||||
MemoryManager& m_memory;
|
||||
AssetCreationContext& m_context;
|
||||
AssetRegistration<AssetWeaponCamo>& m_registration;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
namespace T6
|
||||
{
|
||||
bool LoadWeaponCamoAsJson(
|
||||
std::istream& stream, WeaponCamo& weaponCamo, MemoryManager& memory, AssetCreationContext& context, AssetRegistration<AssetWeaponCamo>& registration)
|
||||
{
|
||||
const JsonLoader loader(stream, memory, context, registration);
|
||||
|
||||
return loader.Load(weaponCamo);
|
||||
}
|
||||
} // namespace T6
|
||||
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "Asset/AssetCreationContext.h"
|
||||
#include "Asset/AssetRegistration.h"
|
||||
#include "Game/T6/T6.h"
|
||||
#include "Utils/MemoryManager.h"
|
||||
|
||||
#include <istream>
|
||||
|
||||
namespace T6
|
||||
{
|
||||
bool LoadWeaponCamoAsJson(
|
||||
std::istream& stream, WeaponCamo& weaponCamo, MemoryManager& memory, AssetCreationContext& context, AssetRegistration<AssetWeaponCamo>& registration);
|
||||
} // namespace T6
|
||||
@@ -0,0 +1,55 @@
|
||||
#include "LoaderWeaponCamoT6.h"
|
||||
|
||||
#include "Game/T6/T6.h"
|
||||
#include "JsonWeaponCamoLoaderT6.h"
|
||||
#include "Pool/GlobalAssetPool.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <format>
|
||||
#include <iostream>
|
||||
|
||||
using namespace T6;
|
||||
|
||||
namespace
|
||||
{
|
||||
class WeaponCamoLoader final : public AssetCreator<AssetWeaponCamo>
|
||||
{
|
||||
public:
|
||||
WeaponCamoLoader(MemoryManager& memory, ISearchPath& searchPath)
|
||||
: m_memory(memory),
|
||||
m_search_path(searchPath)
|
||||
{
|
||||
}
|
||||
|
||||
AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override
|
||||
{
|
||||
const auto file = m_search_path.Open(std::format("camo/{}.json", assetName));
|
||||
if (!file.IsOpen())
|
||||
return AssetCreationResult::NoAction();
|
||||
|
||||
auto* weaponCamo = m_memory.Alloc<WeaponCamo>();
|
||||
weaponCamo->name = m_memory.Dup(assetName.c_str());
|
||||
|
||||
AssetRegistration<AssetWeaponCamo> registration(assetName, weaponCamo);
|
||||
if (!LoadWeaponCamoAsJson(*file.m_stream, *weaponCamo, m_memory, context, registration))
|
||||
{
|
||||
std::cerr << std::format("Failed to load weapon camo \"{}\"\n", assetName);
|
||||
return AssetCreationResult::Failure();
|
||||
}
|
||||
|
||||
return AssetCreationResult::Success(context.AddAsset(std::move(registration)));
|
||||
}
|
||||
|
||||
private:
|
||||
MemoryManager& m_memory;
|
||||
ISearchPath& m_search_path;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
namespace T6
|
||||
{
|
||||
std::unique_ptr<AssetCreator<AssetWeaponCamo>> CreateWeaponCamoLoader(MemoryManager& memory, ISearchPath& searchPath)
|
||||
{
|
||||
return std::make_unique<WeaponCamoLoader>(memory, searchPath);
|
||||
}
|
||||
} // namespace T6
|
||||
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "Asset/IAssetCreator.h"
|
||||
#include "Game/T6/T6.h"
|
||||
#include "SearchPath/ISearchPath.h"
|
||||
#include "Utils/MemoryManager.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace T6
|
||||
{
|
||||
std::unique_ptr<AssetCreator<AssetWeaponCamo>> CreateWeaponCamoLoader(MemoryManager& memory, ISearchPath& searchPath);
|
||||
} // namespace T6
|
||||
@@ -0,0 +1,54 @@
|
||||
#include "RawLoaderAttachmentT6.h"
|
||||
|
||||
#include "Game/T6/ObjConstantsT6.h"
|
||||
#include "Game/T6/T6.h"
|
||||
#include "InfoString/InfoString.h"
|
||||
#include "InfoStringLoaderAttachmentT6.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <format>
|
||||
#include <iostream>
|
||||
|
||||
using namespace T6;
|
||||
|
||||
namespace
|
||||
{
|
||||
class RawLoaderAttachment final : public AssetCreator<AssetAttachment>
|
||||
{
|
||||
public:
|
||||
RawLoaderAttachment(MemoryManager& memory, ISearchPath& searchPath, Zone& zone)
|
||||
: m_search_path(searchPath),
|
||||
m_info_string_loader(memory, searchPath, zone)
|
||||
{
|
||||
}
|
||||
|
||||
AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override
|
||||
{
|
||||
const auto fileName = std::format("attachment/{}", assetName);
|
||||
const auto file = m_search_path.Open(fileName);
|
||||
if (!file.IsOpen())
|
||||
return AssetCreationResult::NoAction();
|
||||
|
||||
InfoString infoString;
|
||||
if (!infoString.FromStream(ObjConstants::INFO_STRING_PREFIX_WEAPON_ATTACHMENT, *file.m_stream))
|
||||
{
|
||||
std::cerr << std::format("Could not parse as info string file: \"{}\"\n", fileName);
|
||||
return AssetCreationResult::Failure();
|
||||
}
|
||||
|
||||
return m_info_string_loader.CreateAsset(assetName, infoString, context);
|
||||
}
|
||||
|
||||
private:
|
||||
ISearchPath& m_search_path;
|
||||
InfoStringLoaderAttachment m_info_string_loader;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
namespace T6
|
||||
{
|
||||
std::unique_ptr<AssetCreator<AssetAttachment>> CreateRawAttachmentLoader(MemoryManager& memory, ISearchPath& searchPath, Zone& zone)
|
||||
{
|
||||
return std::make_unique<RawLoaderAttachment>(memory, searchPath, zone);
|
||||
}
|
||||
} // namespace T6
|
||||
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "Asset/IAssetCreator.h"
|
||||
#include "Game/T6/T6.h"
|
||||
#include "SearchPath/ISearchPath.h"
|
||||
#include "Utils/MemoryManager.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace T6
|
||||
{
|
||||
std::unique_ptr<AssetCreator<AssetAttachment>> CreateRawAttachmentLoader(MemoryManager& memory, ISearchPath& searchPath, Zone& zone);
|
||||
} // namespace T6
|
||||
@@ -0,0 +1,54 @@
|
||||
#include "RawLoaderAttachmentUniqueT6.h"
|
||||
|
||||
#include "Game/T6/ObjConstantsT6.h"
|
||||
#include "Game/T6/T6.h"
|
||||
#include "InfoString/InfoString.h"
|
||||
#include "InfoStringLoaderAttachmentUniqueT6.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <format>
|
||||
#include <iostream>
|
||||
|
||||
using namespace T6;
|
||||
|
||||
namespace
|
||||
{
|
||||
class RawLoaderAttachmentUnique final : public AssetCreator<AssetAttachmentUnique>
|
||||
{
|
||||
public:
|
||||
RawLoaderAttachmentUnique(MemoryManager& memory, ISearchPath& searchPath, Zone& zone)
|
||||
: m_search_path(searchPath),
|
||||
m_info_string_loader(memory, searchPath, zone)
|
||||
{
|
||||
}
|
||||
|
||||
AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override
|
||||
{
|
||||
const auto fileName = std::format("attachmentunique/{}", assetName);
|
||||
const auto file = m_search_path.Open(fileName);
|
||||
if (!file.IsOpen())
|
||||
return AssetCreationResult::NoAction();
|
||||
|
||||
InfoString infoString;
|
||||
if (!infoString.FromStream(ObjConstants::INFO_STRING_PREFIX_WEAPON_ATTACHMENT_UNIQUE, *file.m_stream))
|
||||
{
|
||||
std::cerr << std::format("Could not parse as info string file: \"{}\"\n", fileName);
|
||||
return AssetCreationResult::Failure();
|
||||
}
|
||||
|
||||
return m_info_string_loader.CreateAsset(assetName, infoString, context);
|
||||
}
|
||||
|
||||
private:
|
||||
ISearchPath& m_search_path;
|
||||
InfoStringLoaderAttachmentUnique m_info_string_loader;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
namespace T6
|
||||
{
|
||||
std::unique_ptr<AssetCreator<AssetAttachmentUnique>> CreateRawAttachmentUniqueLoader(MemoryManager& memory, ISearchPath& searchPath, Zone& zone)
|
||||
{
|
||||
return std::make_unique<RawLoaderAttachmentUnique>(memory, searchPath, zone);
|
||||
}
|
||||
} // namespace T6
|
||||
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "Asset/IAssetCreator.h"
|
||||
#include "Game/T6/T6.h"
|
||||
#include "SearchPath/ISearchPath.h"
|
||||
#include "Utils/MemoryManager.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace T6
|
||||
{
|
||||
std::unique_ptr<AssetCreator<AssetAttachmentUnique>> CreateRawAttachmentUniqueLoader(MemoryManager& memory, ISearchPath& searchPath, Zone& zone);
|
||||
} // namespace T6
|
||||
@@ -0,0 +1,54 @@
|
||||
#include "RawLoaderWeaponT6.h"
|
||||
|
||||
#include "Game/T6/ObjConstantsT6.h"
|
||||
#include "Game/T6/T6.h"
|
||||
#include "InfoString/InfoString.h"
|
||||
#include "InfoStringLoaderWeaponT6.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <format>
|
||||
#include <iostream>
|
||||
|
||||
using namespace T6;
|
||||
|
||||
namespace
|
||||
{
|
||||
class RawLoaderWeapon final : public AssetCreator<AssetWeapon>
|
||||
{
|
||||
public:
|
||||
RawLoaderWeapon(MemoryManager& memory, ISearchPath& searchPath, Zone& zone)
|
||||
: m_search_path(searchPath),
|
||||
m_info_string_loader(memory, searchPath, zone)
|
||||
{
|
||||
}
|
||||
|
||||
AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override
|
||||
{
|
||||
const auto fileName = std::format("weapons/{}", assetName);
|
||||
const auto file = m_search_path.Open(fileName);
|
||||
if (!file.IsOpen())
|
||||
return AssetCreationResult::NoAction();
|
||||
|
||||
InfoString infoString;
|
||||
if (!infoString.FromStream(ObjConstants::INFO_STRING_PREFIX_WEAPON, *file.m_stream))
|
||||
{
|
||||
std::cerr << std::format("Could not parse as info string file: \"{}\"\n", fileName);
|
||||
return AssetCreationResult::Failure();
|
||||
}
|
||||
|
||||
return m_info_string_loader.CreateAsset(assetName, infoString, context);
|
||||
}
|
||||
|
||||
private:
|
||||
ISearchPath& m_search_path;
|
||||
InfoStringLoaderWeapon m_info_string_loader;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
namespace T6
|
||||
{
|
||||
std::unique_ptr<AssetCreator<AssetWeapon>> CreateRawWeaponLoader(MemoryManager& memory, ISearchPath& searchPath, Zone& zone)
|
||||
{
|
||||
return std::make_unique<RawLoaderWeapon>(memory, searchPath, zone);
|
||||
}
|
||||
} // namespace T6
|
||||
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "Asset/IAssetCreator.h"
|
||||
#include "Game/T6/T6.h"
|
||||
#include "SearchPath/ISearchPath.h"
|
||||
#include "Utils/MemoryManager.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace T6
|
||||
{
|
||||
std::unique_ptr<AssetCreator<AssetWeapon>> CreateRawWeaponLoader(MemoryManager& memory, ISearchPath& searchPath, Zone& zone);
|
||||
} // namespace T6
|
||||
Reference in New Issue
Block a user