Adds caching for expensive type resolution.
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Deukhoofd 2021-09-22 19:02:01 +02:00
parent 7e9e574577
commit e5ea2bbc90
Signed by: Deukhoofd
GPG Key ID: F63E044490819F6F
22 changed files with 124 additions and 42 deletions

View File

@ -1,4 +1,5 @@
#include "AngelScriptEvolutionScript.hpp"
#include "AngelScriptFunctionCall.hpp"
#include "AngelScriptResolver.hpp"
void AngelScriptEvolutionScript::DoesEvolveFromLevelUp(
@ -8,7 +9,7 @@ void AngelScriptEvolutionScript::DoesEvolveFromLevelUp(
return;
}
AngelScriptUtils::AngelscriptFunctionCall(
__DoesEvolveFromLevelUp.Function, _resolver->GetContextPool(), _scriptObject, ""_cnc,
__DoesEvolveFromLevelUp.Function, _resolver->GetContextPool(), _scriptObject, _resolver, ""_cnc,
[&]([[maybe_unused]] asIScriptContext* ctx) {
ctx->SetArgObject(0, (void*)evolution.GetRaw());
ctx->SetArgObject(1, (void*)pokemon.GetRaw());

View File

@ -1,8 +1,8 @@
#ifndef PKMNLIB_ANGELSCRIPTEVOLUTIONSCRIPT_HPP
#define PKMNLIB_ANGELSCRIPTEVOLUTIONSCRIPT_HPP
#include <angelscript.h>
#include "../../Battling/Pokemon/Pokemon.hpp"
#include "../../Library/Evolutions/EvolutionData.hpp"
#include "AngelScriptFunctionCall.hpp"
class AngelScriptResolver;

View File

@ -1,12 +1,13 @@
#ifndef PKMNLIB_ANGELSCRIPTFUNCTIONCALL_HPP
#define PKMNLIB_ANGELSCRIPTFUNCTIONCALL_HPP
#include "AngelScriptResolver.hpp"
#include "ContextPool.hpp"
class AngelScriptUtils {
public:
static void AngelscriptFunctionCall(asIScriptFunction* func, ContextPool* ctxPool, asIScriptObject* obj,
const ArbUt::StringView& scriptName,
AngelScriptResolver* resolver, const ArbUt::StringView& scriptName,
const std::function<void(asIScriptContext*)>& setup,
const std::function<void(asIScriptContext*)>& onEnd) {
auto ctx = asGetActiveContext();
@ -17,6 +18,9 @@ public:
} else {
ctx->PushState();
}
if (ctx->GetUserData() == nullptr) {
ctx->SetUserData(resolver->GetUserdata());
}
ctx->Prepare(func);
ctx->SetObject(obj);
setup(ctx);

View File

@ -1,10 +1,12 @@
#include "AngelScriptItemUseScript.hpp"
#include "AngelScriptFunctionCall.hpp"
#include "AngelScriptResolver.hpp"
#include "AngelscriptUserdata.hpp"
CScriptArray*
AngelScriptItemUseScript::GetEffectParameters(const ArbUt::List<CreatureLib::Library::EffectParameter*>& ls) {
asITypeInfo* t = _resolver->GetBaseType("array<EffectParameter@>"_cnc);
CScriptArray* arr = CScriptArray::Create(t, ls.Count());
auto* ud = _resolver->GetUserdata();
auto* arr = ud->CreateArray("array<EffectParameter@>"_cnc, ls.Count());
for (size_t i = 0; i < ls.Count(); i++) {
arr->SetValue(i, (void**)&ls[i]);
}
@ -15,7 +17,7 @@ void AngelScriptItemUseScript::OnInitialize(const ArbUt::List<CreatureLib::Libra
if (__OnInitialize.Exists) {
CScriptArray* arr = nullptr;
AngelScriptUtils::AngelscriptFunctionCall(
__OnInitialize.Function, _resolver->GetContextPool(), _scriptObject, ""_cnc,
__OnInitialize.Function, _resolver->GetContextPool(), _scriptObject, _resolver, ""_cnc,
[&]([[maybe_unused]] asIScriptContext* ctx) {
arr = GetEffectParameters(parameters);
ctx->SetArgAddress(0, arr);
@ -32,7 +34,7 @@ bool AngelScriptItemUseScript::IsItemUsable() const {
}
bool res = false;
AngelScriptUtils::AngelscriptFunctionCall(
__IsItemUsable.Function, _resolver->GetContextPool(), _scriptObject, ""_cnc,
__IsItemUsable.Function, _resolver->GetContextPool(), _scriptObject, _resolver, ""_cnc,
[&]([[maybe_unused]] asIScriptContext* ctx) {},
[&]([[maybe_unused]] asIScriptContext* ctx) { res = ctx->GetReturnByte() == 1; });
return res;
@ -44,7 +46,7 @@ bool AngelScriptItemUseScript::IsCreatureUseItem() const {
}
bool res = false;
AngelScriptUtils::AngelscriptFunctionCall(
__IsPokemonUseItem.Function, _resolver->GetContextPool(), _scriptObject, ""_cnc,
__IsPokemonUseItem.Function, _resolver->GetContextPool(), _scriptObject, _resolver, ""_cnc,
[&]([[maybe_unused]] asIScriptContext* ctx) {},
[&]([[maybe_unused]] asIScriptContext* ctx) { res = ctx->GetReturnByte() == 1; });
return res;
@ -55,7 +57,7 @@ bool AngelScriptItemUseScript::IsUseValidForCreature(CreatureLib::Battling::Crea
}
bool res = false;
AngelScriptUtils::AngelscriptFunctionCall(
__IsUseValidForPokemon.Function, _resolver->GetContextPool(), _scriptObject, ""_cnc,
__IsUseValidForPokemon.Function, _resolver->GetContextPool(), _scriptObject, _resolver, ""_cnc,
[&]([[maybe_unused]] asIScriptContext* ctx) { ctx->SetArgObject(0, (void*)creature); },
[&]([[maybe_unused]] asIScriptContext* ctx) { res = ctx->GetReturnByte() == 1; });
return res;
@ -66,7 +68,7 @@ bool AngelScriptItemUseScript::IsHoldable() const {
}
bool res = false;
AngelScriptUtils::AngelscriptFunctionCall(
__IsHoldable.Function, _resolver->GetContextPool(), _scriptObject, ""_cnc,
__IsHoldable.Function, _resolver->GetContextPool(), _scriptObject, _resolver, ""_cnc,
[&]([[maybe_unused]] asIScriptContext* ctx) {},
[&]([[maybe_unused]] asIScriptContext* ctx) { res = ctx->GetReturnByte() == 1; });
return res;
@ -76,7 +78,7 @@ void AngelScriptItemUseScript::OnUse() const {
CreatureLib::Battling::ItemUseScript::OnUse();
}
AngelScriptUtils::AngelscriptFunctionCall(
__OnUse.Function, _resolver->GetContextPool(), _scriptObject, ""_cnc,
__OnUse.Function, _resolver->GetContextPool(), _scriptObject, _resolver, ""_cnc,
[&]([[maybe_unused]] asIScriptContext* ctx) {}, [&]([[maybe_unused]] asIScriptContext* ctx) {});
}
void AngelScriptItemUseScript::OnCreatureUse(CreatureLib::Battling::Creature* creature) const {
@ -84,7 +86,7 @@ void AngelScriptItemUseScript::OnCreatureUse(CreatureLib::Battling::Creature* cr
CreatureLib::Battling::ItemUseScript::OnUse();
}
AngelScriptUtils::AngelscriptFunctionCall(
__OnPokemonUse.Function, _resolver->GetContextPool(), _scriptObject, ""_cnc,
__OnPokemonUse.Function, _resolver->GetContextPool(), _scriptObject, _resolver, ""_cnc,
[&]([[maybe_unused]] asIScriptContext* ctx) { ctx->SetArgObject(0, (void*)creature); },
[&]([[maybe_unused]] asIScriptContext* ctx) {});
}

View File

@ -3,7 +3,6 @@
#include <CreatureLib/Battling/ScriptHandling/ItemUseScript.hpp>
#include "../../../extern/angelscript_addons/scriptarray/scriptarray.h"
#include "AngelScriptFunctionCall.hpp"
class AngelScriptResolver;

View File

@ -9,8 +9,10 @@
#include "../../Battling/PkmnScriptCategory.hpp"
#include "../../Battling/Pokemon/Pokemon.hpp"
#include "AngelScriptMetadata.hpp"
#include "AngelscriptUserdata.hpp"
#include "ByteCodeHandling/FileByteCodeStream.hpp"
#include "ByteCodeHandling/MemoryByteCodeStream.hpp"
#include "ContextPool.hpp"
#include "TypeRegistry/BasicScriptClass.hpp"
#include "TypeRegistry/Battling/RegisterBattleClass.hpp"
#include "TypeRegistry/Battling/RegisterBattleLibrary.hpp"
@ -48,6 +50,22 @@ static void TranslateException(asIScriptContext* ctx, void* /*userParam*/) {
}
}
AngelScriptResolver::AngelScriptResolver() : _userData(new AngelscriptUserdata(this)) {}
AngelScriptResolver::~AngelScriptResolver() {
for (const auto& ius : _itemUseScripts) {
delete ius.second;
}
delete _contextPool;
for (const auto& category : _typeDatabase) {
for (const auto& type : category.second) {
delete type.second;
}
}
delete _userData;
_engine->ShutDownAndRelease();
}
void AngelScriptResolver::Initialize(CreatureLib::Battling::BattleLibrary* arg, bool includeStandard) {
for (auto scriptCategory : ScriptCategoryHelper::GetValues()) {
_typeDatabase.Insert(scriptCategory, {});
@ -101,7 +119,7 @@ void AngelScriptResolver::Initialize(CreatureLib::Battling::BattleLibrary* arg,
_engine->RegisterGlobalProperty("const StaticLibrary@ StaticLib", (void*)staticLib.get());
}
_contextPool = new ContextPool(_engine);
_contextPool = new ContextPool(_engine, _userData);
asPrepareMultithread();
}
@ -209,6 +227,7 @@ AngelScriptResolver::LoadEvolutionScript(const ArbUt::StringView& view) {
return nullptr;
}
auto* ctx = _contextPool->RequestContext();
auto* factory = typeInfoOption.value().get()->GetFactoryByIndex(0);
ctx->Prepare(factory);
auto result = ctx->Execute();
@ -441,4 +460,4 @@ i32 AngelScriptResolver::IncludeCallback(const char* include, const char*, CScri
return -102;
}
return builder->AddSectionFromFile((const char*)path.c_str());
}
}

View File

@ -14,6 +14,8 @@
#include "AngelScriptScript.hpp"
#include "AngelScriptTypeInfo.hpp"
class AngelscriptUserdata;
class AngelScriptResolver final : public PkmnLib::Battling::ScriptResolver {
private:
asIScriptEngine* _engine = nullptr;
@ -21,6 +23,7 @@ private:
ContextPool* _contextPool = nullptr;
CScriptBuilder _builder = {};
std::string _sourceDirectory = {};
AngelscriptUserdata* _userData;
ArbUt::Dictionary<ScriptCategory, ArbUt::Dictionary<ArbUt::StringView, AngelScriptTypeInfo*>> _typeDatabase;
ArbUt::Dictionary<ArbUt::StringView, asITypeInfo*> _baseTypes;
@ -42,18 +45,8 @@ private:
const ArbUt::StringView& effectName);
public:
~AngelScriptResolver() override {
for (const auto& ius : _itemUseScripts) {
delete ius.second;
}
delete _contextPool;
for (const auto& category : _typeDatabase) {
for (const auto& type : category.second) {
delete type.second;
}
}
_engine->ShutDownAndRelease();
}
AngelScriptResolver();
~AngelScriptResolver() override;
void Initialize(CreatureLib::Battling::BattleLibrary* library) override { Initialize(library, true); }
void Initialize(CreatureLib::Battling::BattleLibrary* library, bool includeStandard);
@ -112,5 +105,7 @@ public:
}
inline ContextPool* GetContextPool() const noexcept { return _contextPool; }
inline AngelscriptUserdata* GetUserdata() const noexcept { return _userData; }
};
#endif // PKMNLIB_ANGELSCRIPRESOLVER_HPP

View File

@ -1,18 +1,18 @@
#include "AngelScriptScript.hpp"
#include "AngelScriptFunctionCall.hpp"
#include "AngelScriptResolver.hpp"
#include "AngelscriptUserdata.hpp"
#define CALL_HOOK(name, setup) \
auto s = _type->Get##name(); \
if (!s.Exists) \
return; \
AngelScriptUtils::AngelscriptFunctionCall( \
s.Function, _ctxPool, _obj, GetName(), [&]([[maybe_unused]] asIScriptContext* ctx) { setup }, \
s.Function, _ctxPool, _obj, _resolver, GetName(), [&]([[maybe_unused]] asIScriptContext* ctx) { setup }, \
[&]([[maybe_unused]] asIScriptContext* ctx) {});
CScriptArray* AngelScriptScript::GetEffectParameters(const ArbUt::List<CreatureLib::Library::EffectParameter*>& ls) {
asITypeInfo* t = _resolver->GetBaseType("array<EffectParameter@>"_cnc);
CScriptArray* arr = CScriptArray::Create(t, ls.Count());
auto arr = _resolver->GetUserdata()->CreateArray("array<EffectParameter@>"_cnc, ls.Count());
for (size_t i = 0; i < ls.Count(); i++) {
arr->SetValue(i, (void**)&ls[i]);
}

View File

@ -6,9 +6,10 @@
#include "../../../extern/angelscript_addons/scriptarray/scriptarray.h"
#include "../../Battling/PkmnScript.hpp"
#include "AngelScriptTypeInfo.hpp"
#include "ContextPool.hpp"
class AngelScriptResolver;
class ContextPool;
class AngelScriptScript final : public PkmnLib::Battling::PkmnScript {
private:
AngelScriptResolver* _resolver = nullptr;

View File

@ -0,0 +1,36 @@
#ifndef PKMNLIB_ANGELSCRIPTUSERDATA_HPP
#define PKMNLIB_ANGELSCRIPTUSERDATA_HPP
#include <Arbutils/Collections/Dictionary.hpp>
#include "AngelScriptResolver.hpp"
class AngelscriptUserdata {
AngelScriptResolver* _resolver;
ArbUt::Dictionary<ArbUt::StringView, asITypeInfo*> _cachedTypes;
public:
AngelscriptUserdata(AngelScriptResolver* r) : _resolver(r) {}
~AngelscriptUserdata() {
for (auto& t : _cachedTypes) {
t.second->Release();
}
}
asITypeInfo* GetType(const ArbUt::StringView& name) {
auto v = _cachedTypes.TryGet(name);
if (v.has_value()) {
return v.value();
}
auto t = _resolver->GetBaseType(name);
t->AddRef();
_cachedTypes.Set(name, t);
return t;
}
CScriptArray* CreateArray(const ArbUt::StringView& name, size_t length) {
auto t = GetType(name);
return CScriptArray::Create(t, length);
}
};
#endif // PKMNLIB_ANGELSCRIPTUSERDATA_HPP

View File

@ -4,6 +4,7 @@
#include <angelscript.h>
#include <mutex>
#include <thread>
#include "AngelscriptUserdata.hpp"
class ContextPool {
struct CtxThreadedPoolStorage {
@ -19,6 +20,7 @@ class ContextPool {
ArbUt::Dictionary<std::thread::id, CtxThreadedPoolStorage*> _pool;
asIScriptEngine* _engine;
AngelscriptUserdata* _userData;
CtxThreadedPoolStorage* GetThreadPool() {
auto id = std::this_thread::get_id();
@ -30,7 +32,7 @@ class ContextPool {
}
public:
ContextPool(asIScriptEngine* engine) : _engine(engine) {}
ContextPool(asIScriptEngine* engine, AngelscriptUserdata* userData) : _engine(engine), _userData(userData) {}
~ContextPool() {
for (const auto& kv : _pool) {
@ -48,6 +50,7 @@ public:
pool->Pool.pop_back();
} else {
ctx = _engine->CreateContext();
ctx->SetUserData(_userData);
}
return ctx;
}

View File

@ -6,6 +6,7 @@
#include "../../../../Battling/Pokemon/Pokemon.hpp"
#include "../../AngelScriptResolver.hpp"
#include "../../AngelScriptScript.hpp"
#include "../../AngelscriptUserdata.hpp"
#include "../HelperFile.hpp"
void RegisterBattleClass::Register(asIScriptEngine* engine) {
@ -99,17 +100,29 @@ void RegisterBattleClass::RegisterBattleSide(asIScriptEngine* engine) {
void RegisterBattleClass::RegisterBattle(asIScriptEngine* engine) {
REGISTER_GETTER("Battle", "const BattleLibrary@ get_Library() const property", CreatureLib::Battling::Battle,
GetLibrary);
REGISTER_GETTER("Battle", "bool get_CanFlee() const property", CreatureLib::Battling::Battle,
CanFlee);
REGISTER_GETTER("Battle", "uint get_CurrentTurn() const property", CreatureLib::Battling::Battle,
GetCurrentTurn);
REGISTER_GETTER("Battle", "BattleRandom@ get_Random() const property", CreatureLib::Battling::Battle,
GetRandom);
REGISTER_GETTER("Battle", "bool get_CanFlee() const property", CreatureLib::Battling::Battle, CanFlee);
REGISTER_GETTER("Battle", "uint get_CurrentTurn() const property", CreatureLib::Battling::Battle, GetCurrentTurn);
REGISTER_GETTER("Battle", "BattleRandom@ get_Random() const property", CreatureLib::Battling::Battle, GetRandom);
REGISTER_GETTER("Battle", "ChoiceQueue@ get_TurnQueue() const property", CreatureLib::Battling::Battle,
GetCurrentTurnQueue);
{
auto l = [](const CreatureLib::Battling::Battle* b) {
const auto& ls = b->GetSides();
auto* ctx = asGetActiveContext();
auto* ud = (AngelscriptUserdata*)ctx->GetUserData();
auto* arr = ud->CreateArray("array<BattleSide@>"_cnc, ls.Count());
for (size_t i = 0; i < ls.Count(); i++) {
arr->SetValue(i, ls[i].GetRaw());
}
return arr;
};
Ensure(engine->RegisterObjectMethod("Battle", "const array<BattleSide@>& get_Sides() const property",
asFUNCTIONPR(l, (const CreatureLib::Battling::Battle*), CScriptArray*),
asCALL_CDECL_OBJFIRST) >= 0);
}
auto r = engine->RegisterObjectMethod("Battle", "bool CanUse(BaseTurnChoice@ choice)",
asMETHOD(PkmnLib::Battling::Battle, CanUse), asCALL_THISCALL);
asMETHOD(PkmnLib::Battling::Battle, CanUse), asCALL_THISCALL);
Ensure(r >= 0);
r = engine->RegisterObjectMethod("Battle", "ref@ AddVolatile(const constString &in name)",
asFUNCTION(AddVolatileWrapper), asCALL_CDECL_OBJFIRST);

View File

@ -6,6 +6,7 @@
#include "../../../../Battling/Pokemon/Pokemon.hpp"
#include "../../AngelScriptResolver.hpp"
#include "../../AngelScriptScript.hpp"
#include "../../AngelscriptUserdata.hpp"
#include "../HelperFile.hpp"
void RegisterPokemonClass::Register(asIScriptEngine* engine) {
@ -63,10 +64,9 @@ ENUM__SIZE_WRAPPER(Pkmn_GenderWrapper, PkmnLib::Battling::Pokemon, GetGender)
CScriptArray* GetMoves(const PkmnLib::Battling::Pokemon* obj) {
asIScriptContext* ctx = asGetActiveContext();
if (ctx) {
asIScriptEngine* engine = ctx->GetEngine();
asITypeInfo* t = engine->GetTypeInfoByDecl("array<LearnedMove@>");
auto a = obj->GetMoves();
CScriptArray* arr = CScriptArray::Create(t, a.Count());
auto ud = (AngelscriptUserdata*)ctx->GetUserData();
CScriptArray* arr = ud->CreateArray("array<LearnedMove@>"_cnc, a.Count());
for (size_t i = 0; i < a.Count(); i++) {
arr->SetValue(i, &a[i]);
}

View File

@ -2,6 +2,7 @@
#include "../../extern/doctest.hpp"
#include "../../src/Battling/Pokemon/CreatePokemon.hpp"
#include "../../src/ScriptResolving/AngelScript/AngelScriptResolver.hpp"
#include "../../src/ScriptResolving/AngelScript/ContextPool.hpp"
#include "../TestLibrary/TestLibrary.hpp"
#define AS_CLASS(name, contents) \

View File

@ -1,6 +1,7 @@
#ifdef TESTS_BUILD
#include "../../extern/doctest.hpp"
#include "../../src/ScriptResolving/AngelScript/AngelScriptResolver.hpp"
#include "../../src/ScriptResolving/AngelScript/ContextPool.hpp"
#include "../TestLibrary/TestLibrary.hpp"
static std::unordered_map<const char*, const char*> _scripts =

View File

@ -3,6 +3,7 @@
#include "../../../../src/Battling/Battle/Battle.hpp"
#include "../../../../src/Battling/Pokemon/CreatePokemon.hpp"
#include "../../../../src/ScriptResolving/AngelScript/AngelScriptResolver.hpp"
#include "../../../../src/ScriptResolving/AngelScript/ContextPool.hpp"
#include "../../../TestLibrary/TestLibrary.hpp"
static std::unordered_map<const char*, const char*> _scripts =

View File

@ -2,6 +2,7 @@
#include "../../../../extern/doctest.hpp"
#include "../../../../src/Battling/Pokemon/CreatePokemon.hpp"
#include "../../../../src/ScriptResolving/AngelScript/AngelScriptResolver.hpp"
#include "../../../../src/ScriptResolving/AngelScript/ContextPool.hpp"
#include "../../../TestLibrary/TestLibrary.hpp"
static std::unordered_map<const char*, const char*> _scripts =

View File

@ -1,6 +1,7 @@
#ifdef TESTS_BUILD
#include "../../../../extern/doctest.hpp"
#include "../../../../src/ScriptResolving/AngelScript/AngelScriptResolver.hpp"
#include "../../../../src/ScriptResolving/AngelScript/ContextPool.hpp"
#include "../../../TestLibrary/TestLibrary.hpp"
static std::unordered_map<const char*, const char*> _scripts =

View File

@ -1,6 +1,7 @@
#ifdef TESTS_BUILD
#include "../../../../extern/doctest.hpp"
#include "../../../../src/ScriptResolving/AngelScript/AngelScriptResolver.hpp"
#include "../../../../src/ScriptResolving/AngelScript/ContextPool.hpp"
#include "../../../TestLibrary/TestLibrary.hpp"
static std::unordered_map<const char*, const char*> _scripts =

View File

@ -1,6 +1,7 @@
#ifdef TESTS_BUILD
#include "../../../../extern/doctest.hpp"
#include "../../../../src/ScriptResolving/AngelScript/AngelScriptResolver.hpp"
#include "../../../../src/ScriptResolving/AngelScript/ContextPool.hpp"
#include "../../../TestLibrary/TestLibrary.hpp"
static std::unordered_map<const char*, const char*> _scripts =

View File

@ -1,6 +1,7 @@
#ifdef TESTS_BUILD
#include "../../../../extern/doctest.hpp"
#include "../../../../src/ScriptResolving/AngelScript/AngelScriptResolver.hpp"
#include "../../../../src/ScriptResolving/AngelScript/ContextPool.hpp"
#include "../../../TestLibrary/TestLibrary.hpp"
static std::unordered_map<const char*, const char*> _scripts =

View File

@ -1,6 +1,7 @@
#ifdef TESTS_BUILD
#include "../../../../extern/doctest.hpp"
#include "../../../../src/ScriptResolving/AngelScript/AngelScriptResolver.hpp"
#include "../../../../src/ScriptResolving/AngelScript/ContextPool.hpp"
#include "../../../TestLibrary/TestLibrary.hpp"
static std::unordered_map<const char*, const char*> _scripts =