Actual implementation of Angelscript hooks into battle library.
Some checks failed
continuous-integration/drone/push Build is failing
Some checks failed
continuous-integration/drone/push Build is failing
This commit is contained in:
@@ -2,8 +2,11 @@
|
||||
#define AS_USE_ACCESSORS
|
||||
#include "../../../extern/angelscript_addons/scriptarray/scriptarray.h"
|
||||
#undef AS_USE_ACCESSORS
|
||||
#include <cassert>
|
||||
#include "../../../extern/angelscript_addons/scripthandle/scripthandle.h"
|
||||
#include "../../../extern/angelscript_addons/scripthelper/scripthelper.h"
|
||||
#include "../../../extern/angelscript_addons/scriptstdstring/scriptstdstring.h"
|
||||
#include "TypeRegistry/BasicScriptClass.hpp"
|
||||
#include "TypeRegistry/Battling/RegisterExecutingAttack.hpp"
|
||||
#include "TypeRegistry/Battling/RegisterPokemonClass.hpp"
|
||||
#include "TypeRegistry/Library/RegisterGrowthRateTypes.hpp"
|
||||
@@ -17,7 +20,8 @@ CreatureLib::Battling::ScriptResolver* PkmnLib::Battling::BattleLibrary::CreateS
|
||||
return new AngelScripResolver();
|
||||
}
|
||||
|
||||
void AngelScripResolver::Initialize(CreatureLib::Battling::BattleLibrary* library) {
|
||||
void AngelScripResolver::Initialize(CreatureLib::Battling::BattleLibrary* arg) {
|
||||
auto library = (PkmnLib::Battling::BattleLibrary*)arg;
|
||||
_engine = asCreateScriptEngine();
|
||||
|
||||
int32_t r = _engine->SetMessageCallback(asFUNCTION(MessageCallback), nullptr, asCALL_CDECL);
|
||||
@@ -25,10 +29,13 @@ void AngelScripResolver::Initialize(CreatureLib::Battling::BattleLibrary* librar
|
||||
throw CreatureException("Registering message callback failed.");
|
||||
|
||||
_engine->SetEngineProperty(asEP_DISALLOW_EMPTY_LIST_ELEMENTS, true);
|
||||
_engine->SetEngineProperty(asEP_DISALLOW_VALUE_ASSIGN_FOR_REF_TYPE, true);
|
||||
_engine->SetEngineProperty(asEP_DISALLOW_VALUE_ASSIGN_FOR_REF_TYPE, false);
|
||||
_engine->SetEngineProperty(asEP_ALLOW_UNSAFE_REFERENCES, true);
|
||||
_engine->SetEngineProperty(asEP_ALWAYS_IMPL_DEFAULT_CONSTRUCT, true);
|
||||
_engine->SetEngineProperty(asEP_AUTO_GARBAGE_COLLECT, false);
|
||||
_engine->SetEngineProperty(asEP_REQUIRE_ENUM_SCOPE, true);
|
||||
_engine->SetEngineProperty(asEP_PROPERTY_ACCESSOR_MODE, 2);
|
||||
|
||||
|
||||
RegisterStdString(_engine);
|
||||
|
||||
@@ -38,11 +45,15 @@ void AngelScripResolver::Initialize(CreatureLib::Battling::BattleLibrary* librar
|
||||
r = _engine->RegisterGlobalFunction("void print(const string &in)", asFUNCTION(Print), asCALL_CDECL);
|
||||
if (r < 0)
|
||||
throw CreatureException("Registering print function failed.");
|
||||
RegisterScriptHandle(_engine);
|
||||
|
||||
_mainModule = _engine->GetModule("pkmn", asGM_ALWAYS_CREATE);
|
||||
|
||||
RegisterTypes();
|
||||
RegisterExceptionRoutines(_engine);
|
||||
|
||||
_mainModule = _engine->GetModule("pkmn", asGM_ALWAYS_CREATE);
|
||||
auto staticLib = library->GetStaticLib();
|
||||
_engine->RegisterGlobalProperty("const StaticLibrary@ StaticLib", &staticLib);
|
||||
|
||||
_contextPool = new ContextPool(_engine);
|
||||
}
|
||||
@@ -59,6 +70,9 @@ void AngelScripResolver::RegisterTypes() {
|
||||
// Register battle types
|
||||
RegisterPokemonClass::Register(_engine);
|
||||
RegisterExecutingAttack::Register(_engine);
|
||||
|
||||
// Register base script
|
||||
BasicScriptClass::Register(_engine);
|
||||
}
|
||||
|
||||
AngelScriptTypeInfo* AngelScripResolver::GetTypeInfo(const std::string& name) {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <Battling/ScriptHandling/Script.hpp>
|
||||
#define ANGELSCRIPT_DLL_LIBRARY_IMPORT
|
||||
#include <angelscript.h>
|
||||
#include <Core/Exceptions/NotImplementedException.hpp>
|
||||
#include "AngelScriptTypeInfo.hpp"
|
||||
#include "ContextPool.hpp"
|
||||
|
||||
@@ -19,25 +20,6 @@ public:
|
||||
|
||||
~AngelScriptScript() override { _obj->Release(); }
|
||||
|
||||
void InvokeMethod(const char* name) {
|
||||
auto func = _type->GetFunction(name);
|
||||
if (func == nullptr)
|
||||
return;
|
||||
auto ctx = _ctxPool->RequestContext();
|
||||
ctx->Prepare(func);
|
||||
ctx->SetObject(_obj);
|
||||
auto result = ctx->Execute();
|
||||
if (result != asEXECUTION_FINISHED) {
|
||||
if (result == asEXECUTION_EXCEPTION) {
|
||||
throw CreatureException(ctx->GetExceptionString());
|
||||
}
|
||||
throw CreatureException("Function failed.");
|
||||
}
|
||||
_ctxPool->ReturnContextToPool(ctx);
|
||||
}
|
||||
|
||||
asIScriptObject* GetScriptObject() { return _obj; }
|
||||
|
||||
asIScriptFunction* PrepareMethod(const char* name, asIScriptContext* ctx) {
|
||||
auto func = _type->GetFunction(name);
|
||||
ctx->Prepare(func);
|
||||
@@ -46,6 +28,89 @@ public:
|
||||
}
|
||||
|
||||
ContextPool* GetContextPool() { return _ctxPool; }
|
||||
|
||||
#define CALLHOOK(name, setup) \
|
||||
auto s = _type->Get##name(); \
|
||||
if (!s.Exists) \
|
||||
return; \
|
||||
auto ctx = _ctxPool->RequestContext(); \
|
||||
ctx->Prepare(s.Function); \
|
||||
ctx->SetObject(_obj); \
|
||||
setup; \
|
||||
auto scriptResult = ctx->Execute(); \
|
||||
if (scriptResult != 0) { \
|
||||
throw CreatureException("Script didn't finish properly; message " + std::to_string(scriptResult)); \
|
||||
} \
|
||||
_ctxPool->ReturnContextToPool(ctx);
|
||||
|
||||
void Stack() override { CALLHOOK(Stack, {}); }
|
||||
|
||||
void OnBeforeTurn(const CreatureLib::Battling::BaseTurnChoice* choice) override {
|
||||
throw NotImplementedException(); //TODO
|
||||
}
|
||||
|
||||
void ChangeAttack(CreatureLib::Battling::AttackTurnChoice* choice, std::string* outAttack) override {
|
||||
throw NotImplementedException(); //TODO
|
||||
}
|
||||
|
||||
void PreventAttack(CreatureLib::Battling::ExecutingAttack* attack, bool* outResult) override {
|
||||
CALLHOOK(PreventAttack, {
|
||||
ctx->SetArgObject(0, (void*)attack);
|
||||
ctx->SetArgAddress(1, outResult);
|
||||
})
|
||||
}
|
||||
|
||||
void FailAttack(CreatureLib::Battling::ExecutingAttack* attack, bool* outFailed) override {
|
||||
CALLHOOK(FailAttack, {
|
||||
ctx->SetArgObject(0, (void*)attack);
|
||||
ctx->SetArgAddress(1, outFailed);
|
||||
})
|
||||
}
|
||||
|
||||
void StopBeforeAttack(CreatureLib::Battling::ExecutingAttack* attack, bool* outResult) override {
|
||||
CALLHOOK(StopBeforeAttack, {
|
||||
ctx->SetArgObject(0, (void*)attack);
|
||||
ctx->SetArgAddress(1, outResult);
|
||||
})
|
||||
}
|
||||
|
||||
void OnBeforeAttack(CreatureLib::Battling::ExecutingAttack* attack) override { Script::OnBeforeAttack(attack); }
|
||||
void FailIncomingAttack(CreatureLib::Battling::ExecutingAttack* attack, CreatureLib::Battling::Creature* target,
|
||||
bool* outResult) override {
|
||||
Script::FailIncomingAttack(attack, target, outResult);
|
||||
}
|
||||
void IsInvulnerable(CreatureLib::Battling::ExecutingAttack* attack, CreatureLib::Battling::Creature* target,
|
||||
bool* outResult) override {
|
||||
Script::IsInvulnerable(attack, target, outResult);
|
||||
}
|
||||
void OnAttackMiss(CreatureLib::Battling::ExecutingAttack* attack,
|
||||
CreatureLib::Battling::Creature* target) override {
|
||||
Script::OnAttackMiss(attack, target);
|
||||
}
|
||||
void ChangeAttackType(CreatureLib::Battling::ExecutingAttack* attack, CreatureLib::Battling::Creature* target,
|
||||
uint8_t hitNumber, uint8_t* outType) override {
|
||||
Script::ChangeAttackType(attack, target, hitNumber, outType);
|
||||
}
|
||||
void OnStatusMove(const CreatureLib::Battling::ExecutingAttack* attack, CreatureLib::Battling::Creature* target,
|
||||
uint8_t hitNumber) override {
|
||||
Script::OnStatusMove(attack, target, hitNumber);
|
||||
}
|
||||
void PreventSecondaryEffects(const CreatureLib::Battling::ExecutingAttack* attack,
|
||||
CreatureLib::Battling::Creature* target, uint8_t hitNumber, bool* outResult) override {
|
||||
Script::PreventSecondaryEffects(attack, target, hitNumber, outResult);
|
||||
}
|
||||
void OnSecondaryEffect(const CreatureLib::Battling::ExecutingAttack* attack,
|
||||
CreatureLib::Battling::Creature* target, uint8_t hitNumber) override {
|
||||
Script::OnSecondaryEffect(attack, target, hitNumber);
|
||||
}
|
||||
void OnAfterHits(const CreatureLib::Battling::ExecutingAttack* attack,
|
||||
CreatureLib::Battling::Creature* target) override {
|
||||
Script::OnAfterHits(attack, target);
|
||||
}
|
||||
void PreventSelfSwitch(const CreatureLib::Battling::SwitchTurnChoice* choice, bool* outResult) override {
|
||||
Script::PreventSelfSwitch(choice, outResult);
|
||||
}
|
||||
};
|
||||
|
||||
#undef CALLHOOK
|
||||
#endif // PKMNLIB_ANGELSCRIPTSCRIPT_HPP
|
||||
|
||||
@@ -2,42 +2,59 @@
|
||||
#define PKMNLIB_ANGELSCRIPTTYPEINFO_HPP
|
||||
|
||||
#define ANGELSCRIPT_DLL_LIBRARY_IMPORT
|
||||
#include <angelscript.h>
|
||||
#include <unordered_map>
|
||||
#include <Core/Exceptions/CreatureException.hpp>
|
||||
#include <angelscript.h>
|
||||
#include <cstring>
|
||||
#include <unordered_map>
|
||||
|
||||
class AngelScriptTypeInfo {
|
||||
private:
|
||||
asITypeInfo* _type = nullptr;
|
||||
std::unordered_map<std::string, asIScriptFunction*> _functions;
|
||||
|
||||
struct FunctionInfo {
|
||||
bool Exists = false;
|
||||
asIScriptFunction* Function = nullptr;
|
||||
};
|
||||
|
||||
FunctionInfo Initialize(const std::string& decl) {
|
||||
auto val = _type->GetMethodByDecl(decl.c_str(), false);
|
||||
if (val == nullptr){
|
||||
return FunctionInfo{.Exists = false, .Function = nullptr};
|
||||
}
|
||||
if (!val->IsOverride()){
|
||||
return FunctionInfo{.Exists = false, .Function = nullptr};
|
||||
}
|
||||
return FunctionInfo{.Exists = true, .Function = val};
|
||||
}
|
||||
|
||||
public:
|
||||
explicit AngelScriptTypeInfo(asITypeInfo* type) : _type(type){}
|
||||
~AngelScriptTypeInfo(){
|
||||
for (const auto& f: _functions){
|
||||
explicit AngelScriptTypeInfo(asITypeInfo* type) : _type(type) {}
|
||||
~AngelScriptTypeInfo() {
|
||||
for (const auto& f : _functions) {
|
||||
f.second->Release();
|
||||
}
|
||||
_functions.clear();
|
||||
}
|
||||
|
||||
asIScriptFunction* GetFunction(const std::string& functionName){
|
||||
asIScriptFunction* GetFunction(const std::string& functionName) {
|
||||
auto find = _functions.find(functionName);
|
||||
if (find != _functions.end()){
|
||||
if (find != _functions.end()) {
|
||||
return find->second;
|
||||
}
|
||||
auto func = _type->GetMethodByName(functionName.c_str());
|
||||
if (func != nullptr){
|
||||
if (func != nullptr) {
|
||||
func->AddRef();
|
||||
}
|
||||
_functions.insert({functionName, func});
|
||||
return func;
|
||||
}
|
||||
|
||||
asIScriptObject* Instantiate(asIScriptContext* ctx){
|
||||
asIScriptObject* Instantiate(asIScriptContext* ctx) {
|
||||
auto factory = _type->GetFactoryByIndex(0);
|
||||
ctx->Prepare(factory);
|
||||
auto result = ctx->Execute();
|
||||
if (result != asEXECUTION_FINISHED){
|
||||
if (result != asEXECUTION_FINISHED) {
|
||||
throw CreatureException("Instantiation failed.");
|
||||
}
|
||||
asIScriptObject* obj = *(asIScriptObject**)ctx->GetAddressOfReturnValue();
|
||||
@@ -45,6 +62,16 @@ public:
|
||||
return obj;
|
||||
}
|
||||
|
||||
#define SCRIPT_HOOK_FUNCTION(name, decl) \
|
||||
private: FunctionInfo __##name = Initialize(decl); \
|
||||
public: const FunctionInfo& Get##name() const { return __##name; }
|
||||
|
||||
SCRIPT_HOOK_FUNCTION(Stack, "void Stack()");
|
||||
SCRIPT_HOOK_FUNCTION(PreventAttack, "void PreventAttack(ExecutingMove@ attack, bool& result)");
|
||||
SCRIPT_HOOK_FUNCTION(FailAttack, "void FailAttack(ExecutingMove@ attack, bool& result)");
|
||||
SCRIPT_HOOK_FUNCTION(StopBeforeAttack, "void StopBeforeAttack(ExecutingMove@ attack, bool& result)");
|
||||
|
||||
};
|
||||
|
||||
#undef SCRIPT_HOOK_FUNCTION
|
||||
#endif // PKMNLIB_ANGELSCRIPTTYPEINFO_HPP
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
#include "BasicScriptClass.hpp"
|
||||
#include <cassert>
|
||||
|
||||
void BasicScriptClass::Register(asIScriptEngine* engine) {
|
||||
[[maybe_unused]] int r = engine->GetModuleByIndex(0)->AddScriptSection("PkmnScript", R"(
|
||||
shared abstract class PkmnScript {
|
||||
void Stack(){};
|
||||
void PreventAttack(ExecutingMove@ attack, bool& result){};
|
||||
void FailAttack(ExecutingMove@ attack, bool& result){};
|
||||
void StopBeforeAttack(ExecutingMove@ attack, bool& result){};
|
||||
}
|
||||
)");
|
||||
assert(r >= 0);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#ifndef PKMNLIB_BASICSCRIPTCLASS_HPP
|
||||
#define PKMNLIB_BASICSCRIPTCLASS_HPP
|
||||
|
||||
#include <angelscript.h>
|
||||
class BasicScriptClass {
|
||||
public:
|
||||
static void Register(asIScriptEngine* engine);
|
||||
};
|
||||
|
||||
#endif // PKMNLIB_BASICSCRIPTCLASS_HPP
|
||||
@@ -10,10 +10,13 @@ void RegisterStaticLibraryTypes::Register(asIScriptEngine* engine) {
|
||||
void RegisterStaticLibraryTypes::RegisterLibrarySettingsType(asIScriptEngine* engine) {
|
||||
[[maybe_unused]] int r = engine->RegisterObjectType("LibrarySettings", 0, asOBJ_REF | asOBJ_NOCOUNT);
|
||||
r = engine->RegisterObjectMethod("LibrarySettings", "uint8 get_MaximalLevel() const property",
|
||||
asMETHOD(CreatureLib::Library::LibrarySettings, GetMaximalLevel), asCALL_THISCALL);
|
||||
asMETHOD(PkmnLib::Library::LibrarySettings, GetMaximalLevel), asCALL_THISCALL);
|
||||
assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("LibrarySettings", "uint8 get_MaximalMoves() const property",
|
||||
asMETHOD(CreatureLib::Library::LibrarySettings, GetMaximalMoves), asCALL_THISCALL);
|
||||
asMETHOD(PkmnLib::Library::LibrarySettings, GetMaximalMoves), asCALL_THISCALL);
|
||||
assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("LibrarySettings", "uint16 get_ShinyRate() const property",
|
||||
asMETHOD(PkmnLib::Library::LibrarySettings, GetShinyRate), asCALL_THISCALL);
|
||||
assert(r >= 0);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user