inital commit

This commit is contained in:
2023-05-23 02:06:58 +02:00
commit 2a9b6ac9f9
7 changed files with 368 additions and 0 deletions

View File

@ -0,0 +1,124 @@
#include "./plugin.hpp"
// https://youtu.be/RsHGUL5E1_s
#define SOLANA_PLUGIN_HOST
#include "./solana_plugin_v1.h"
#if (defined(_WIN32) || defined(_WIN64))
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#undef WIN32_LEAN_AND_MEAN
#else
#include <dlfcn.h>
#endif
#if defined(_WIN32) || defined(_WIN64)
#define WINDOWS
#elif defined(__APPLE__)
#define APPLE
#else
#define LINUX
#endif
#include <iostream>
#include <cassert>
void* Plugin::loadSymbol(const char* s_name) {
#if defined(_WIN32) || defined(_WIN64)
return GetProcAddress(_dl, s_name);
#else
return dlsym(_dl, s_name);
#endif
}
// loads lib and gets name (and version)
Plugin::Plugin(const char* path) {
#if defined(_WIN32) || defined(_WIN64)
_dl = (void*)LoadLibraryA(path);
#else
_dl = (void*)dlopen(path, RTLD_NOW /*| RTLD_LOCAL*/);
#endif
if (!_dl) {
std::cerr << "PLG opening '" << path << "' failed\n";
return;
}
_fn_name = loadSymbol("solana_plugin_get_name");
_fn_version = loadSymbol("solana_plugin_get_version");
_fn_start = loadSymbol("solana_plugin_start");
_fn_stop = loadSymbol("solana_plugin_stop");
_fn_tick = loadSymbol("solana_plugin_tick");
if (!_fn_name || !_fn_version || !_fn_start || !_fn_stop || !_fn_tick) {
std::cerr << "PLG '" << path << "' misses functions\n";
return;
}
name = reinterpret_cast<decltype(&solana_plugin_get_name)>(_fn_name)();
if (name.empty()) {
std::cerr << "PLG '" << path << "' misses name\n";
return;
}
version = reinterpret_cast<decltype(&solana_plugin_get_version)>(_fn_version)();
if (version != SOLANA_PLUGIN_VERSION) {
std::cerr << "PLG '" << path << "' version mismatch IS:" << version << " SHOULD:" << SOLANA_PLUGIN_VERSION << "\n";
return;
}
valid_plugin = true;
}
Plugin::Plugin(Plugin&& other) {
valid_plugin = other.valid_plugin;
name = other.name;
_dl = other._dl;
other._dl = nullptr;
_fn_name = other._fn_name;
other._fn_name = nullptr;
_fn_start = other._fn_start;
other._fn_start = nullptr;
_fn_stop = other._fn_stop;
other._fn_stop = nullptr;
_fn_tick = other._fn_tick;
other._fn_tick = nullptr;
}
// unloads the plugin
Plugin::~Plugin(void) {
if (_dl != nullptr) {
#if defined(_WIN32) || defined(_WIN64)
FreeLibrary(_dl);
#else
dlclose(_dl);
#endif
}
}
// runs the start function
uint32_t Plugin::start(SolanaAPI* solana_api) const {
assert(valid_plugin);
return reinterpret_cast<decltype(&solana_plugin_start)>(_fn_start)(solana_api);
}
// stop function
void Plugin::stop(void) const {
assert(valid_plugin);
reinterpret_cast<decltype(&solana_plugin_stop)>(_fn_stop)();
}
// tick function
void Plugin::tick(float delta) const {
assert(valid_plugin);
reinterpret_cast<decltype(&solana_plugin_tick)>(_fn_tick)(delta);
}

View File

@ -0,0 +1,47 @@
#pragma once
#include <string>
extern "C" {
struct SolanaAPI;
}
struct Plugin {
bool valid_plugin = false;
std::string name;
uint32_t version;
// void* is platform independent enough, maybe use uint64_t
void* _dl = nullptr;
void* _fn_name = nullptr; // TODO: make variable instead of function?
void* _fn_version = nullptr; // TODO: make variable instead of function?
void* _fn_start = nullptr;
void* _fn_stop = nullptr;
void* _fn_tick = nullptr;
void* loadSymbol(const char* name);
// loads lib and gets name (and version)
Plugin(const char* path);
Plugin(Plugin&& other);
Plugin(const Plugin& other) = delete;
// unloads the plugin
~Plugin(void);
// runs the start function
uint32_t start(SolanaAPI* solana_api) const;
// stop function
void stop(void) const;
// tick function
void tick(float delta) const;
operator bool(void) const {
return valid_plugin;
}
};

