Actual implementation of Angelscript hooks into battle library.
continuous-integration/drone/push Build is failing
Details
continuous-integration/drone/push Build is failing
Details
This commit is contained in:
parent
0455fec875
commit
bcc038b49d
|
@ -40,7 +40,7 @@ class PkmnLibConan(ConanFile):
|
|||
self.options["AngelScript"].link_std_statically = True
|
||||
|
||||
def requirements(self):
|
||||
self.requires("CreatureLib/c3b573c7daa3f2815e063c9dabfaa5dbfe6dbb20@creaturelib/master")
|
||||
self.requires("CreatureLib/cd7ddcf78ec0ee4ae645d1862f92ec23246af949@creaturelib/master")
|
||||
if self.options.script_handler == "angelscript":
|
||||
self.requires("AngelScript/2.34@AngelScript/Deukhoofd")
|
||||
else:
|
||||
|
|
|
@ -0,0 +1,360 @@
|
|||
#include "scripthandle.h"
|
||||
#include <new>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
static void Construct(CScriptHandle *self) { new(self) CScriptHandle(); }
|
||||
static void Construct(CScriptHandle *self, const CScriptHandle &o) { new(self) CScriptHandle(o); }
|
||||
// This one is not static because it needs to be friend with the CScriptHandle class
|
||||
void Construct(CScriptHandle *self, void *ref, int typeId) { new(self) CScriptHandle(ref, typeId); }
|
||||
static void Destruct(CScriptHandle *self) { self->~CScriptHandle(); }
|
||||
|
||||
CScriptHandle::CScriptHandle()
|
||||
{
|
||||
m_ref = 0;
|
||||
m_type = 0;
|
||||
}
|
||||
|
||||
CScriptHandle::CScriptHandle(const CScriptHandle &other)
|
||||
{
|
||||
m_ref = other.m_ref;
|
||||
m_type = other.m_type;
|
||||
|
||||
AddRefHandle();
|
||||
}
|
||||
|
||||
CScriptHandle::CScriptHandle(void *ref, asITypeInfo *type)
|
||||
{
|
||||
m_ref = ref;
|
||||
m_type = type;
|
||||
|
||||
AddRefHandle();
|
||||
}
|
||||
|
||||
// This constructor shouldn't be called from the application
|
||||
// directly as it requires an active script context
|
||||
CScriptHandle::CScriptHandle(void *ref, int typeId)
|
||||
{
|
||||
m_ref = 0;
|
||||
m_type = 0;
|
||||
|
||||
Assign(ref, typeId);
|
||||
}
|
||||
|
||||
CScriptHandle::~CScriptHandle()
|
||||
{
|
||||
ReleaseHandle();
|
||||
}
|
||||
|
||||
void CScriptHandle::ReleaseHandle()
|
||||
{
|
||||
if( m_ref && m_type )
|
||||
{
|
||||
asIScriptEngine *engine = m_type->GetEngine();
|
||||
engine->ReleaseScriptObject(m_ref, m_type);
|
||||
|
||||
engine->Release();
|
||||
|
||||
m_ref = 0;
|
||||
m_type = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void CScriptHandle::AddRefHandle()
|
||||
{
|
||||
if( m_ref && m_type )
|
||||
{
|
||||
asIScriptEngine *engine = m_type->GetEngine();
|
||||
engine->AddRefScriptObject(m_ref, m_type);
|
||||
|
||||
// Hold on to the engine so it isn't destroyed while
|
||||
// a reference to a script object is still held
|
||||
engine->AddRef();
|
||||
}
|
||||
}
|
||||
|
||||
CScriptHandle &CScriptHandle::operator =(const CScriptHandle &other)
|
||||
{
|
||||
Set(other.m_ref, other.m_type);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void CScriptHandle::Set(void *ref, asITypeInfo *type)
|
||||
{
|
||||
if( m_ref == ref ) return;
|
||||
|
||||
ReleaseHandle();
|
||||
|
||||
m_ref = ref;
|
||||
m_type = type;
|
||||
|
||||
AddRefHandle();
|
||||
}
|
||||
|
||||
void *CScriptHandle::GetRef()
|
||||
{
|
||||
return m_ref;
|
||||
}
|
||||
|
||||
asITypeInfo *CScriptHandle::GetType() const
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
|
||||
int CScriptHandle::GetTypeId() const
|
||||
{
|
||||
if( m_type == 0 ) return 0;
|
||||
|
||||
return m_type->GetTypeId() | asTYPEID_OBJHANDLE;
|
||||
}
|
||||
|
||||
// This method shouldn't be called from the application
|
||||
// directly as it requires an active script context
|
||||
CScriptHandle &CScriptHandle::Assign(void *ref, int typeId)
|
||||
{
|
||||
// When receiving a null handle we just clear our memory
|
||||
if( typeId == 0 )
|
||||
{
|
||||
Set(0, 0);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Dereference received handles to get the object
|
||||
if( typeId & asTYPEID_OBJHANDLE )
|
||||
{
|
||||
// Store the actual reference
|
||||
ref = *(void**)ref;
|
||||
typeId &= ~asTYPEID_OBJHANDLE;
|
||||
}
|
||||
|
||||
// Get the object type
|
||||
asIScriptContext *ctx = asGetActiveContext();
|
||||
asIScriptEngine *engine = ctx->GetEngine();
|
||||
asITypeInfo *type = engine->GetTypeInfoById(typeId);
|
||||
|
||||
// If the argument is another CScriptHandle, we should copy the content instead
|
||||
if( type && strcmp(type->GetName(), "ref") == 0 )
|
||||
{
|
||||
CScriptHandle *r = (CScriptHandle*)ref;
|
||||
ref = r->m_ref;
|
||||
type = r->m_type;
|
||||
}
|
||||
|
||||
Set(ref, type);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool CScriptHandle::operator==(const CScriptHandle &o) const
|
||||
{
|
||||
if( m_ref == o.m_ref &&
|
||||
m_type == o.m_type )
|
||||
return true;
|
||||
|
||||
// TODO: If type is not the same, we should attempt to do a dynamic cast,
|
||||
// which may change the pointer for application registered classes
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CScriptHandle::operator!=(const CScriptHandle &o) const
|
||||
{
|
||||
return !(*this == o);
|
||||
}
|
||||
|
||||
bool CScriptHandle::Equals(void *ref, int typeId) const
|
||||
{
|
||||
// Null handles are received as reference to a null handle
|
||||
if( typeId == 0 )
|
||||
ref = 0;
|
||||
|
||||
// Dereference handles to get the object
|
||||
if( typeId & asTYPEID_OBJHANDLE )
|
||||
{
|
||||
// Compare the actual reference
|
||||
ref = *(void**)ref;
|
||||
typeId &= ~asTYPEID_OBJHANDLE;
|
||||
}
|
||||
|
||||
// TODO: If typeId is not the same, we should attempt to do a dynamic cast,
|
||||
// which may change the pointer for application registered classes
|
||||
|
||||
if( ref == m_ref ) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// AngelScript: used as '@obj = cast<obj>(ref);'
|
||||
void CScriptHandle::Cast(void **outRef, int typeId)
|
||||
{
|
||||
// If we hold a null handle, then just return null
|
||||
if( m_type == 0 )
|
||||
{
|
||||
*outRef = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// It is expected that the outRef is always a handle
|
||||
assert( typeId & asTYPEID_OBJHANDLE );
|
||||
|
||||
// Compare the type id of the actual object
|
||||
typeId &= ~asTYPEID_OBJHANDLE;
|
||||
asIScriptEngine *engine = m_type->GetEngine();
|
||||
asITypeInfo *type = engine->GetTypeInfoById(typeId);
|
||||
|
||||
*outRef = 0;
|
||||
|
||||
// RefCastObject will increment the refCount of the returned object if successful
|
||||
engine->RefCastObject(m_ref, m_type, type, outRef);
|
||||
}
|
||||
|
||||
void CScriptHandle::EnumReferences(asIScriptEngine *inEngine)
|
||||
{
|
||||
// If we're holding a reference, we'll notify the garbage collector of it
|
||||
if (m_ref)
|
||||
inEngine->GCEnumCallback(m_ref);
|
||||
|
||||
// The object type itself is also garbage collected
|
||||
if( m_type)
|
||||
inEngine->GCEnumCallback(m_type);
|
||||
}
|
||||
|
||||
void CScriptHandle::ReleaseReferences(asIScriptEngine *inEngine)
|
||||
{
|
||||
// Simply clear the content to release the references
|
||||
Set(0, 0);
|
||||
}
|
||||
|
||||
void RegisterScriptHandle_Native(asIScriptEngine *engine)
|
||||
{
|
||||
int r;
|
||||
|
||||
#if AS_CAN_USE_CPP11
|
||||
// With C++11 it is possible to use asGetTypeTraits to automatically determine the flags that represent the C++ class
|
||||
r = engine->RegisterObjectType("ref", sizeof(CScriptHandle), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asGetTypeTraits<CScriptHandle>()); assert( r >= 0 );
|
||||
#else
|
||||
r = engine->RegisterObjectType("ref", sizeof(CScriptHandle), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asOBJ_APP_CLASS_CDAK); assert( r >= 0 );
|
||||
#endif
|
||||
r = engine->RegisterObjectBehaviour("ref", asBEHAVE_CONSTRUCT, "void f()", asFUNCTIONPR(Construct, (CScriptHandle *), void), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("ref", asBEHAVE_CONSTRUCT, "void f(const ref &in)", asFUNCTIONPR(Construct, (CScriptHandle *, const CScriptHandle &), void), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("ref", asBEHAVE_CONSTRUCT, "void f(const ?&in)", asFUNCTIONPR(Construct, (CScriptHandle *, void *, int), void), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("ref", asBEHAVE_DESTRUCT, "void f()", asFUNCTIONPR(Destruct, (CScriptHandle *), void), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("ref", asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(CScriptHandle,EnumReferences), asCALL_THISCALL); assert(r >= 0);
|
||||
r = engine->RegisterObjectBehaviour("ref", asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(CScriptHandle, ReleaseReferences), asCALL_THISCALL); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("ref", "void opCast(?&out)", asMETHODPR(CScriptHandle, Cast, (void **, int), void), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("ref", "ref &opHndlAssign(const ref &in)", asMETHOD(CScriptHandle, operator=), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("ref", "ref &opHndlAssign(const ?&in)", asMETHOD(CScriptHandle, Assign), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("ref", "bool opEquals(const ref &in) const", asMETHODPR(CScriptHandle, operator==, (const CScriptHandle &) const, bool), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("ref", "bool opEquals(const ?&in) const", asMETHODPR(CScriptHandle, Equals, (void*, int) const, bool), asCALL_THISCALL); assert( r >= 0 );
|
||||
}
|
||||
|
||||
void CScriptHandle_Construct_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptHandle *self = reinterpret_cast<CScriptHandle*>(gen->GetObject());
|
||||
new(self) CScriptHandle();
|
||||
}
|
||||
|
||||
void CScriptHandle_ConstructCopy_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptHandle *other = reinterpret_cast<CScriptHandle*>(gen->GetArgAddress(0));
|
||||
CScriptHandle *self = reinterpret_cast<CScriptHandle*>(gen->GetObject());
|
||||
new(self) CScriptHandle(*other);
|
||||
}
|
||||
|
||||
void CScriptHandle_ConstructVar_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
void *ref = gen->GetArgAddress(0);
|
||||
int typeId = gen->GetArgTypeId(0);
|
||||
CScriptHandle *self = reinterpret_cast<CScriptHandle*>(gen->GetObject());
|
||||
Construct(self, ref, typeId);
|
||||
}
|
||||
|
||||
void CScriptHandle_Destruct_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptHandle *self = reinterpret_cast<CScriptHandle*>(gen->GetObject());
|
||||
self->~CScriptHandle();
|
||||
}
|
||||
|
||||
void CScriptHandle_Cast_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
void **ref = reinterpret_cast<void**>(gen->GetArgAddress(0));
|
||||
int typeId = gen->GetArgTypeId(0);
|
||||
CScriptHandle *self = reinterpret_cast<CScriptHandle*>(gen->GetObject());
|
||||
self->Cast(ref, typeId);
|
||||
}
|
||||
|
||||
void CScriptHandle_Assign_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptHandle *other = reinterpret_cast<CScriptHandle*>(gen->GetArgAddress(0));
|
||||
CScriptHandle *self = reinterpret_cast<CScriptHandle*>(gen->GetObject());
|
||||
*self = *other;
|
||||
gen->SetReturnAddress(self);
|
||||
}
|
||||
|
||||
void CScriptHandle_AssignVar_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
void *ref = gen->GetArgAddress(0);
|
||||
int typeId = gen->GetArgTypeId(0);
|
||||
CScriptHandle *self = reinterpret_cast<CScriptHandle*>(gen->GetObject());
|
||||
self->Assign(ref, typeId);
|
||||
gen->SetReturnAddress(self);
|
||||
}
|
||||
|
||||
void CScriptHandle_Equals_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptHandle *other = reinterpret_cast<CScriptHandle*>(gen->GetArgAddress(0));
|
||||
CScriptHandle *self = reinterpret_cast<CScriptHandle*>(gen->GetObject());
|
||||
gen->SetReturnByte(*self == *other);
|
||||
}
|
||||
|
||||
void CScriptHandle_EqualsVar_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
void *ref = gen->GetArgAddress(0);
|
||||
int typeId = gen->GetArgTypeId(0);
|
||||
CScriptHandle *self = reinterpret_cast<CScriptHandle*>(gen->GetObject());
|
||||
gen->SetReturnByte(self->Equals(ref, typeId));
|
||||
}
|
||||
|
||||
void CScriptHandle_EnumReferences_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptHandle *self = reinterpret_cast<CScriptHandle*>(gen->GetObject());
|
||||
self->EnumReferences(gen->GetEngine());
|
||||
}
|
||||
|
||||
void CScriptHandle_ReleaseReferences_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptHandle *self = reinterpret_cast<CScriptHandle*>(gen->GetObject());
|
||||
self->ReleaseReferences(gen->GetEngine());
|
||||
}
|
||||
|
||||
void RegisterScriptHandle_Generic(asIScriptEngine *engine)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = engine->RegisterObjectType("ref", sizeof(CScriptHandle), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asOBJ_APP_CLASS_CDAK); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("ref", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(CScriptHandle_Construct_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("ref", asBEHAVE_CONSTRUCT, "void f(const ref &in)", asFUNCTION(CScriptHandle_ConstructCopy_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("ref", asBEHAVE_CONSTRUCT, "void f(const ?&in)", asFUNCTION(CScriptHandle_ConstructVar_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("ref", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(CScriptHandle_Destruct_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("ref", asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(CScriptHandle_EnumReferences_Generic), asCALL_GENERIC); assert(r >= 0);
|
||||
r = engine->RegisterObjectBehaviour("ref", asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(CScriptHandle_ReleaseReferences_Generic), asCALL_GENERIC); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("ref", "void opCast(?&out)", asFUNCTION(CScriptHandle_Cast_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("ref", "ref &opHndlAssign(const ref &in)", asFUNCTION(CScriptHandle_Assign_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("ref", "ref &opHndlAssign(const ?&in)", asFUNCTION(CScriptHandle_AssignVar_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("ref", "bool opEquals(const ref &in) const", asFUNCTION(CScriptHandle_Equals_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("ref", "bool opEquals(const ?&in) const", asFUNCTION(CScriptHandle_EqualsVar_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
}
|
||||
|
||||
void RegisterScriptHandle(asIScriptEngine *engine)
|
||||
{
|
||||
if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") )
|
||||
RegisterScriptHandle_Generic(engine);
|
||||
else
|
||||
RegisterScriptHandle_Native(engine);
|
||||
}
|
||||
|
||||
|
||||
END_AS_NAMESPACE
|
|
@ -0,0 +1,69 @@
|
|||
#ifndef SCRIPTHANDLE_H
|
||||
#define SCRIPTHANDLE_H
|
||||
|
||||
#ifndef ANGELSCRIPT_H
|
||||
// Avoid having to inform include path if header is already include before
|
||||
#include <angelscript.h>
|
||||
#endif
|
||||
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
class CScriptHandle
|
||||
{
|
||||
public:
|
||||
// Constructors
|
||||
CScriptHandle();
|
||||
CScriptHandle(const CScriptHandle &other);
|
||||
CScriptHandle(void *ref, asITypeInfo *type);
|
||||
~CScriptHandle();
|
||||
|
||||
// Copy the stored value from another any object
|
||||
CScriptHandle &operator=(const CScriptHandle &other);
|
||||
|
||||
// Set the reference
|
||||
void Set(void *ref, asITypeInfo *type);
|
||||
|
||||
// Compare equalness
|
||||
bool operator==(const CScriptHandle &o) const;
|
||||
bool operator!=(const CScriptHandle &o) const;
|
||||
bool Equals(void *ref, int typeId) const;
|
||||
|
||||
// Dynamic cast to desired handle type
|
||||
void Cast(void **outRef, int typeId);
|
||||
|
||||
// Returns the type of the reference held
|
||||
asITypeInfo *GetType() const;
|
||||
int GetTypeId() const;
|
||||
|
||||
// Get the reference
|
||||
void *GetRef();
|
||||
|
||||
// GC callback
|
||||
void EnumReferences(asIScriptEngine *engine);
|
||||
void ReleaseReferences(asIScriptEngine *engine);
|
||||
|
||||
protected:
|
||||
// These functions need to have access to protected
|
||||
// members in order to call them from the script engine
|
||||
friend void Construct(CScriptHandle *self, void *ref, int typeId);
|
||||
friend void RegisterScriptHandle_Native(asIScriptEngine *engine);
|
||||
friend void CScriptHandle_AssignVar_Generic(asIScriptGeneric *gen);
|
||||
|
||||
void ReleaseHandle();
|
||||
void AddRefHandle();
|
||||
|
||||
// These shouldn't be called directly by the
|
||||
// application as they requires an active context
|
||||
CScriptHandle(void *ref, int typeId);
|
||||
CScriptHandle &Assign(void *ref, int typeId);
|
||||
|
||||
void *m_ref;
|
||||
asITypeInfo *m_type;
|
||||
};
|
||||
|
||||
void RegisterScriptHandle(asIScriptEngine *engine);
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,119 @@
|
|||
#ifdef TESTS_BUILD
|
||||
#include "../../extern/catch.hpp"
|
||||
#include "../../src/Battling/Pokemon/CreatePokemon.hpp"
|
||||
#include "../../src/ScriptResolving/AngelScript/AngelScripResolver.hpp"
|
||||
#include "../TestLibrary/TestLibrary.hpp"
|
||||
|
||||
#define AS_CLASS(name, contents) { #name, "class " #name " : PkmnScript { " contents "}" }
|
||||
|
||||
static std::unordered_map<const char*, const char*> _scripts = std::unordered_map<const char*, const char*> {
|
||||
AS_CLASS(blankScript, ),
|
||||
AS_CLASS( stackScript, "int value = 0; void Stack() override { value++; } int GetValue() { return value; }"),
|
||||
{"doubleInheritanceScript", R"(
|
||||
class doubleInheritanceScriptBase : PkmnScript {
|
||||
int value = 0;
|
||||
void Stack() override{
|
||||
value++;
|
||||
}
|
||||
|
||||
int GetValue(){ return value; }
|
||||
}
|
||||
class doubleInheritanceScript : doubleInheritanceScriptBase {}
|
||||
)"},
|
||||
AS_CLASS( preventAttackScript, R"(
|
||||
void PreventAttack(ExecutingMove@ attack, bool& result) override{
|
||||
result = !result;
|
||||
})"),
|
||||
AS_CLASS( stopBeforeAttackScript, R"(
|
||||
void StopBeforeAttack(ExecutingMove@ attack, bool& result) override{
|
||||
result = !result;
|
||||
})"),
|
||||
|
||||
};
|
||||
|
||||
static const char* _testLoadFunc(const char* name) { return _scripts[name]; }
|
||||
|
||||
static AngelScripResolver* _resolverCache = nullptr;
|
||||
static AngelScripResolver* GetScriptResolver(PkmnLib::Battling::BattleLibrary* mainLib) {
|
||||
if (_resolverCache == nullptr) {
|
||||
_resolverCache = dynamic_cast<AngelScripResolver*>(PkmnLib::Battling::BattleLibrary::CreateScriptResolver());
|
||||
_resolverCache->Initialize(mainLib);
|
||||
_resolverCache->SetCreateFunction(&_testLoadFunc);
|
||||
for (auto kv : _scripts) {
|
||||
_resolverCache->CreateScript(kv.first);
|
||||
}
|
||||
_resolverCache->FinalizeModule();
|
||||
}
|
||||
return _resolverCache;
|
||||
}
|
||||
|
||||
static AngelScriptScript* GetScript(PkmnLib::Battling::BattleLibrary* mainLib, const char* scriptName) {
|
||||
auto lib = GetScriptResolver(mainLib);
|
||||
auto s = lib->LoadScript(AngelScripResolver::ScriptCategory::Creature, scriptName);
|
||||
auto script = dynamic_cast<AngelScriptScript*>(s);
|
||||
return script;
|
||||
}
|
||||
|
||||
TEST_CASE("Invoke non-implemented script function") {
|
||||
auto mainLib = TestLibrary::GetLibrary();
|
||||
auto script = GetScript(mainLib, "blankScript");
|
||||
script->Stack();
|
||||
delete script;
|
||||
}
|
||||
|
||||
TEST_CASE("Invoke Stack script function") {
|
||||
auto mainLib = TestLibrary::GetLibrary();
|
||||
auto script = GetScript(mainLib, "stackScript");
|
||||
for (int i = 1; i <= 10; i++) {
|
||||
script->Stack();
|
||||
|
||||
auto ctxPool = script->GetContextPool();
|
||||
auto ctx = ctxPool->RequestContext();
|
||||
script->PrepareMethod("GetValue", ctx);
|
||||
REQUIRE(ctx->Execute() == asEXECUTION_FINISHED);
|
||||
REQUIRE(ctx->GetReturnDWord() == i);
|
||||
ctxPool->ReturnContextToPool(ctx);
|
||||
}
|
||||
|
||||
delete script;
|
||||
}
|
||||
|
||||
TEST_CASE("Invoke Stack script function with implementation in base class") {
|
||||
auto mainLib = TestLibrary::GetLibrary();
|
||||
auto script = GetScript(mainLib, "doubleInheritanceScript");
|
||||
for (int i = 1; i <= 10; i++) {
|
||||
script->Stack();
|
||||
|
||||
auto ctxPool = script->GetContextPool();
|
||||
auto ctx = ctxPool->RequestContext();
|
||||
script->PrepareMethod("GetValue", ctx);
|
||||
REQUIRE(ctx->Execute() == asEXECUTION_FINISHED);
|
||||
REQUIRE(ctx->GetReturnDWord() == i);
|
||||
ctxPool->ReturnContextToPool(ctx);
|
||||
}
|
||||
|
||||
delete script;
|
||||
}
|
||||
|
||||
TEST_CASE("Invoke preventAttackScript script function") {
|
||||
auto mainLib = TestLibrary::GetLibrary();
|
||||
auto script = GetScript(mainLib, "preventAttackScript");
|
||||
bool b = false;
|
||||
script->PreventAttack(nullptr, &b);
|
||||
REQUIRE(b);
|
||||
|
||||
delete script;
|
||||
}
|
||||
|
||||
TEST_CASE("Invoke StopBeforeAttack script function") {
|
||||
auto mainLib = TestLibrary::GetLibrary();
|
||||
auto script = GetScript(mainLib, "stopBeforeAttackScript");
|
||||
bool b = false;
|
||||
script->StopBeforeAttack(nullptr, &b);
|
||||
REQUIRE(b);
|
||||
|
||||
delete script;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
|
@ -89,41 +89,4 @@ TEST_CASE("Build script resolver, create object, invoke addition method") {
|
|||
delete lib;
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("Test whether species object was properly registered.") {
|
||||
auto lib = dynamic_cast<AngelScripResolver*>(PkmnLib::Battling::BattleLibrary::CreateScriptResolver());
|
||||
auto mainLib = TestLibrary::GetLibrary();
|
||||
lib->Initialize(mainLib);
|
||||
lib->SetCreateFunction(&_testLoadFunc);
|
||||
lib->CreateScript("testScript1");
|
||||
lib->FinalizeModule();
|
||||
auto species = mainLib->GetSpeciesLibrary()->GetPkmnSpecies("testSpecies2");
|
||||
|
||||
auto obj =
|
||||
dynamic_cast<AngelScriptScript*>(lib->LoadScript(AngelScripResolver::ScriptCategory::Creature, "testScript1"));
|
||||
|
||||
auto ctxPool = obj->GetContextPool();
|
||||
auto ctx = ctxPool->RequestContext();
|
||||
|
||||
obj->PrepareMethod("testFunc2", ctx);
|
||||
ctx->SetArgObject(0, const_cast<PkmnLib::Library::PokemonSpecies*>(species));
|
||||
auto result = ctx->Execute();
|
||||
if (result == asEXECUTION_EXCEPTION){
|
||||
FAIL(ctx->GetExceptionString());
|
||||
}
|
||||
ctx->Unprepare();
|
||||
|
||||
species = mainLib->GetSpeciesLibrary()->GetPkmnSpecies("testSpecies");
|
||||
|
||||
obj->PrepareMethod("testFunc2", ctx);
|
||||
ctx->SetArgObject(0, const_cast<PkmnLib::Library::PokemonSpecies*>(species));
|
||||
result = ctx->Execute();
|
||||
REQUIRE(result == asEXECUTION_EXCEPTION);
|
||||
|
||||
ctxPool->ReturnContextToPool(ctx);
|
||||
delete obj;
|
||||
delete lib;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue