Layout work on an AngelScript implementation.
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
2020-01-11 22:30:23 +01:00
parent 497acc1311
commit c716992f12
24 changed files with 5342 additions and 38 deletions

View File

@@ -0,0 +1,72 @@
#include "AngelScripResolver.hpp"
#include "TypeRegistry/RegisterPokemonTypes.hpp"
#include "../../extern/angelscript_addons/scriptstdstring/scriptstdstring.h"
#include "../../extern/angelscript_addons/scripthelper/scripthelper.h"
CreatureLib::Battling::ScriptResolver* PkmnLib::Battling::BattleLibrary::CreateScriptResolver(){
return new AngelScripResolver();
}
void AngelScripResolver::Initialize(CreatureLib::Battling::BattleLibrary* library) {
_engine = asCreateScriptEngine();
_engine->SetEngineProperty(asEP_DISALLOW_EMPTY_LIST_ELEMENTS, true);
_engine->SetEngineProperty(asEP_DISALLOW_VALUE_ASSIGN_FOR_REF_TYPE, true);
_engine->SetEngineProperty(asEP_ALLOW_IMPLICIT_HANDLE_TYPES, true);
_engine->SetEngineProperty(asEP_ALWAYS_IMPL_DEFAULT_CONSTRUCT, true);
_engine->SetEngineProperty(asEP_AUTO_GARBAGE_COLLECT, false);
int32_t r = _engine->SetMessageCallback(asFUNCTION(MessageCallback), nullptr, asCALL_CDECL);
if (r < 0)
throw CreatureException("Registering message callback failed.");
RegisterStdString(_engine);
r = _engine->RegisterGlobalFunction("void print(const string &in)", asFUNCTION(Print), asCALL_CDECL);
if (r < 0) throw CreatureException("Registering print function failed.");
RegisterExceptionRoutines(_engine);
RegisterPokemonTypes::Register(_engine);
_mainModule = _engine->GetModule("pkmn", asGM_ALWAYS_CREATE);
_contextPool = new ContextPool(_engine);
}
AngelScriptTypeInfo* AngelScripResolver::GetTypeInfo(const std::string& name) {
auto find = _types.find(name);
if (find != _types.end()){
return find->second;
}
auto type = _mainModule->GetTypeInfoByDecl(name.c_str());
if (type == nullptr){
_types.insert({name, nullptr});
return nullptr;
}
auto typeinfo = new AngelScriptTypeInfo(type);
_types.insert({name, typeinfo});
return typeinfo;
}
void AngelScripResolver::MessageCallback(const asSMessageInfo* msg, void* param) {
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);
}
CreatureLib::Battling::Script* AngelScripResolver::LoadScript(ScriptCategory category, const std::string& scriptName) {
auto typeInfo = GetTypeInfo(scriptName);
if (typeInfo == nullptr) return nullptr;
auto ctx = _contextPool->RequestContext();
auto obj = typeInfo->Instantiate(ctx);
_contextPool->ReturnContextToPool(ctx);
return new AngelScriptScript(scriptName, typeInfo, obj, _contextPool);
}
void AngelScripResolver::FinalizeModule() {
int r = _mainModule->Build();
if (r < 0)
throw CreatureException("Building Script Module failed.");
}
void AngelScripResolver::CreateScript(const char* scriptName) {
auto scriptString = _loadFunc(scriptName);
_mainModule->AddScriptSection(scriptName, scriptString);
}

View File

@@ -0,0 +1,46 @@
#ifndef PKMNLIB_ANGELSCRIPRESOLVER_HPP
#define PKMNLIB_ANGELSCRIPRESOLVER_HPP
#include <Battling/ScriptHandling/ScriptResolver.hpp>
#include "../Battling/Library/BattleLibrary.hpp"
#undef GetProperty
#include <angelscript.h>
#include <cassert>
#include <iostream>
#include "AngelScriptScript.hpp"
#include "AngelScriptTypeInfo.hpp"
class AngelScripResolver : public CreatureLib::Battling::ScriptResolver {
private:
asIScriptEngine* _engine = nullptr;
asIScriptModule* _mainModule = nullptr;
ContextPool* _contextPool = nullptr;
const char* (*_loadFunc)(const char*) = nullptr;
std::unordered_map<std::string, AngelScriptTypeInfo*> _types;
static void MessageCallback(const asSMessageInfo* msg, void* param);
static void Print(const std::string& str) { std::cout << str << std::endl; }
AngelScriptTypeInfo* GetTypeInfo(const std::string& name);
public:
~AngelScripResolver() override {
delete _contextPool;
for (const auto& type : _types) {
delete type.second;
}
_types.clear();
_engine->ShutDownAndRelease();
}
void Initialize(CreatureLib::Battling::BattleLibrary* library) override;
void SetCreateFunction(const char* (*loadFunc)(const char* scriptName)) { _loadFunc = loadFunc; }
void CreateScript(const char* scriptName);
void FinalizeModule();
CreatureLib::Battling::Script* LoadScript(ScriptCategory category, const std::string& scriptName) override;
};
#endif // PKMNLIB_ANGELSCRIPRESOLVER_HPP