View File

@ -0,0 +1,53 @@
#include "./plugin_manager.hpp"
#include <iostream>
// def
std::map<std::string, void*> g_instance_map {};
extern "C" {
void* g_resolveInstance__internal(const char* id) {
if (auto it = g_instance_map.find(id); it != g_instance_map.end()) {
return it->second;
}
return nullptr;
}
void g_provideInstance__internal(const char* id, const char* plugin_name, void* instance) {
g_instance_map[id] = instance;
std::cout << "PLM '" << plugin_name << "' provided '" << id << "'\n";
}
} // extern C
PluginManager::~PluginManager(void) {
// destruct in reverse!
for (auto it = _plugins.rbegin(); it != _plugins.rend(); it++) {
it->stop();
}
}
bool PluginManager::add(const std::string& plug_path) {
Plugin p{plug_path.c_str()};
if (!p) {
return false;
}
if (p.start(&_sapi) != 0) {
return false;
}
_plugins.emplace_back(std::move(p));
return true;
}
void PluginManager::tick(float delta) {
for (const auto& p : _plugins) {
p.tick(delta);
}
}

View File

@ -0,0 +1,44 @@
#pragma once
#define SOLANA_PLUGIN_HOST
#include <solanaceae/plugin/solana_plugin_v1.h>
#include <solanaceae/plugin/plugin.hpp>
#include <vector>
#include <map>
#include <string>
// TODO: save plug name to instance
extern std::map<std::string, void*> g_instance_map;
extern "C" {
void* g_resolveInstance__internal(const char* id);
void g_provideInstance__internal(const char* id, const char* plugin_name, void* instance);
} // extern C
// templated helper, use or make sure vtable is right
template<typename T>
void g_provideInstance(const char* id, const char* plugin_name, T* instance) {
g_provideInstance__internal(id, plugin_name, instance);
}
// only on host!
struct PluginManager {
SolanaAPI _sapi {
&g_resolveInstance__internal,
&g_provideInstance__internal,
};
std::vector<Plugin> _plugins;
~PluginManager(void);
bool add(const std::string& plug_path);
void tick(float delta);
};

View File

@ -0,0 +1,58 @@
#ifndef SOLANA_PLUGIN__H
#define SOLANA_PLUGIN__H
#include <stdint.h>
#define SOLANA_PLUGIN_VERSION 1
#if defined(_MSC_VER) || defined(__MINGW32__)
#define SOLANA_PLUGIN_EXPORT __declspec(dllexport)
#elif defined(__GNUC__) // also clang
#define SOLANA_PLUGIN_EXPORT __attribute__((visibility("default")))
#else
#error unsupported platform
#endif
#if defined(SOLANA_PLUGIN_HOST)
#define SOLANA_PLUGIN_DECL
#else
#define SOLANA_PLUGIN_DECL SOLANA_PLUGIN_EXPORT
#endif
#ifdef __cplusplus
extern "C" {
#endif
// public plugin stuff here
struct SolanaAPI {
void* (*resolveInstance)(const char* id);
// resolve_all_instances(const char* id)
void (*provideInstance)(const char* id, const char* plugin_name, void* instance);
};
// ---------- info ----------
SOLANA_PLUGIN_EXPORT const char* solana_plugin_get_name(void);
// get the SOLANA_PLUGIN_VERSION the plugin was compiled with
SOLANA_PLUGIN_EXPORT uint32_t solana_plugin_get_version(void);
// ---------- plugin control ----------
// return 0 on success
SOLANA_PLUGIN_EXPORT uint32_t solana_plugin_start(struct SolanaAPI* solana_api);
SOLANA_PLUGIN_EXPORT void solana_plugin_stop(void);
// called periodically
SOLANA_PLUGIN_EXPORT void solana_plugin_tick(float delta);
#ifdef __cplusplus
}
#endif
#endif // SOLANA_PLUGIN__H