Added Service Scripp Module

This commit is contained in:
Chewico 2025-05-30 23:28:01 +02:00
parent b623fddd26
commit 7adbc97ff2
34 changed files with 472 additions and 27 deletions

View File

@ -14,6 +14,8 @@
#define DEER_VOXEL_TEXTURE_PATH "voxels/textures"
#define DEER_VOXEL_SHADER_PATH "voxels/shaders"
#define DEER_EDITOR_PATH "Editor"
#define DEER_EDITOR_PANEL_PATH "Editor/DockPanelModules"
#define DEER_EDITOR_SERVICE_PATH "Editor/ScriptServiceModules"
#define DEER_MESH_PATH "meshes"
#define DEER_MESH_EXTENSION ".dmesh"

View File

@ -49,10 +49,10 @@ namespace Deer {
#define DEER_SCRIPT_ERROR(...) Deer::Log::getScriptLogger()->error(__VA_ARGS__)
#define DEER_UI_ENGINE_TRACE(...) Deer::Log::getEditorEngineLogger()->trace(__VA_ARGS__)
#define DEER_UI_ENGINE_INFO(...) Deer::Log::getEditorEngineLogger()->info(__VA_ARGS__)
#define DEER_UI_ENGINE_WARN(...) Deer::Log::getEditorEngineLogger()->warn(__VA_ARGS__)
#define DEER_UI_ENGINE_ERROR(...) Deer::Log::getEditorEngineLogger()->error(__VA_ARGS__)
#define DEER_EDITOR_ENGINE_TRACE(...) Deer::Log::getEditorEngineLogger()->trace(__VA_ARGS__)
#define DEER_EDITOR_ENGINE_INFO(...) Deer::Log::getEditorEngineLogger()->info(__VA_ARGS__)
#define DEER_EDITOR_ENGINE_WARN(...) Deer::Log::getEditorEngineLogger()->warn(__VA_ARGS__)
#define DEER_EDITOR_ENGINE_ERROR(...) Deer::Log::getEditorEngineLogger()->error(__VA_ARGS__)
#ifdef LINUX
#define DEER_CORE_ASSERT(condition, ...) \

View File

@ -12,6 +12,7 @@ namespace Deer {
namespace EditorEngine {
class DockPanelContext;
class DockPanelObject;
class ServiceScriptContext;
void initialize();
void deinitialize();
@ -22,15 +23,17 @@ namespace Deer {
// Panels
extern asIScriptEngine* scriptEngine;
extern asIScriptContext* executingScriptContext;
extern CScriptBuilder dockPanelScriptBuilder;
extern CScriptBuilder scriptBuilder;
extern std::vector<DockPanelContext> dockPanelModules;
extern std::vector<ServiceScriptContext> serviceScriptModules;
extern DockPanelObject* currentDockPanelExecution;
void loadDockPanels();
void loadServiceScripts();
void registerEditorEngineFunctions();
void registerEditorEngineStructs();
void registerDockPanel();
}
namespace DataStore {

View File

@ -18,6 +18,11 @@ namespace Deer {
RegisterScriptHandle(scriptEngine);
RegisterScriptAny(scriptEngine);
AS_RET_CHECK(scriptEngine->RegisterInterface("DockPanel"));
AS_RET_CHECK(scriptEngine->RegisterInterfaceMethod("DockPanel", "void onRender()"));
AS_RET_CHECK(scriptEngine->RegisterInterface("ServiceScript"));
AS_CHECK(scriptEngine->RegisterFuncdef("void ReciverFunc(any@)"));
AS_CHECK(scriptEngine->RegisterFuncdef("void TransferFunc(any@, any@)"));
@ -27,13 +32,6 @@ namespace Deer {
registerMathStructs();
registerFrameBufferStructs();
registerEnvironmentStructs();
registerDockPanel();
}
void registerDockPanel() {
AS_RET_CHECK(scriptEngine->RegisterInterface("DockPanel"));
AS_RET_CHECK(scriptEngine->RegisterInterfaceMethod("DockPanel", "void onRender()"));
}
}

View File

@ -56,9 +56,6 @@ namespace Deer {
isValid = true;
int refCount = object->AddRef(); // increments refcount by 1
refCount = object->Release();
scriptContext->Unprepare();
}

View File

@ -19,7 +19,7 @@ namespace fs = std::filesystem;
namespace Deer {
namespace EditorEngine {
CScriptBuilder dockPanelScriptBuilder;
CScriptBuilder scriptBuilder;
}
void EditorEngine::loadDockPanels() {
@ -47,7 +47,7 @@ namespace Deer {
continue;
}
int r; r = dockPanelScriptBuilder.StartNewModule(scriptEngine, dockPanelInfo->name.c_str());
int r; r = scriptBuilder.StartNewModule(scriptEngine, dockPanelInfo->name.c_str());
if (r < 0) {
DEER_EDITOR_ENGINE_ERROR("Failed to create module for dock panel module {0}", path.string().c_str());
delete dockPanelInfo;
@ -56,14 +56,14 @@ namespace Deer {
for (const auto& entry : fs::recursive_directory_iterator(_dir)) {
if (entry.is_regular_file() && entry.path().extension() == ".as") {
r = dockPanelScriptBuilder.AddSectionFromFile(entry.path().string().c_str());
r = scriptBuilder.AddSectionFromFile(entry.path().string().c_str());
if (r < 0) {
DEER_EDITOR_ENGINE_ERROR("Failed loading script for module {0}\nscript: {1}", path.string().c_str(), entry.path().string().c_str());
}
}
}
r = dockPanelScriptBuilder.BuildModule();
r = scriptBuilder.BuildModule();
if (r < 0) {
DEER_EDITOR_ENGINE_ERROR("Failed compiling module {0}", path.string().c_str());
delete dockPanelInfo;

View File

@ -4,6 +4,7 @@
#include "DeerStudio/EditorEngine/DockPanel/DockPanelObject.h"
#include "DeerStudio/EditorEngine/DockPanel/DockPanelContext.h"
#include "DeerStudio/EditorEngine/ServiceScript/ServiceScriptContext.h"
#include "DeerStudio/EditorEngine.h"
#include "Deer/Log.h"
@ -22,6 +23,7 @@ namespace Deer {
asIScriptEngine* scriptEngine = nullptr;
std::vector<DockPanelContext> dockPanelModules;
std::vector<ServiceScriptContext> serviceScriptModules;
DockPanelObject* currentDockPanelExecution = nullptr;
asIScriptContext* executingScriptContext;
@ -49,9 +51,14 @@ namespace Deer {
// This is simply to generate the as.predefined for better experience
extract_angelScript();
loadServiceScripts();
loadDockPanels();
active = true;
for (ServiceScriptContext& service : serviceScriptModules) {
service.init();
}
for (DockPanelContext& pannel : dockPanelModules)
pannel.init();
@ -59,6 +66,7 @@ namespace Deer {
void EditorEngine::deinitialize() {
dockPanelModules.clear();
serviceScriptModules.clear();
if (scriptEngine)
scriptEngine->ShutDownAndRelease();

View File

@ -0,0 +1,71 @@
#include "DeerStudio/EditorEngine.h"
#include "DeerStudio/EditorEngine/ServiceScript/ServiceScriptContext.h"
#include "DeerStudio/EditorEngine/ServiceScript/ServiceScriptInfo.h"
#include "DeerStudio/EditorEngine/ErrorHandle.h"
#include "Deer/Log.h"
#include "Deer/Path.h"
#include "Deer/DataStore.h"
#include "angelscript.h"
#include "scriptbuilder.h"
#include <iostream>
#include <filesystem>
#include <vector>
#include <string>
namespace fs = std::filesystem;
namespace Deer {
void EditorEngine::loadServiceScripts() {
Path path = DataStore::rootPath / DEER_EDITOR_SERVICE_PATH;
if (!fs::exists(path) || !fs::is_directory(path)) {
DEER_EDITOR_ENGINE_ERROR("Could not find folder " DEER_EDITOR_SERVICE_PATH);
return;
}
for (const auto& _dir : fs::directory_iterator(path)) {
Path panelInfo_path = _dir.path() / "ServiceScript.json";
// A panel info is neded to load a panel
if (!fs::exists(panelInfo_path) || !fs::is_regular_file(panelInfo_path)) {
DEER_EDITOR_ENGINE_WARN("Editor engine did not find ServiceScript.json in folder {0}", panelInfo_path.c_str());
continue;
}
ServiceScriptInfo* serviceScriptInfo = loadServiceScriptInfo(panelInfo_path);
if (serviceScriptInfo->name == "null") {
DEER_EDITOR_ENGINE_ERROR("Failed to load service script module from {0},\n incorrect ServiceScript.json file", path.string().c_str());
delete serviceScriptInfo;
continue;
}
int r; r = scriptBuilder.StartNewModule(scriptEngine, serviceScriptInfo->name.c_str());
if (r < 0) {
DEER_EDITOR_ENGINE_ERROR("Failed to create module for service script module {0}", path.string().c_str());
delete serviceScriptInfo;
continue;
}
for (const auto& entry : fs::recursive_directory_iterator(_dir)) {
if (entry.is_regular_file() && entry.path().extension() == ".as") {
r = scriptBuilder.AddSectionFromFile(entry.path().string().c_str());
if (r < 0) {
DEER_EDITOR_ENGINE_ERROR("Failed loading script for module {0}\nscript: {1}", path.string().c_str(), entry.path().string().c_str());
}
}
}
r = scriptBuilder.BuildModule();
if (r < 0) {
DEER_EDITOR_ENGINE_ERROR("Failed compiling module {0}", path.string().c_str());
delete serviceScriptInfo;
continue;
}
serviceScriptModules.push_back(ServiceScriptContext(scriptEngine->GetModule(serviceScriptInfo->name.c_str()), serviceScriptInfo));
}
}
}

View File

@ -0,0 +1,41 @@
#include "DeerStudio/EditorEngine/ServiceScript/ServiceScriptInfo.h"
#include "Deer/Log.h"
#include "cereal/cereal.hpp"
#include "cereal/archives/json.hpp"
#include "cereal/types/string.hpp"
#include <filesystem>
#include <fstream>
#include <cstring>
namespace Deer {
namespace EditorEngine {
template <class Archive>
void serialize(Archive& ar, ServiceScriptInfo& data) {
ar(cereal::make_nvp("name", data.name));
ar(cereal::make_nvp("author", data.author));
ar(cereal::make_nvp("version", data.version));
}
ServiceScriptInfo* loadServiceScriptInfo(Path seriveScriptInfoPath) {
try {
std::ifstream is(seriveScriptInfoPath);
if (!is)
return new ServiceScriptInfo();
ServiceScriptInfo* info = new ServiceScriptInfo();
{
cereal::JSONInputArchive archive(is);
archive(cereal::make_nvp("serviceScriptModule", *info));
}
return info;
} catch (const std::exception& e) {
DEER_EDITOR_ENGINE_TRACE(e.what());
return new ServiceScriptInfo();
}
}
}
}

View File

@ -0,0 +1,79 @@
#include "DeerStudio/EditorEngine/ServiceScript/ServiceScriptContext.h"
#include "DeerStudio/EditorEngine/ErrorHandle.h"
#include "DeerStudio/EditorEngine.h"
#include "angelscript.h"
namespace Deer {
namespace EditorEngine {
ServiceScriptContext::ServiceScriptContext(asIScriptModule* _module, ServiceScriptInfo* _info)
: info(_info), module(_module) {
size_t nScripts = module->GetObjectTypeCount();
asITypeInfo* serviceScriptType = scriptEngine->GetTypeInfoByName("ServiceScript");
if (!serviceScriptType) {
DEER_EDITOR_ENGINE_ERROR("Could not load ServiceScript interface type");
return;
}
context = scriptEngine->CreateContext();
context->AddRef();
for (size_t i = 0; i < nScripts; i++) {
asITypeInfo* info = module->GetObjectTypeByIndex(i);
// If it does not implement service script we are not interested int it
if (!info->Implements(serviceScriptType))
continue;
scriptServices.push_back({info, context});
}
}
ServiceScriptContext::~ServiceScriptContext() {
scriptServices.clear();
if (context)
context->Release();
delete info;
}
ServiceScriptContext::ServiceScriptContext(ServiceScriptContext&& o)
: scriptServices(std::move(o.scriptServices)) {
context = o.context;
module = o.module;
info = o.info;
o.context = nullptr;
o.module = nullptr;
o.info = nullptr;
}
ServiceScriptContext& ServiceScriptContext::operator=(ServiceScriptContext&& o) {
if (&o != this) {
scriptServices = std::move(o.scriptServices);
context = o.context;
module = o.module;
info = o.info;
o.context = nullptr;
o.module = nullptr;
o.info = nullptr;
}
return *this;
}
void ServiceScriptContext::update() {
for (auto& scriptService : scriptServices) {
scriptService.update();
}
}
void ServiceScriptContext::init() {
for (auto& scriptService : scriptServices) {
scriptService.init();
}
}
}
}

View File

@ -0,0 +1,34 @@
#pragma once
#include "DeerStudio/EditorEngine/ServiceScript/ServiceScriptInfo.h"
#include "DeerStudio/EditorEngine/ServiceScript/ServiceScriptObject.h"
#include <vector>
class asIScriptModule;
class asIScriptContext;
namespace Deer {
namespace EditorEngine {
class ServiceScriptContext {
public:
ServiceScriptContext(asIScriptModule*, ServiceScriptInfo*);
~ServiceScriptContext();
ServiceScriptContext(ServiceScriptContext&) = delete;
ServiceScriptContext& operator=(ServiceScriptContext&) = delete;
ServiceScriptContext(ServiceScriptContext&&);
ServiceScriptContext& operator=(ServiceScriptContext&&);
void update();
void init();
inline const char* getName() const { return info->name.c_str(); }
std::vector<ServiceScriptObject> scriptServices;
private:
asIScriptContext* context;
asIScriptModule* module;
ServiceScriptInfo* info;
};
}
}

View File

@ -0,0 +1,15 @@
#pragma once
#include "Deer/Path.h"
#include <string>
namespace Deer {
namespace EditorEngine {
struct ServiceScriptInfo {
std::string name = "null";
std::string author = "";
std::string version = "0.0.0";
};
ServiceScriptInfo* loadServiceScriptInfo(Path panelInfo);
}
}

View File

@ -0,0 +1,108 @@
#include "DeerStudio/EditorEngine/ServiceScript/ServiceScriptObject.h"
#include "DeerStudio/EditorEngine/ErrorHandle.h"
#include "DeerStudio/EditorEngine.h"
#include "angelscript.h"
#include <string>
namespace Deer {
namespace EditorEngine {
ServiceScriptObject::ServiceScriptObject(asITypeInfo* _type, asIScriptContext* _scriptContext)
: type(_type), scriptContext(_scriptContext) {
// Constructor
// "type@ type()"
std::string callString;
const std::string ns(type->GetNamespace());
if (ns != "") {
callString += ns;
callString += "::";
}
callString += type->GetName();
callString += "@ ";
if (ns != "") {
callString += ns;
callString += "::";
}
callString += type->GetName();
callString += "()";
asIScriptFunction* factory = type->GetFactoryByDecl(callString.c_str());
AS_CHECK(scriptContext->Prepare(factory));
AS_CHECK(scriptContext->Execute());
// Return value contains the ref to a asIScriptObject in the location provided
object = *(asIScriptObject**)scriptContext->GetAddressOfReturnValue();
if (!object){
DEER_EDITOR_ENGINE_ERROR("Could not create object", type->GetName());
return;
}
object->AddRef();
updateFunction = type->GetMethodByDecl("void onUpdate()");
initFunction = type->GetMethodByDecl("void onInit()");
scriptContext->Unprepare();
}
ServiceScriptObject::~ServiceScriptObject() {
if (object)
object->Release();
}
void ServiceScriptObject::init() {
if (!initFunction)
return;
AS_CHECK(scriptContext->Prepare(initFunction));
AS_CHECK(scriptContext->SetObject(object));
AS_CHECK(scriptContext->Execute());
AS_CHECK(scriptContext->Unprepare());
}
void ServiceScriptObject::update() {
if (!updateFunction)
return;
AS_CHECK(scriptContext->Prepare(updateFunction));
AS_CHECK(scriptContext->SetObject(object));
AS_CHECK(scriptContext->Execute());
AS_CHECK(scriptContext->Unprepare());
}
const char* ServiceScriptObject::getName() {
return type->GetName();
}
ServiceScriptObject::ServiceScriptObject(ServiceScriptObject&& other) noexcept {
type = other.type;
object = other.object;
updateFunction = other.updateFunction;
initFunction = other.initFunction;
scriptContext = other.scriptContext;
other.type = nullptr;
other.object = nullptr;
other.updateFunction = nullptr;
other.initFunction = nullptr;
other.scriptContext = nullptr;
}
ServiceScriptObject& ServiceScriptObject::operator=(ServiceScriptObject&& other) noexcept {
if (&other != this) {
type = other.type;
object = other.object;
updateFunction = other.updateFunction;
initFunction = other.initFunction;
scriptContext = other.scriptContext;
other.type = nullptr;
other.object = nullptr;
other.updateFunction = nullptr;
other.initFunction = nullptr;
other.scriptContext = nullptr;
}
return *this;
}
}
}

View File

@ -0,0 +1,34 @@
#pragma once
#include <stdint.h>
class asITypeInfo;
class asIScriptObject;
class asIScriptFunction;
class asIScriptContext;
namespace Deer {
namespace EditorEngine {
struct ServiceScriptObject {
public:
ServiceScriptObject(asITypeInfo*, asIScriptContext*);
~ServiceScriptObject();
// Delete copy constructor
ServiceScriptObject(const ServiceScriptObject&) = delete;
ServiceScriptObject& operator=(const ServiceScriptObject&) = delete;
ServiceScriptObject(ServiceScriptObject&& other) noexcept;
ServiceScriptObject& operator=(ServiceScriptObject&& other) noexcept;
void init();
void update();
const char* getName();
private:
asITypeInfo* type = nullptr;
asIScriptObject* object = nullptr;
asIScriptFunction* updateFunction = nullptr;
asIScriptFunction* initFunction = nullptr;
asIScriptContext* scriptContext = nullptr;
};
}
}

View File

@ -0,0 +1,7 @@
{
"dockPanelModule" : {
"name" : "Entity Manipulation",
"author" : "Chewico",
"version" : "1.0.0"
}
}

View File

@ -2,6 +2,9 @@ class MeshExplorer : DockPanel {
string currentPath = "";
void onRender() {
if (true)
return;
UI::setupAutomaticColumns(128);
// To avoid problems we will cache the current path

View File

@ -2,12 +2,17 @@ dictionary meshFrameBuffer;
Environment renderEnvironment;
FrameBuffer getMeshFrameBuffer(string mesh) {
if (meshFrameBuffer.exists(mesh)) {
FrameBuffer fb;
any fbAny = cast<any>(meshFrameBuffer[mesh]);
fbAny.retrieve(fb);
return fb;
}
return generateMeshFrameBuffer(mesh);
}
FrameBuffer generateMeshFrameBuffer(string mesh) {
FrameBuffer fb = Engine::createRGBA8FrameBuffer(mesh, 64, 64);
meshFrameBuffer[mesh] = any(fb);
return fb;
}

View File

@ -1,3 +1,4 @@
class ShaderExplorer : DockPanel {
string currentPath = "";

View File

@ -0,0 +1,7 @@
{
"dockPanelModule" : {
"name" : "Explorers",
"author" : "Chewico",
"version" : "1.0.0"
}
}

View File

@ -92,5 +92,4 @@ class ViewportPannel : DockPanel {
void viewportCameraProps(any@ data) {
sceneCamera.camera.fov = UI::slider("Fov", sceneCamera.camera.fov / 3.14f * 180, 10, 160) / 180 * 3.14f;
}
}
}

View File

@ -0,0 +1,7 @@
{
"dockPanelModule" : {
"name" : "Viewport",
"author" : "Chewico",
"version" : "1.0.0"
}
}

View File

@ -0,0 +1,17 @@
class ActiveEntity : ServiceScript {
Entity entity;
void onInit() {
entity = Engine::getMainEnvironment().getRootEntity();
}
[ServiceAPI]
Entity getActiveEntity() {
return entity;
}
[ServiceAPI]
void setActiveEntity(Entity ent) {
entity = ent;
}
}

View File

@ -0,0 +1,7 @@
{
"serviceScriptModule" : {
"name" : "ActiveEntity",
"author" : "Chewico",
"version" : "1.0.0"
}
}

View File

@ -200,6 +200,11 @@ class any {
bool retrieve(int64&out);
bool retrieve(double&out);
}
class DockPanel {
void onRender();
}
class ServiceScript {
}
class Entity {
string get_name() const property;
void set_name(string&in) property;
@ -319,9 +324,6 @@ class Environment {
Entity getRootEntity();
Entity getEntity(int);
}
class DockPanel {
void onRender();
}
string formatInt(int64 val, const string&in options = "", uint width = 0);
string formatUInt(uint64 val, const string&in options = "", uint width = 0);
string formatFloat(double val, const string&in options = "", uint width = 0, uint precision = 0);