Fixed spelling error in AngelScriptResolver name.
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
268
src/ScriptResolving/AngelScript/AngelScriptResolver.cpp
Normal file
268
src/ScriptResolving/AngelScript/AngelScriptResolver.cpp
Normal file
@@ -0,0 +1,268 @@
|
||||
#include "AngelScriptResolver.hpp"
|
||||
#include <CreatureLib/Battling/Models/Creature.hpp>
|
||||
#include <cassert>
|
||||
#include <regex>
|
||||
#include "../../../extern/angelscript_addons/scripthandle/scripthandle.h"
|
||||
#include "../../../extern/angelscript_addons/scripthelper/scripthelper.h"
|
||||
#include "../../../extern/angelscript_addons/scriptstdstring/scriptstdstring.h"
|
||||
#include "../../Battling/PkmnScriptCategory.hpp"
|
||||
#include "ByteCodeHandling/FileByteCodeStream.hpp"
|
||||
#include "ByteCodeHandling/MemoryByteCodeStream.hpp"
|
||||
#include "TypeRegistry/BasicScriptClass.hpp"
|
||||
#include "TypeRegistry/Battling/RegisterBattleClass.hpp"
|
||||
#include "TypeRegistry/Battling/RegisterBattleLibrary.hpp"
|
||||
#include "TypeRegistry/Battling/RegisterExecutingAttack.hpp"
|
||||
#include "TypeRegistry/Battling/RegisterPokemonClass.hpp"
|
||||
#include "TypeRegistry/Battling/RegisterTurnChoices.hpp"
|
||||
#include "TypeRegistry/ConstString.hpp"
|
||||
#include "TypeRegistry/Library/RegisterEffectParameter.hpp"
|
||||
#include "TypeRegistry/Library/RegisterGrowthRateTypes.hpp"
|
||||
#include "TypeRegistry/Library/RegisterItemTypes.hpp"
|
||||
#include "TypeRegistry/Library/RegisterMoveTypes.hpp"
|
||||
#include "TypeRegistry/Library/RegisterSpeciesTypes.hpp"
|
||||
#include "TypeRegistry/Library/RegisterStaticLibraryTypes.hpp"
|
||||
#include "TypeRegistry/Library/RegisterTypeLibrary.hpp"
|
||||
|
||||
CreatureLib::Battling::ScriptResolver* PkmnLib::Battling::BattleLibrary::CreateScriptResolver() {
|
||||
return new AngelScriptResolver();
|
||||
}
|
||||
|
||||
static void TranslateException(asIScriptContext* ctx, void* /*userParam*/) {
|
||||
try {
|
||||
// Retrow the original exception so we can catch it again
|
||||
throw;
|
||||
} catch (std::exception& e) {
|
||||
// Tell the VM the type of exception that occurred
|
||||
ctx->SetException(e.what());
|
||||
} catch (...) {
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
||||
void AngelScriptResolver::Initialize(CreatureLib::Battling::BattleLibrary* arg) {
|
||||
for (auto scriptCategory : ScriptCategoryHelper::GetValues()) {
|
||||
_typeDatabase.Insert(scriptCategory, {});
|
||||
}
|
||||
for (auto scriptCategory : PkmnScriptCategoryHelper::GetValues()) {
|
||||
_typeDatabase.Insert(static_cast<ScriptCategory>(scriptCategory), {});
|
||||
}
|
||||
|
||||
auto library = (PkmnLib::Battling::BattleLibrary*)arg;
|
||||
_engine = asCreateScriptEngine();
|
||||
_engine->SetTranslateAppExceptionCallback(asFUNCTION(TranslateException), 0, asCALL_CDECL);
|
||||
|
||||
int32_t r = _engine->SetMessageCallback(asFUNCTION(MessageCallback), nullptr, asCALL_CDECL);
|
||||
if (r < 0)
|
||||
throw CreatureException("Registering message callback failed.");
|
||||
|
||||
_engine->SetEngineProperty(asEP_DISALLOW_EMPTY_LIST_ELEMENTS, 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);
|
||||
_engine->SetEngineProperty(asEP_COMPILER_WARNINGS, 2);
|
||||
|
||||
RegisterStdString(_engine);
|
||||
ConstStringRegister::Register(_engine);
|
||||
|
||||
// Register Script Array type
|
||||
RegisterScriptArray(_engine, true);
|
||||
|
||||
r = _engine->RegisterGlobalFunction("void print(const string &in)", asFUNCTION(Print), asCALL_CDECL);
|
||||
if (r < 0)
|
||||
throw CreatureException("Registering print function failed.");
|
||||
RegisterScriptHandle(_engine);
|
||||
|
||||
_builder.StartNewModule(_engine, "pkmn");
|
||||
_mainModule = _builder.GetModule();
|
||||
|
||||
RegisterTypes();
|
||||
RegisterExceptionRoutines(_engine);
|
||||
|
||||
auto staticLib = library->GetStaticLib();
|
||||
_engine->RegisterGlobalProperty("const StaticLibrary@ StaticLib", &staticLib);
|
||||
|
||||
_contextPool = new ContextPool(_engine);
|
||||
}
|
||||
|
||||
void AngelScriptResolver::RegisterTypes() {
|
||||
// Register static library types
|
||||
RegisterSpeciesTypes::Register(_engine);
|
||||
RegisterItemTypes::Register(_engine);
|
||||
RegisterMoveTypes::Register(_engine);
|
||||
RegisterGrowthRateTypes::Register(_engine);
|
||||
RegisterTypeLibrary::Register(_engine);
|
||||
RegisterStaticLibraryTypes::Register(_engine);
|
||||
RegisterEffectParameter::Register(_engine);
|
||||
|
||||
// Register battle types
|
||||
RegisterPokemonClass::Register(_engine);
|
||||
RegisterExecutingAttack::Register(_engine);
|
||||
RegisterTurnChoices::Register(_engine);
|
||||
RegisterBattleLibrary::Register(_engine);
|
||||
RegisterBattleClass::Register(_engine);
|
||||
[[maybe_unused]] int r =
|
||||
_engine->RegisterObjectMethod("Pokemon", "const Battle@ get_Battle() const property",
|
||||
asMETHOD(CreatureLib::Battling::Creature, GetBattle), asCALL_THISCALL);
|
||||
assert(r >= 0);
|
||||
|
||||
// Register base script
|
||||
BasicScriptClass::Register(_engine);
|
||||
}
|
||||
|
||||
void AngelScriptResolver::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* AngelScriptResolver::LoadScript(ScriptCategory category, const ConstString& scriptName) {
|
||||
Dictionary<ConstString, AngelScriptTypeInfo*> innerDb;
|
||||
if (!_typeDatabase.TryGet(category, innerDb)) {
|
||||
_typeDatabase.Insert(category, innerDb);
|
||||
return nullptr;
|
||||
}
|
||||
AngelScriptTypeInfo* t;
|
||||
if (!innerDb.TryGet(scriptName, t)) {
|
||||
innerDb.Insert(scriptName, nullptr);
|
||||
return nullptr;
|
||||
}
|
||||
if (t == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
auto ctx = _contextPool->RequestContext();
|
||||
auto obj = t->Instantiate(ctx);
|
||||
_contextPool->ReturnContextToPool(ctx);
|
||||
return new AngelScriptScript(this, t, obj, _contextPool);
|
||||
}
|
||||
void AngelScriptResolver::FinalizeModule() {
|
||||
int r = _builder.BuildModule();
|
||||
if (r < 0)
|
||||
throw CreatureException("Building Script Module failed.");
|
||||
asUINT count = _mainModule->GetObjectTypeCount();
|
||||
std::regex metadataMatcher(R"(^\s*(\w+)([\w\s=]*)$)", std::regex_constants::icase);
|
||||
std::regex variableMatcher(R"(\s*(\w+)=(\w+))", std::regex_constants::icase);
|
||||
std::smatch base_match;
|
||||
|
||||
for (asUINT n = 0; n < count; n++) {
|
||||
auto typeInfo = _mainModule->GetObjectTypeByIndex(n);
|
||||
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 metadataKind = Arbutils::CaseInsensitiveConstString(base_match[1].str());
|
||||
auto metadataVariables = base_match[2].str();
|
||||
if (!std::regex_match(metadataVariables, base_match, variableMatcher)) {
|
||||
continue;
|
||||
}
|
||||
ConstString effectName;
|
||||
for (size_t variableIndex = 1; variableIndex < base_match.size(); variableIndex += 2) {
|
||||
if (Arbutils::CaseInsensitiveConstString::GetHash(base_match[variableIndex]) == "effect"_cnc) {
|
||||
auto val = base_match[variableIndex + 1].str();
|
||||
effectName = ConstString(val);
|
||||
}
|
||||
}
|
||||
if (effectName.Empty()) {
|
||||
continue;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void AngelScriptResolver::CreateScript(const char* name, const char* script) {
|
||||
_builder.AddSectionFromMemory(name, script);
|
||||
}
|
||||
void AngelScriptResolver::WriteByteCodeToFile(const char* file, bool stripDebugInfo) {
|
||||
FILE* wFile = nullptr;
|
||||
wFile = fopen(file, "wb");
|
||||
AssertNotNull(wFile);
|
||||
auto stream = new FileByteCodeStream(wFile);
|
||||
_mainModule->SaveByteCode(stream, stripDebugInfo);
|
||||
Assert(fclose(wFile) == 0);
|
||||
delete stream;
|
||||
}
|
||||
void AngelScriptResolver::LoadByteCodeFromFile(
|
||||
const char* file, const Dictionary<ScriptCategory, Dictionary<ConstString, const char*>>& types) {
|
||||
FILE* rFile = nullptr;
|
||||
rFile = fopen(file, "rb");
|
||||
AssertNotNull(rFile);
|
||||
auto stream = new FileByteCodeStream(rFile);
|
||||
InitializeByteCode(stream, types);
|
||||
Assert(fclose(rFile) == 0);
|
||||
delete stream;
|
||||
}
|
||||
uint8_t* AngelScriptResolver::WriteByteCodeToMemory(size_t& size, bool stripDebugInfo) {
|
||||
auto stream = new MemoryByteCodeStream();
|
||||
auto result = _mainModule->SaveByteCode(stream, stripDebugInfo);
|
||||
Assert(result == asSUCCESS);
|
||||
auto arr = stream->GetOut();
|
||||
size = stream->GetWrittenSize();
|
||||
arr = static_cast<uint8_t*>(realloc(arr, size * sizeof(uint8_t)));
|
||||
delete stream;
|
||||
return arr;
|
||||
}
|
||||
void AngelScriptResolver::LoadByteCodeFromMemory(
|
||||
uint8_t* byte, size_t size, const Dictionary<ScriptCategory, Dictionary<ConstString, const char*>>& types) {
|
||||
auto stream = new MemoryByteCodeStream(byte, size);
|
||||
InitializeByteCode(stream, types);
|
||||
delete stream;
|
||||
}
|
||||
void AngelScriptResolver::InitializeByteCode(
|
||||
asIBinaryStream* stream, const Dictionary<ScriptCategory, Dictionary<ConstString, const char*>>& types) {
|
||||
int result = _mainModule->LoadByteCode(stream);
|
||||
Assert(result == asSUCCESS);
|
||||
|
||||
auto typeCount = _mainModule->GetObjectTypeCount();
|
||||
Dictionary<uint32_t, asITypeInfo*> objectTypes;
|
||||
for (asUINT i = 0; i < typeCount; i++) {
|
||||
auto t = _mainModule->GetObjectTypeByIndex(i);
|
||||
objectTypes.Insert(ConstString::GetHash(t->GetName()), t);
|
||||
}
|
||||
Dictionary<ScriptCategory, Dictionary<ConstString, AngelScriptTypeInfo*>> typeDatabase;
|
||||
for (auto& innerDb : types) {
|
||||
Dictionary<ConstString, AngelScriptTypeInfo*> newInnerDb;
|
||||
for (auto& val : innerDb.second) {
|
||||
auto decl = val.second;
|
||||
auto type = objectTypes[ConstString::GetHash(decl)];
|
||||
newInnerDb.Insert(val.first, new AngelScriptTypeInfo(val.first, type));
|
||||
}
|
||||
typeDatabase.Insert(innerDb.first, newInnerDb);
|
||||
}
|
||||
_typeDatabase = typeDatabase;
|
||||
}
|
||||
Reference in New Issue
Block a user