View File

@@ -1 +1,2 @@
#undef GetProperty
#include "AngelScriptScript.hpp"

View File

@@ -1,6 +1,55 @@
#ifndef PKMNLIB_ANGELSCRIPTSCRIPT_HPP
#define PKMNLIB_ANGELSCRIPTSCRIPT_HPP
#include <Battling/ScriptHandling/Script.hpp>
#undef GetProperty
#include <angelscript.h>
#include "AngelScriptTypeInfo.hpp"
#include "ContextPool.hpp"
class AngelScriptScript {};
class AngelScriptScript : public CreatureLib::Battling::Script {
private:
AngelScriptTypeInfo* _type = nullptr;
ContextPool* _ctxPool = nullptr;
asIScriptObject* _obj = nullptr;
public:
AngelScriptScript(const std::string& name, AngelScriptTypeInfo* type, asIScriptObject* obj, ContextPool* ctxPool)
: CreatureLib::Battling::Script(name), _type(type), _ctxPool(ctxPool), _obj(obj) {
}
~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);
ctx->SetObject(_obj);
return func;
}
ContextPool* GetContextPool(){
return _ctxPool;
}
};
#endif // PKMNLIB_ANGELSCRIPTSCRIPT_HPP

View File

@@ -0,0 +1 @@
#include "AngelScriptTypeInfo.hpp"

View File

@@ -0,0 +1,47 @@
#ifndef PKMNLIB_ANGELSCRIPTTYPEINFO_HPP
#define PKMNLIB_ANGELSCRIPTTYPEINFO_HPP
#include <angelscript.h>
#include <unordered_map>
#include <Core/Exceptions/CreatureException.hpp>
class AngelScriptTypeInfo {
private:
asITypeInfo* _type = nullptr;
std::unordered_map<std::string, asIScriptFunction*> _functions;
public:
explicit AngelScriptTypeInfo(asITypeInfo* type) : _type(type){}
~AngelScriptTypeInfo(){
for (const auto& f: _functions){
f.second->Release();
}
_functions.clear();
}
asIScriptFunction* GetFunction(const std::string& functionName){
auto find = _functions.find(functionName);
if (find != _functions.end()){
return find->second;
}
auto func = _type->GetMethodByName(functionName.c_str());
func->AddRef();
_functions.insert({functionName, func});
return func;
}
asIScriptObject* Instantiate(asIScriptContext* ctx){
auto factory = _type->GetFactoryByIndex(0);
ctx->Prepare(factory);
auto result = ctx->Execute();
if (result != asEXECUTION_FINISHED){
throw CreatureException("Instantiation failed.");
}
asIScriptObject* obj = *(asIScriptObject**)ctx->GetAddressOfReturnValue();
obj->AddRef();
return obj;
}
};
#endif // PKMNLIB_ANGELSCRIPTTYPEINFO_HPP

View File

@@ -0,0 +1 @@
#include "ContextPool.hpp"

View File

@@ -0,0 +1,37 @@
#ifndef PKMNLIB_CONTEXTPOOL_HPP
#define PKMNLIB_CONTEXTPOOL_HPP
#include <angelscript.h>
#include <vector>
class ContextPool {
std::vector<asIScriptContext*> _pool;
asIScriptEngine* _engine;
public:
ContextPool(asIScriptEngine* engine) : _engine(engine) {}
~ContextPool(){
for (auto ctx: _pool){
ctx->Release();
}
}
asIScriptContext* RequestContext() {
// Get a context from the pool, or create a new
asIScriptContext* ctx = nullptr;
if (!_pool.empty()) {
ctx = *_pool.rbegin();
_pool.pop_back();
} else
ctx = _engine->CreateContext();
return ctx;
}
void ReturnContextToPool(asIScriptContext* ctx) {
_pool.push_back(ctx);
ctx->Unprepare();
}
};
#endif // PKMNLIB_CONTEXTPOOL_HPP

View File

@@ -1,16 +0,0 @@
#include "../Battling/Library/PokemonScriptResolver.hpp"
#define ANGELSCRIPT_DLL_LIBRARY_IMPORT
#define GetPropertyCache
#undef GetProperty
#include <angelscript.h>
#define GetProperty GetPropertyCache
using namespace PkmnLib::Battling;
void PokemonScriptResolver::Initialize(const PkmnLib::Battling::BattleLibrary* library){
}
CreatureLib::Battling::Script* PokemonScriptResolver::LoadScript(ScriptCategory category, const std::string& scriptName){
return nullptr;
}

View File

@@ -0,0 +1,36 @@
#include "RegisterPokemonTypes.hpp"
#include <cassert>
#include "../../Library/Species/PokemonSpecies.hpp"
void RegisterPokemonTypes::Register(asIScriptEngine* engine) {
RegisterGenderEnum(engine);
RegisterSpeciesType(engine);
}
void RegisterPokemonTypes::RegisterGenderEnum(asIScriptEngine* engine) {
int r = engine->RegisterEnum("Gender"); assert(r >= 0);
r = engine->RegisterEnumValue("Gender", "Male", 0); assert(r >= 0);
r = engine->RegisterEnumValue("Gender", "Female", 1); assert(r >= 0);
r = engine->RegisterEnumValue("Gender", "Genderless", 2); assert(r >= 0);
}
void RegisterPokemonTypes::RegisterSpeciesType(asIScriptEngine* engine) {
int r = engine->RegisterObjectType("Species", 0, asOBJ_REF | asOBJ_NOCOUNT);
assert(r >= 0);
r = engine->RegisterObjectMethod("Species", "const string& get_Name() const property",
asMETHOD(PkmnLib::Library::PokemonSpecies, GetName), asCALL_THISCALL);
assert(r >= 0);
r = engine->RegisterObjectMethod("Species", "uint16 get_Id() const property",
asMETHOD(PkmnLib::Library::PokemonSpecies, GetId), asCALL_THISCALL);
assert(r >= 0);
r = engine->RegisterObjectMethod("Species", "float get_GenderRate() const property",
asMETHOD(PkmnLib::Library::PokemonSpecies, GetGenderRate), asCALL_THISCALL);
assert(r >= 0);
r = engine->RegisterObjectMethod("Species", "uint8 get_CaptureRate() const property",
asMETHOD(PkmnLib::Library::PokemonSpecies, GetCaptureRate), asCALL_THISCALL);
assert(r >= 0);
r = engine->RegisterObjectMethod("Species", "Gender GetRandomGender() const",
asMETHOD(PkmnLib::Library::PokemonSpecies, GetRandomGender), asCALL_THISCALL);
assert(r >= 0);
}

View File

@@ -0,0 +1,14 @@
#ifndef PKMNLIB_REGISTERPOKEMONTYPES_HPP
#define PKMNLIB_REGISTERPOKEMONTYPES_HPP
#include <angelscript.h>
class RegisterPokemonTypes {
public:
static void Register(asIScriptEngine* engine);
private:
static void RegisterGenderEnum(asIScriptEngine* engine);
static void RegisterSpeciesType(asIScriptEngine* engine);
};
#endif // PKMNLIB_REGISTERPOKEMONTYPES_HPP

View File

@@ -33,7 +33,8 @@ namespace PkmnLib::Battling {
const Library::NatureLibrary* GetNatureLibrary() const {
return GetStaticLib()->GetNatureLibrary();
}
static CreatureLib::Battling::ScriptResolver* CreateScriptResolver();
};
}
#endif // PKMNLIB_BATTLELIBRARY_HPP

View File

@@ -1,15 +0,0 @@
#ifndef PKMNLIB_POKEMONSCRIPTRESOLVER_HPP
#define PKMNLIB_POKEMONSCRIPTRESOLVER_HPP
#include <Battling/ScriptHandling/ScriptResolver.hpp>
#include "../../Battling/Library/BattleLibrary.hpp"
namespace PkmnLib::Battling {
class PokemonScriptResolver : public CreatureLib::Battling::ScriptResolver {
public:
~PokemonScriptResolver() override = default;
void Initialize(const PkmnLib::Battling::BattleLibrary* library);
CreatureLib::Battling::Script* LoadScript(ScriptCategory category, const std::string& scriptName) override;
};
}
#endif // PKMNLIB_POKEMONSCRIPTRESOLVER_HPP