2020-04-23 22:05:43 +00:00
|
|
|
#include "AngelScriptResolver.hpp"
|
2020-02-16 15:43:37 +00:00
|
|
|
#include <CreatureLib/Battling/Models/Creature.hpp>
|
2020-04-10 12:57:20 +00:00
|
|
|
#include <regex>
|
2021-03-27 21:39:25 +00:00
|
|
|
#include "../../../extern/angelscript_addons/scriptdictionary/scriptdictionary.h"
|
2020-02-04 18:34:30 +00:00
|
|
|
#include "../../../extern/angelscript_addons/scripthandle/scripthandle.h"
|
2020-02-02 11:23:50 +00:00
|
|
|
#include "../../../extern/angelscript_addons/scripthelper/scripthelper.h"
|
|
|
|
#include "../../../extern/angelscript_addons/scriptstdstring/scriptstdstring.h"
|
2020-04-18 14:04:48 +00:00
|
|
|
#include "../../Battling/PkmnScriptCategory.hpp"
|
2020-06-02 19:52:34 +00:00
|
|
|
#include "../../Battling/Pokemon/Pokemon.hpp"
|
2020-04-11 12:42:49 +00:00
|
|
|
#include "ByteCodeHandling/FileByteCodeStream.hpp"
|
|
|
|
#include "ByteCodeHandling/MemoryByteCodeStream.hpp"
|
2020-02-04 18:34:30 +00:00
|
|
|
#include "TypeRegistry/BasicScriptClass.hpp"
|
2020-02-16 15:43:37 +00:00
|
|
|
#include "TypeRegistry/Battling/RegisterBattleClass.hpp"
|
|
|
|
#include "TypeRegistry/Battling/RegisterBattleLibrary.hpp"
|
2020-01-26 14:18:04 +00:00
|
|
|
#include "TypeRegistry/Battling/RegisterExecutingAttack.hpp"
|
2021-05-08 10:12:36 +00:00
|
|
|
#include "TypeRegistry/Battling/RegisterParty.hpp"
|
2020-01-26 14:18:04 +00:00
|
|
|
#include "TypeRegistry/Battling/RegisterPokemonClass.hpp"
|
2020-02-16 15:43:37 +00:00
|
|
|
#include "TypeRegistry/Battling/RegisterTurnChoices.hpp"
|
2020-04-06 18:03:44 +00:00
|
|
|
#include "TypeRegistry/ConstString.hpp"
|
2020-06-02 19:52:34 +00:00
|
|
|
#include "TypeRegistry/HelperFile.hpp"
|
2020-04-10 18:39:11 +00:00
|
|
|
#include "TypeRegistry/Library/RegisterEffectParameter.hpp"
|
2020-01-13 18:52:32 +00:00
|
|
|
#include "TypeRegistry/Library/RegisterGrowthRateTypes.hpp"
|
|
|
|
#include "TypeRegistry/Library/RegisterItemTypes.hpp"
|
|
|
|
#include "TypeRegistry/Library/RegisterMoveTypes.hpp"
|
2020-01-13 19:05:03 +00:00
|
|
|
#include "TypeRegistry/Library/RegisterSpeciesTypes.hpp"
|
2020-01-23 14:10:08 +00:00
|
|
|
#include "TypeRegistry/Library/RegisterStaticLibraryTypes.hpp"
|
2020-01-13 19:16:23 +00:00
|
|
|
#include "TypeRegistry/Library/RegisterTypeLibrary.hpp"
|
2020-01-11 21:30:23 +00:00
|
|
|
|
2020-01-13 18:43:34 +00:00
|
|
|
CreatureLib::Battling::ScriptResolver* PkmnLib::Battling::BattleLibrary::CreateScriptResolver() {
|
2020-04-23 22:05:43 +00:00
|
|
|
return new AngelScriptResolver();
|
2020-01-11 21:30:23 +00:00
|
|
|
}
|
2020-01-12 17:20:59 +00:00
|
|
|
|
2020-04-11 12:42:49 +00:00
|
|
|
static void TranslateException(asIScriptContext* ctx, void* /*userParam*/) {
|
|
|
|
try {
|
2020-04-10 18:39:11 +00:00
|
|
|
// Retrow the original exception so we can catch it again
|
|
|
|
throw;
|
2021-03-27 21:19:18 +00:00
|
|
|
} catch (ArbUt::Exception& e) {
|
|
|
|
// Tell the VM the type of exception that occurred
|
|
|
|
ctx->SetException(e.what());
|
2021-03-27 21:39:25 +00:00
|
|
|
} catch (std::exception& e) {
|
2020-04-10 18:39:11 +00:00
|
|
|
// Tell the VM the type of exception that occurred
|
|
|
|
ctx->SetException(e.what());
|
2020-04-11 12:42:49 +00:00
|
|
|
} catch (...) {
|
2020-04-10 18:39:11 +00:00
|
|
|
// The callback must not allow any exception to be thrown, but it is not necessary
|
|
|
|
// to explicitly set an exception string if the default exception string is sufficient
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-19 13:57:20 +00:00
|
|
|
void AngelScriptResolver::Initialize(CreatureLib::Battling::BattleLibrary* arg, bool includeStandard) {
|
2020-04-10 12:57:20 +00:00
|
|
|
for (auto scriptCategory : ScriptCategoryHelper::GetValues()) {
|
|
|
|
_typeDatabase.Insert(scriptCategory, {});
|
|
|
|
}
|
2020-04-18 14:04:48 +00:00
|
|
|
for (auto scriptCategory : PkmnScriptCategoryHelper::GetValues()) {
|
|
|
|
_typeDatabase.Insert(static_cast<ScriptCategory>(scriptCategory), {});
|
|
|
|
}
|
2020-04-10 12:57:20 +00:00
|
|
|
|
2020-02-04 18:34:30 +00:00
|
|
|
auto library = (PkmnLib::Battling::BattleLibrary*)arg;
|
2020-01-11 21:30:23 +00:00
|
|
|
_engine = asCreateScriptEngine();
|
2020-04-10 18:39:11 +00:00
|
|
|
_engine->SetTranslateAppExceptionCallback(asFUNCTION(TranslateException), 0, asCALL_CDECL);
|
2020-01-11 21:30:23 +00:00
|
|
|
|
2020-01-26 14:18:04 +00:00
|
|
|
int32_t r = _engine->SetMessageCallback(asFUNCTION(MessageCallback), nullptr, asCALL_CDECL);
|
|
|
|
if (r < 0)
|
2020-08-16 09:12:04 +00:00
|
|
|
throw ArbUt::Exception("Registering message callback failed.");
|
2020-01-26 14:18:04 +00:00
|
|
|
|
2020-01-11 21:30:23 +00:00
|
|
|
_engine->SetEngineProperty(asEP_DISALLOW_EMPTY_LIST_ELEMENTS, true);
|
2020-02-04 18:34:30 +00:00
|
|
|
_engine->SetEngineProperty(asEP_DISALLOW_VALUE_ASSIGN_FOR_REF_TYPE, false);
|
|
|
|
_engine->SetEngineProperty(asEP_ALLOW_UNSAFE_REFERENCES, true);
|
2020-01-11 21:30:23 +00:00
|
|
|
_engine->SetEngineProperty(asEP_ALWAYS_IMPL_DEFAULT_CONSTRUCT, true);
|
|
|
|
_engine->SetEngineProperty(asEP_AUTO_GARBAGE_COLLECT, false);
|
2020-01-18 12:07:56 +00:00
|
|
|
_engine->SetEngineProperty(asEP_REQUIRE_ENUM_SCOPE, true);
|
2020-02-04 18:34:30 +00:00
|
|
|
_engine->SetEngineProperty(asEP_PROPERTY_ACCESSOR_MODE, 2);
|
2020-02-16 15:43:37 +00:00
|
|
|
_engine->SetEngineProperty(asEP_COMPILER_WARNINGS, 2);
|
2020-01-11 21:30:23 +00:00
|
|
|
|
2020-12-11 13:08:13 +00:00
|
|
|
if (includeStandard) {
|
2020-09-19 13:57:20 +00:00
|
|
|
RegisterStdString(_engine);
|
|
|
|
ConstStringRegister::Register(_engine);
|
2020-01-26 14:18:04 +00:00
|
|
|
|
2020-09-19 13:57:20 +00:00
|
|
|
// Register Script Array type
|
|
|
|
RegisterScriptArray(_engine, true);
|
|
|
|
RegisterScriptHandle(_engine);
|
2021-03-27 21:39:25 +00:00
|
|
|
RegisterScriptDictionary(_engine);
|
2020-09-29 15:51:11 +00:00
|
|
|
r = _engine->RegisterGlobalFunction("void print(const string &in)", asFUNCTION(Print), asCALL_CDECL);
|
|
|
|
if (r < 0)
|
|
|
|
throw ArbUt::Exception("Registering print function failed.");
|
2021-03-28 15:15:06 +00:00
|
|
|
r = _engine->RegisterGlobalFunction("void print(const constString &in)", asFUNCTION(PrintConst), asCALL_CDECL);
|
|
|
|
if (r < 0)
|
|
|
|
throw ArbUt::Exception("Registering print function failed.");
|
2020-09-19 13:57:20 +00:00
|
|
|
}
|
2020-01-26 14:18:04 +00:00
|
|
|
|
2020-02-19 08:07:44 +00:00
|
|
|
_builder.StartNewModule(_engine, "pkmn");
|
|
|
|
_mainModule = _builder.GetModule();
|
2020-01-11 21:30:23 +00:00
|
|
|
|
2020-01-26 14:18:04 +00:00
|
|
|
RegisterTypes();
|
2020-01-11 21:30:23 +00:00
|
|
|
RegisterExceptionRoutines(_engine);
|
|
|
|
|
2020-12-11 13:08:13 +00:00
|
|
|
if (library != nullptr) {
|
2020-09-19 11:33:17 +00:00
|
|
|
auto& staticLib = library->GetStaticLib();
|
|
|
|
_engine->RegisterGlobalProperty("const StaticLibrary@ StaticLib", (void*)staticLib.get());
|
|
|
|
}
|
2020-01-26 14:18:04 +00:00
|
|
|
|
|
|
|
_contextPool = new ContextPool(_engine);
|
2021-04-17 11:50:43 +00:00
|
|
|
|
|
|
|
asPrepareMultithread();
|
2020-01-26 14:18:04 +00:00
|
|
|
}
|
|
|
|
|
2020-04-23 22:05:43 +00:00
|
|
|
void AngelScriptResolver::RegisterTypes() {
|
2020-01-26 14:18:04 +00:00
|
|
|
// Register static library types
|
2020-01-13 19:05:03 +00:00
|
|
|
RegisterSpeciesTypes::Register(_engine);
|
2020-01-13 18:21:41 +00:00
|
|
|
RegisterItemTypes::Register(_engine);
|
2020-01-13 18:43:34 +00:00
|
|
|
RegisterMoveTypes::Register(_engine);
|
2020-01-13 18:52:32 +00:00
|
|
|
RegisterGrowthRateTypes::Register(_engine);
|
2020-01-13 19:16:23 +00:00
|
|
|
RegisterTypeLibrary::Register(_engine);
|
2020-01-23 14:10:08 +00:00
|
|
|
RegisterStaticLibraryTypes::Register(_engine);
|
2020-04-10 18:39:11 +00:00
|
|
|
RegisterEffectParameter::Register(_engine);
|
2020-01-11 21:30:23 +00:00
|
|
|
|
2020-01-26 14:18:04 +00:00
|
|
|
// Register battle types
|
2021-03-26 22:05:51 +00:00
|
|
|
// Predeclare these two types, and declare their implementation later.
|
|
|
|
[[maybe_unused]] int r = _engine->RegisterObjectType("Battle", 0, asOBJ_REF | asOBJ_NOCOUNT);
|
|
|
|
Ensure(r >= 0);
|
|
|
|
r = _engine->RegisterObjectType("BattleSide", 0, asOBJ_REF | asOBJ_NOCOUNT);
|
|
|
|
Ensure(r >= 0);
|
|
|
|
|
2020-01-26 14:18:04 +00:00
|
|
|
RegisterPokemonClass::Register(_engine);
|
2021-05-08 10:12:36 +00:00
|
|
|
RegisterParty::Register(_engine);
|
2020-01-26 14:18:04 +00:00
|
|
|
RegisterExecutingAttack::Register(_engine);
|
2020-02-16 15:43:37 +00:00
|
|
|
RegisterTurnChoices::Register(_engine);
|
|
|
|
RegisterBattleLibrary::Register(_engine);
|
|
|
|
RegisterBattleClass::Register(_engine);
|
2020-02-04 18:34:30 +00:00
|
|
|
|
|
|
|
// Register base script
|
|
|
|
BasicScriptClass::Register(_engine);
|
2020-01-11 21:30:23 +00:00
|
|
|
}
|
2020-01-26 14:18:04 +00:00
|
|
|
|
2020-07-18 10:42:54 +00:00
|
|
|
void AngelScriptResolver::MessageCallback(const asSMessageInfo* msg, void*) {
|
2020-01-11 21:30:23 +00:00
|
|
|
const char* type = "ERR ";
|
|
|
|
if (msg->type == asMSGTYPE_WARNING)
|
|
|
|
type = "WARN";
|
|
|
|
else if (msg->type == asMSGTYPE_INFORMATION)
|
|
|
|
type = "INFO";
|
|
|
|
printf("%s (%d, %d) : %s : %s\n", msg->section, msg->row, msg->col, type, msg->message);
|
|
|
|
}
|
2020-02-16 13:38:05 +00:00
|
|
|
|
2021-03-07 10:12:18 +00:00
|
|
|
CreatureLib::Battling::BattleScript* AngelScriptResolver::LoadScript(ScriptCategory category,
|
2021-03-07 16:09:30 +00:00
|
|
|
const ArbUt::StringView& scriptName) {
|
2020-07-04 13:50:30 +00:00
|
|
|
ArbUt::Dictionary<ArbUt::StringView, AngelScriptTypeInfo*> innerDb;
|
2020-12-12 13:25:27 +00:00
|
|
|
auto v = _typeDatabase.TryGet(category);
|
|
|
|
if (!v.has_value()) {
|
2020-05-27 16:39:46 +00:00
|
|
|
innerDb.Insert(scriptName, nullptr);
|
2020-04-10 12:57:20 +00:00
|
|
|
_typeDatabase.Insert(category, innerDb);
|
|
|
|
return nullptr;
|
2020-12-12 13:25:27 +00:00
|
|
|
} else {
|
|
|
|
innerDb = v.value();
|
2020-04-10 12:57:20 +00:00
|
|
|
}
|
2020-12-12 13:25:27 +00:00
|
|
|
auto t = innerDb.TryGet(scriptName);
|
|
|
|
if (!t.has_value()) {
|
2020-04-10 12:57:20 +00:00
|
|
|
innerDb.Insert(scriptName, nullptr);
|
2020-01-13 18:43:34 +00:00
|
|
|
return nullptr;
|
2020-04-10 12:57:20 +00:00
|
|
|
}
|
2021-01-16 17:14:08 +00:00
|
|
|
if (t.value() == nullptr) {
|
2020-04-10 12:57:20 +00:00
|
|
|
return nullptr;
|
|
|
|
}
|
2020-01-11 21:30:23 +00:00
|
|
|
auto ctx = _contextPool->RequestContext();
|
2020-12-12 13:25:27 +00:00
|
|
|
auto obj = const_cast<AngelScriptTypeInfo*>(t.value().get())->Instantiate(ctx);
|
2020-01-11 21:30:23 +00:00
|
|
|
_contextPool->ReturnContextToPool(ctx);
|
2020-12-12 13:25:27 +00:00
|
|
|
return new AngelScriptScript(this, t.value(), obj, _contextPool);
|
2020-01-11 21:30:23 +00:00
|
|
|
}
|
2021-03-07 16:09:30 +00:00
|
|
|
|
|
|
|
CreatureLib::Battling::ItemUseScript* AngelScriptResolver::LoadItemScript(const CreatureLib::Library::Item* item) {
|
|
|
|
auto v = this->_itemUseScripts.TryGet(item);
|
|
|
|
if (v.has_value()) {
|
|
|
|
return v.value();
|
|
|
|
}
|
|
|
|
if (!item->GetEffect().HasValue()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto typeInfoOption = _itemUseTypes.TryGet(item->GetEffect().GetValue()->GetEffectName());
|
|
|
|
if (!typeInfoOption.has_value()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto* ctx = _contextPool->RequestContext();
|
|
|
|
auto factory = typeInfoOption.value().get()->GetFactoryByIndex(0);
|
|
|
|
ctx->Prepare(factory);
|
|
|
|
auto result = ctx->Execute();
|
|
|
|
if (result != asEXECUTION_FINISHED) {
|
|
|
|
throw ArbUt::Exception("Instantiation failed.");
|
|
|
|
}
|
|
|
|
asIScriptObject* obj = *(asIScriptObject**)ctx->GetAddressOfReturnValue();
|
|
|
|
obj->AddRef();
|
|
|
|
auto scriptObject = new AngelScriptItemUseScript(obj, this);
|
2021-03-27 12:33:56 +00:00
|
|
|
scriptObject->OnInitialize(item->GetEffect().GetValue()->GetParameters());
|
2021-03-07 16:09:30 +00:00
|
|
|
_itemUseScripts.Insert(item, scriptObject);
|
|
|
|
_contextPool->ReturnContextToPool(ctx);
|
|
|
|
return scriptObject;
|
|
|
|
}
|
|
|
|
|
2020-04-23 22:05:43 +00:00
|
|
|
void AngelScriptResolver::FinalizeModule() {
|
2020-02-19 08:07:44 +00:00
|
|
|
int r = _builder.BuildModule();
|
2020-01-11 21:30:23 +00:00
|
|
|
if (r < 0)
|
2020-08-16 09:12:04 +00:00
|
|
|
throw ArbUt::Exception("Building Script Module failed.");
|
2020-04-10 13:15:46 +00:00
|
|
|
asUINT count = _mainModule->GetObjectTypeCount();
|
2020-04-19 11:20:14 +00:00
|
|
|
std::regex metadataMatcher(R"(^\s*(\w+)([\w\s=]*)$)", std::regex_constants::icase);
|
|
|
|
std::regex variableMatcher(R"(\s*(\w+)=(\w+))", std::regex_constants::icase);
|
2020-04-10 12:57:20 +00:00
|
|
|
std::smatch base_match;
|
|
|
|
|
2021-03-07 16:09:30 +00:00
|
|
|
auto pkmnScriptType = _mainModule->GetTypeInfoByName("PkmnScript");
|
|
|
|
auto itemUseScriptType = _mainModule->GetTypeInfoByName("ItemUseScript");
|
2020-04-10 13:15:46 +00:00
|
|
|
for (asUINT n = 0; n < count; n++) {
|
2020-04-10 12:57:20 +00:00
|
|
|
auto typeInfo = _mainModule->GetObjectTypeByIndex(n);
|
2021-03-07 16:09:30 +00:00
|
|
|
if (typeInfo->DerivesFrom(pkmnScriptType)) {
|
|
|
|
auto metadata = _builder.GetMetadataForType(typeInfo->GetTypeId());
|
|
|
|
for (size_t m = 0; m < metadata.size(); m++) {
|
|
|
|
auto data = metadata[m];
|
|
|
|
if (std::regex_match(data, base_match, metadataMatcher)) {
|
|
|
|
auto mt = base_match[1].str();
|
|
|
|
auto metadataKind = ArbUt::StringView(mt.c_str(), mt.length());
|
|
|
|
auto metadataVariables = base_match[2].str();
|
|
|
|
if (!std::regex_match(metadataVariables, base_match, variableMatcher)) {
|
|
|
|
continue;
|
2020-04-10 12:57:20 +00:00
|
|
|
}
|
2021-03-07 16:09:30 +00:00
|
|
|
ArbUt::StringView effectName;
|
|
|
|
for (size_t variableIndex = 1; variableIndex < base_match.size(); variableIndex += 2) {
|
|
|
|
if (ArbUt::StringView::CalculateHash(base_match[variableIndex].str().c_str()) == "effect"_cnc) {
|
|
|
|
auto val = base_match[variableIndex + 1].str();
|
|
|
|
effectName = ArbUt::StringView(val.c_str(), val.length());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
RegisterScriptType(typeInfo, metadataKind, effectName);
|
2020-04-10 12:57:20 +00:00
|
|
|
}
|
2021-03-07 16:09:30 +00:00
|
|
|
}
|
|
|
|
} else if (typeInfo->DerivesFrom(itemUseScriptType)) {
|
|
|
|
auto metadata = _builder.GetMetadataForType(typeInfo->GetTypeId());
|
|
|
|
for (size_t m = 0; m < metadata.size(); m++) {
|
|
|
|
auto data = metadata[m];
|
|
|
|
if (std::regex_match(data, base_match, metadataMatcher)) {
|
|
|
|
auto mt = base_match[1].str();
|
|
|
|
auto metadataKind = ArbUt::StringView(mt.c_str(), mt.length());
|
|
|
|
auto metadataVariables = base_match[2].str();
|
|
|
|
if (!std::regex_match(metadataVariables, base_match, variableMatcher)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
ArbUt::StringView effectName;
|
|
|
|
for (size_t variableIndex = 1; variableIndex < base_match.size(); variableIndex += 2) {
|
|
|
|
if (ArbUt::StringView::CalculateHash(base_match[variableIndex].str().c_str()) == "effect"_cnc) {
|
|
|
|
auto val = base_match[variableIndex + 1].str();
|
|
|
|
effectName = ArbUt::StringView(val.c_str(), val.length());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_itemUseTypes.Insert(effectName, typeInfo);
|
2020-04-10 12:57:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-01-11 21:30:23 +00:00
|
|
|
}
|
2021-03-07 16:09:30 +00:00
|
|
|
void AngelScriptResolver::RegisterScriptType(asITypeInfo* typeInfo, const ArbUt::StringView& metadataKind,
|
|
|
|
const ArbUt::StringView& effectName) {
|
|
|
|
if (effectName.IsEmpty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
switch (metadataKind) {
|
|
|
|
case "Move"_cnc:
|
|
|
|
_typeDatabase[ScriptCategory::Attack].Insert(effectName, new AngelScriptTypeInfo(effectName, typeInfo));
|
|
|
|
break;
|
|
|
|
case "Pokemon"_cnc:
|
|
|
|
_typeDatabase[ScriptCategory::Creature].Insert(effectName, new AngelScriptTypeInfo(effectName, typeInfo));
|
|
|
|
break;
|
|
|
|
case "Ability"_cnc:
|
|
|
|
_typeDatabase[ScriptCategory::Talent].Insert(effectName, new AngelScriptTypeInfo(effectName, typeInfo));
|
|
|
|
break;
|
|
|
|
case "Status"_cnc:
|
|
|
|
_typeDatabase[ScriptCategory::Status].Insert(effectName, new AngelScriptTypeInfo(effectName, typeInfo));
|
|
|
|
break;
|
|
|
|
case "Battle"_cnc:
|
|
|
|
_typeDatabase[ScriptCategory::Battle].Insert(effectName, new AngelScriptTypeInfo(effectName, typeInfo));
|
|
|
|
break;
|
|
|
|
case "Side"_cnc:
|
|
|
|
_typeDatabase[ScriptCategory::Side].Insert(effectName, new AngelScriptTypeInfo(effectName, typeInfo));
|
|
|
|
break;
|
|
|
|
case "Weather"_cnc:
|
|
|
|
_typeDatabase[static_cast<ScriptCategory>(PkmnScriptCategory::Weather)].Insert(
|
|
|
|
effectName, new AngelScriptTypeInfo(effectName, typeInfo));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2020-04-23 22:05:43 +00:00
|
|
|
void AngelScriptResolver::CreateScript(const char* name, const char* script) {
|
2020-02-19 08:07:44 +00:00
|
|
|
_builder.AddSectionFromMemory(name, script);
|
2020-01-11 21:30:23 +00:00
|
|
|
}
|
2020-04-23 22:05:43 +00:00
|
|
|
void AngelScriptResolver::WriteByteCodeToFile(const char* file, bool stripDebugInfo) {
|
2020-04-12 08:17:15 +00:00
|
|
|
FILE* wFile = nullptr;
|
2020-05-02 09:13:04 +00:00
|
|
|
// Open file in write binary mode.
|
2020-04-12 08:17:15 +00:00
|
|
|
wFile = fopen(file, "wb");
|
2020-05-02 09:13:04 +00:00
|
|
|
// Ensure we opened it.
|
2020-12-13 11:32:52 +00:00
|
|
|
EnsureNotNull(wFile);
|
2020-05-02 09:13:04 +00:00
|
|
|
// Save the initial position, as we need to write here later.
|
|
|
|
fpos_t startPos;
|
|
|
|
fgetpos(wFile, &startPos);
|
|
|
|
// The first 8 bytes are the position of the data for which script name is which script decl.
|
|
|
|
// We don't know this position yet, so we write an empty value here. We write a size of 8, to accommodate an
|
|
|
|
// unsigned long.
|
|
|
|
uint64_t byteCodeSizeArr[]{0};
|
|
|
|
fwrite(byteCodeSizeArr, sizeof(uint64_t), 1, wFile);
|
|
|
|
// We initialize a stream, with no bounds (as this is a read thing)
|
|
|
|
auto stream = new FileByteCodeStream(wFile, SIZE_MAX);
|
|
|
|
// And save the angelscript byte code.
|
2020-04-11 12:42:49 +00:00
|
|
|
_mainModule->SaveByteCode(stream, stripDebugInfo);
|
2020-05-02 09:13:04 +00:00
|
|
|
// We grab the current position of the written file. This is the position the types will be written on. So we need
|
|
|
|
// to know this.
|
|
|
|
uint64_t bytecodeSize = (uint64_t)ftell(wFile);
|
2021-03-07 17:11:18 +00:00
|
|
|
stream->WriteTypes(_typeDatabase, _itemUseTypes);
|
2020-05-02 09:13:04 +00:00
|
|
|
|
|
|
|
// Go back to the start of the file
|
|
|
|
fsetpos(wFile, &startPos);
|
|
|
|
// And write the actual position the types are at.
|
|
|
|
byteCodeSizeArr[0] = bytecodeSize;
|
|
|
|
fwrite(byteCodeSizeArr, sizeof(uint64_t), 1, wFile);
|
|
|
|
|
|
|
|
// Close the file
|
2020-12-13 11:32:52 +00:00
|
|
|
Ensure(fclose(wFile) == 0);
|
2020-04-11 12:42:49 +00:00
|
|
|
delete stream;
|
|
|
|
}
|
2020-05-02 09:13:04 +00:00
|
|
|
void AngelScriptResolver::LoadByteCodeFromFile(const char* file) {
|
2020-04-12 08:17:15 +00:00
|
|
|
FILE* rFile = nullptr;
|
2020-05-02 09:13:04 +00:00
|
|
|
// Open the file in read binary mode
|
2020-04-12 08:17:15 +00:00
|
|
|
rFile = fopen(file, "rb");
|
2020-05-02 09:13:04 +00:00
|
|
|
// Ensure it opened
|
2020-12-13 11:32:52 +00:00
|
|
|
EnsureNotNull(rFile);
|
2020-05-02 09:13:04 +00:00
|
|
|
// the first 8 bytes are position of the types database, everything before that is the angelscript byte code.
|
|
|
|
uint64_t byteCodeSize[]{0};
|
|
|
|
fread(byteCodeSize, sizeof(uint64_t), 1, rFile);
|
|
|
|
// Initialize a stream, with the earlier found bounds.
|
|
|
|
auto stream = new FileByteCodeStream(rFile, byteCodeSize[0] - 1);
|
|
|
|
// And load the angelscript byte code.
|
|
|
|
int result = _mainModule->LoadByteCode(stream);
|
|
|
|
// Ensure we succeeded in this.
|
2020-12-13 11:32:52 +00:00
|
|
|
Ensure(result == asSUCCESS);
|
2020-05-02 09:13:04 +00:00
|
|
|
|
|
|
|
// Begin loading the type database
|
|
|
|
auto types = stream->ReadTypes();
|
|
|
|
|
2020-07-18 10:42:54 +00:00
|
|
|
InitializeByteCode(types);
|
2020-12-13 11:32:52 +00:00
|
|
|
Ensure(fclose(rFile) == 0);
|
2020-04-11 12:42:49 +00:00
|
|
|
delete stream;
|
|
|
|
}
|
2020-04-23 22:05:43 +00:00
|
|
|
uint8_t* AngelScriptResolver::WriteByteCodeToMemory(size_t& size, bool stripDebugInfo) {
|
2020-04-11 12:42:49 +00:00
|
|
|
auto stream = new MemoryByteCodeStream();
|
2020-05-02 09:13:04 +00:00
|
|
|
size_t byteCodeSize[]{0};
|
|
|
|
stream->Write(byteCodeSize, sizeof(uint64_t));
|
2020-04-11 12:42:49 +00:00
|
|
|
auto result = _mainModule->SaveByteCode(stream, stripDebugInfo);
|
2020-12-13 11:32:52 +00:00
|
|
|
Ensure(result == asSUCCESS);
|
2020-05-02 09:13:04 +00:00
|
|
|
byteCodeSize[0] = (uint64_t)stream->GetWrittenSize();
|
2021-03-07 17:11:18 +00:00
|
|
|
stream->WriteTypes(_typeDatabase, _itemUseTypes);
|
2020-05-02 09:13:04 +00:00
|
|
|
stream->WriteToPosition(byteCodeSize, sizeof(uint64_t), 0);
|
2020-04-11 12:42:49 +00:00
|
|
|
auto arr = stream->GetOut();
|
|
|
|
size = stream->GetWrittenSize();
|
2020-04-11 13:03:44 +00:00
|
|
|
arr = static_cast<uint8_t*>(realloc(arr, size * sizeof(uint8_t)));
|
2020-04-11 12:42:49 +00:00
|
|
|
delete stream;
|
|
|
|
return arr;
|
|
|
|
}
|
2020-05-02 09:13:04 +00:00
|
|
|
void AngelScriptResolver::LoadByteCodeFromMemory(uint8_t* byte, size_t size) {
|
2020-04-11 12:42:49 +00:00
|
|
|
auto stream = new MemoryByteCodeStream(byte, size);
|
2020-05-02 09:13:04 +00:00
|
|
|
uint64_t byteCodeSizeArr[]{0};
|
|
|
|
stream->Read(byteCodeSizeArr, sizeof(uint64_t));
|
|
|
|
stream->SetAngelScriptBound((size_t)byteCodeSizeArr[0]);
|
|
|
|
// And load the angelscript byte code.
|
|
|
|
int result = _mainModule->LoadByteCode(stream);
|
|
|
|
// Ensure we succeeded in this.
|
2020-12-13 11:32:52 +00:00
|
|
|
Ensure(result == asSUCCESS);
|
2020-05-02 09:13:04 +00:00
|
|
|
|
|
|
|
// Begin loading the type database
|
|
|
|
auto types = stream->ReadTypes();
|
|
|
|
|
2020-07-18 10:42:54 +00:00
|
|
|
InitializeByteCode(types);
|
2020-04-11 12:42:49 +00:00
|
|
|
delete stream;
|
|
|
|
}
|
2020-04-23 22:05:43 +00:00
|
|
|
void AngelScriptResolver::InitializeByteCode(
|
2020-07-04 13:50:30 +00:00
|
|
|
const ArbUt::Dictionary<ScriptCategory, ArbUt::Dictionary<ArbUt::StringView, uint32_t>>& types) {
|
2020-04-11 12:42:49 +00:00
|
|
|
|
|
|
|
auto typeCount = _mainModule->GetObjectTypeCount();
|
2020-05-27 15:26:25 +00:00
|
|
|
ArbUt::Dictionary<uint32_t, asITypeInfo*> objectTypes;
|
2020-04-11 12:42:49 +00:00
|
|
|
for (asUINT i = 0; i < typeCount; i++) {
|
|
|
|
auto t = _mainModule->GetObjectTypeByIndex(i);
|
2021-01-22 13:11:03 +00:00
|
|
|
objectTypes.Set(ArbUt::StringView::CalculateHash(t->GetName()), t);
|
2020-04-11 12:42:49 +00:00
|
|
|
}
|
2020-07-04 13:50:30 +00:00
|
|
|
ArbUt::Dictionary<ScriptCategory, ArbUt::Dictionary<ArbUt::StringView, AngelScriptTypeInfo*>> typeDatabase;
|
2020-05-02 09:13:04 +00:00
|
|
|
for (const auto& innerDb : types) {
|
2021-03-07 17:11:18 +00:00
|
|
|
if (innerDb.first != (ScriptCategory)-1) {
|
|
|
|
ArbUt::Dictionary<ArbUt::StringView, AngelScriptTypeInfo*> newInnerDb;
|
|
|
|
for (const auto& val : innerDb.second) {
|
|
|
|
auto decl = val.second;
|
|
|
|
auto type = objectTypes[decl];
|
|
|
|
newInnerDb.Set(val.first, new AngelScriptTypeInfo(val.first, type));
|
|
|
|
}
|
|
|
|
typeDatabase.Set(innerDb.first, newInnerDb);
|
|
|
|
} else {
|
|
|
|
for (const auto& val : innerDb.second) {
|
|
|
|
auto decl = val.second;
|
|
|
|
auto type = objectTypes[decl];
|
2021-03-07 18:35:38 +00:00
|
|
|
_itemUseTypes.Set(val.first, type);
|
2021-03-07 17:11:18 +00:00
|
|
|
}
|
2020-04-11 12:42:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
_typeDatabase = typeDatabase;
|
2021-03-07 16:09:30 +00:00
|
|
|
}
|