This commit is contained in:
Perttu Ahola 2014-09-16 20:39:57 +03:00
parent 9406265c5e
commit d355b436e6
17 changed files with 944 additions and 17 deletions

1
.gitignore vendored
View File

@ -4,3 +4,4 @@
*.tar.gz *.tar.gz
/build /build
/cache

View File

@ -1,3 +1,3 @@
cmake_minimum_required(VERSION 2.6) cmake_minimum_required(VERSION 2.6)
project(c55lib) project(c55lib)
add_library(c55lib STATIC c55_getopt.cpp) add_library(c55lib STATIC c55_getopt.cpp c55_filesys.cpp)

344
3rdparty/c55lib/c55_filesys.cpp vendored Normal file
View File

@ -0,0 +1,344 @@
#include "c55_filesys.h"
#include <iostream>
#include <string.h>
namespace c55fs
{
/* "image.png", "png" -> TRUE */
bool checkFileExtension(const char *path, const char *ext)
{
int extlen = strlen(ext);
int pathlen = strlen(path);
if(extlen > pathlen - 1)
return false;
int i;
for(i=0; i<extlen; i++){
if(path[pathlen-1-i] != ext[extlen-1-i])
return false;
}
if(path[pathlen-1-i] != '.')
return false;
return true;
}
std::string stripFileExtension(const std::string &path)
{
int pathlen = path.size();
int i;
for(i=pathlen-1; i>=0; i--){
if(path[i] == '.')
return path.substr(0, i);
}
return "";
}
std::string stripFilename(const std::string &path)
{
int pathlen = path.size();
int i;
for(i=pathlen-1; i>=0; i--){
if(path[i] == '/' || path[i] == '\\')
return path.substr(0, i);
}
return "";
}
#ifdef _WIN32 // WINDOWS
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
#include <malloc.h>
#include <tchar.h>
#include <wchar.h>
#include <stdio.h>
#define BUFSIZE MAX_PATH
std::vector<DirListNode> GetDirListing(std::string pathstring)
{
std::vector<DirListNode> listing;
WIN32_FIND_DATA FindFileData;
HANDLE hFind = INVALID_HANDLE_VALUE;
DWORD dwError;
LPTSTR DirSpec;
INT retval;
DirSpec = (LPTSTR) malloc (BUFSIZE);
if( DirSpec == NULL )
{
printf( "Insufficient memory available\n" );
retval = 1;
goto Cleanup;
}
// Check that the input is not larger than allowed.
if (pathstring.size() > (BUFSIZE - 2))
{
_tprintf(TEXT("Input directory is too large.\n"));
retval = 3;
goto Cleanup;
}
//_tprintf (TEXT("Target directory is %s.\n"), pathstring.c_str());
sprintf(DirSpec, "%s", (pathstring + "\\*").c_str());
// Find the first file in the directory.
hFind = FindFirstFile(DirSpec, &FindFileData);
if (hFind == INVALID_HANDLE_VALUE)
{
_tprintf (TEXT("Invalid file handle. Error is %u.\n"),
GetLastError());
retval = (-1);
}
else
{
// NOTE:
// Be very sure to not include '..' in the results, it will
// result in an epic failure when deleting stuff.
DirListNode node;
node.name = FindFileData.cFileName;
node.dir = FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
if(node.name != "." && node.name != "..")
listing.push_back(node);
// List all the other files in the directory.
while (FindNextFile(hFind, &FindFileData) != 0)
{
DirListNode node;
node.name = FindFileData.cFileName;
node.dir = FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
if(node.name != "." && node.name != "..")
listing.push_back(node);
}
dwError = GetLastError();
FindClose(hFind);
if (dwError != ERROR_NO_MORE_FILES)
{
_tprintf (TEXT("FindNextFile error. Error is %u.\n"),
dwError);
retval = (-1);
goto Cleanup;
}
}
retval = 0;
Cleanup:
free(DirSpec);
if(retval != 0) listing.clear();
//for(unsigned int i=0; i<listing.size(); i++){
// std::cout<<listing[i].name<<(listing[i].dir?" (dir)":" (file)")<<std::endl;
//}
return listing;
}
bool CreateDir(std::string path)
{
bool r = CreateDirectory(path.c_str(), NULL);
if(r == true)
return true;
if(GetLastError() == ERROR_ALREADY_EXISTS)
return true;
return false;
}
bool PathExists(std::string path)
{
return (GetFileAttributes(path.c_str()) != INVALID_FILE_ATTRIBUTES);
}
bool RecursiveDelete(std::string path)
{
std::cerr<<"Removing \""<<path<<"\""<<std::endl;
//return false;
// This silly function needs a double-null terminated string...
// Well, we'll just make sure it has at least two, then.
path += "\0\0";
SHFILEOPSTRUCT sfo;
sfo.hwnd = NULL;
sfo.wFunc = FO_DELETE;
sfo.pFrom = path.c_str();
sfo.pTo = NULL;
sfo.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR;
int r = SHFileOperation(&sfo);
if(r != 0)
std::cerr<<"SHFileOperation returned "<<r<<std::endl;
//return (r == 0);
return true;
}
#else // POSIX
#include <unistd.h>
#include <sys/types.h>
#include <dirent.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/wait.h>
std::vector<DirListNode> GetDirListing(std::string pathstring)
{
std::vector<DirListNode> listing;
DIR *dp;
struct dirent *dirp;
if((dp = opendir(pathstring.c_str())) == NULL) {
//std::cout<<"Error("<<errno<<") opening "<<pathstring<<std::endl;
return listing;
}
while ((dirp = readdir(dp)) != NULL) {
// NOTE:
// Be very sure to not include '..' in the results, it will
// result in an epic failure when deleting stuff.
if(dirp->d_name[0]!='.'){
DirListNode node;
node.name = dirp->d_name;
if(dirp->d_type == DT_DIR) node.dir = true;
else node.dir = false;
if(node.name != "." && node.name != "..")
listing.push_back(node);
}
}
closedir(dp);
return listing;
}
bool CreateDir(std::string path)
{
int r = mkdir(path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
if(r == 0)
{
return true;
}
else
{
// If already exists, return true
if(errno == EEXIST)
return true;
return false;
}
}
bool PathExists(std::string path)
{
struct stat st;
return (stat(path.c_str(),&st) == 0);
}
bool RecursiveDelete(std::string path)
{
/*
Execute the 'rm' command directly, by fork() and execve()
*/
std::cerr<<"Removing \""<<path<<"\""<<std::endl;
//return false;
pid_t child_pid = fork();
if(child_pid == 0)
{
// Child
char argv_data[3][10000];
strcpy(argv_data[0], "/bin/rm");
strcpy(argv_data[1], "-rf");
strncpy(argv_data[2], path.c_str(), 10000);
char *argv[4];
argv[0] = argv_data[0];
argv[1] = argv_data[1];
argv[2] = argv_data[2];
argv[3] = NULL;
std::cerr<<"Executing '"<<argv[0]<<"' '"<<argv[1]<<"' '"
<<argv[2]<<"'"<<std::endl;
execv(argv[0], argv);
// Execv shouldn't return. Failed.
_exit(1);
}
else
{
// Parent
int child_status;
pid_t tpid;
do{
tpid = wait(&child_status);
//if(tpid != child_pid) process_terminated(tpid);
}while(tpid != child_pid);
return (child_status == 0);
}
}
#endif
inline std::string trim(std::string str, const std::string &whitespace=" \t\n\r")
{
size_t endpos = str.find_last_not_of(whitespace);
if(std::string::npos != endpos)
str = str.substr(0, endpos+1);
size_t startpos = str.find_first_not_of(whitespace);
if(std::string::npos != startpos)
str = str.substr(startpos);
return str;
}
bool RecursiveDeleteContent(std::string path)
{
std::cerr<<"Removing content of \""<<path<<"\""<<std::endl;
std::vector<DirListNode> list = GetDirListing(path);
for(unsigned int i=0; i<list.size(); i++)
{
if(trim(list[i].name) == "." || trim(list[i].name) == "..")
continue;
std::string childpath = path + DIR_DELIM + list[i].name;
bool r = RecursiveDelete(childpath);
if(r == false)
{
std::cerr<<"Removing \""<<childpath<<"\" failed"<<std::endl;
return false;
}
}
return true;
}
bool CreateAllDirs(std::string path)
{
size_t pos;
std::vector<std::string> tocreate;
std::string basepath = path;
while(!PathExists(basepath))
{
tocreate.push_back(basepath);
pos = basepath.rfind(DIR_DELIM_C);
if(pos == std::string::npos)
return false;
basepath = basepath.substr(0,pos);
}
for(int i=tocreate.size()-1;i>=0;i--)
CreateDir(tocreate[i]);
return true;
}
} // namespace fs

49
3rdparty/c55lib/c55_filesys.h vendored Normal file
View File

@ -0,0 +1,49 @@
#ifndef FILESYS_HEADER
#define FILESYS_HEADER
#include <string>
#include <vector>
#ifdef _WIN32 // WINDOWS
#define DIR_DELIM "\\"
#define DIR_DELIM_C '\\'
#else // POSIX
#define DIR_DELIM "/"
#define DIR_DELIM_C '/'
#endif
namespace c55fs
{
/* "image.png", "png" -> true */
bool checkFileExtension(const char *path, const char *ext);
std::string stripFileExtension(const std::string &path);
std::string stripFilename(const std::string &path);
struct DirListNode
{
std::string name;
bool dir;
};
std::vector<DirListNode> GetDirListing(std::string path);
// Returns true if already exists
bool CreateDir(std::string path);
// Create all directories on the given path that don't already exist.
bool CreateAllDirs(std::string path);
bool PathExists(std::string path);
// Only pass full paths to this one. True on success.
// NOTE: The WIN32 version returns always true.
bool RecursiveDelete(std::string path);
// Only pass full paths to this one. True on success.
bool RecursiveDeleteContent(std::string path);
}//fs
#endif

View File

@ -63,9 +63,13 @@ TARGET_LINK_LIBRARIES(${CLIENT_EXE_NAME}
set(SERVER_EXE_NAME buildat_server) set(SERVER_EXE_NAME buildat_server)
set(SERVER_SRCS set(SERVER_SRCS
src/server/main.cpp src/server/main.cpp
src/server/state.cpp
src/server/rccpp.cpp
) )
add_executable(${SERVER_EXE_NAME} ${SERVER_SRCS}) add_executable(${SERVER_EXE_NAME} ${SERVER_SRCS})
TARGET_LINK_LIBRARIES(${SERVER_EXE_NAME} TARGET_LINK_LIBRARIES(${SERVER_EXE_NAME}
c55lib c55lib
dl
) )
add_definitions(-DRCCPP_ENABLED=1)

View File

@ -2,6 +2,8 @@ Buildat
======= =======
A Minecraft clone with vast extendability. A Minecraft clone with vast extendability.
License: MIT
Client Client
------ ------
Built using Polycode C++. Built using Polycode C++.

View File

@ -1,11 +1,12 @@
#include <string> #pragma once
#include "core/types.h"
namespace client namespace client
{ {
struct Config struct Config
{ {
std::string server_address; ss_ server_address;
std::string polycode_path = "/home/celeron55/softat/polycode/"; ss_ polycode_path = "/home/celeron55/softat/polycode/";
std::string share_path = "../share"; ss_ share_path = "../share";
}; };
} }

View File

@ -1,3 +1,4 @@
#include "core/types.h"
#include "client/config.h" #include "client/config.h"
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsign-compare" #pragma GCC diagnostic ignored "-Wsign-compare"
@ -13,24 +14,24 @@ using Polycode::SDLCore;
using Polycode::Logger; using Polycode::Logger;
using Polycode::String; using Polycode::String;
client::Config g_config; client::Config g_client_config;
int MyLoader(lua_State* pState) int MyLoader(lua_State* pState)
{ {
// TODO: Security // TODO: Security
std::string module = lua_tostring(pState, 1); ss_ module = lua_tostring(pState, 1);
module += ".lua"; module += ".lua";
//Logger::log("Loading custom class: %s\n", module.c_str()); //Logger::log("Loading custom class: %s\n", module.c_str());
std::vector<std::string> defaultPaths = { std::vector<ss_> defaultPaths = {
g_config.polycode_path+"/Bindings/Contents/LUA/API/", g_client_config.polycode_path+"/Bindings/Contents/LUA/API/",
g_config.polycode_path+"/Modules/Bindings/2DPhysics/API/", g_client_config.polycode_path+"/Modules/Bindings/2DPhysics/API/",
g_config.polycode_path+"/Modules/Bindings/3DPhysics/API/", g_client_config.polycode_path+"/Modules/Bindings/3DPhysics/API/",
g_config.polycode_path+"/Modules/Bindings/UI/API/", g_client_config.polycode_path+"/Modules/Bindings/UI/API/",
}; };
for(std::string defaultPath : defaultPaths){ for(ss_ defaultPath : defaultPaths){
defaultPath.append(module); defaultPath.append(module);
const char* fullPath = module.c_str(); const char* fullPath = module.c_str();
@ -54,7 +55,7 @@ int MyLoader(lua_State* pState)
return 1; return 1;
} }
} }
std::string err = "\n\tError - Could could not find "; ss_ err = "\n\tError - Could could not find ";
err += module; err += module;
err += "."; err += ".";
lua_pushstring(pState, err.c_str()); lua_pushstring(pState, err.c_str());
@ -191,7 +192,7 @@ HelloPolycodeApp::HelloPolycodeApp(Polycode::PolycodeView *view):
// SDLCore for Linux // SDLCore for Linux
core = new POLYCODE_CORE(view, 640,480,false,false,0,0,90, 1, true); core = new POLYCODE_CORE(view, 640,480,false,false,0,0,90, 1, true);
Polycode::CoreServices::getInstance()->getResourceManager()->addArchive(g_config.share_path+"/default.pak"); Polycode::CoreServices::getInstance()->getResourceManager()->addArchive(g_client_config.share_path+"/default.pak");
Polycode::CoreServices::getInstance()->getResourceManager()->addDirResource("default", false); Polycode::CoreServices::getInstance()->getResourceManager()->addDirResource("default", false);
scene = new Polycode::Scene(Polycode::Scene::SCENE_2D); scene = new Polycode::Scene(Polycode::Scene::SCENE_2D);
@ -263,7 +264,7 @@ HelloPolycodeApp::HelloPolycodeApp(Polycode::PolycodeView *view):
//luaopen_Physics3D(L); //luaopen_Physics3D(L);
//luaopen_UI(L); //luaopen_UI(L);
int error = luaL_dofile(L, (g_config.share_path+"/init.lua").c_str()); int error = luaL_dofile(L, (g_client_config.share_path+"/init.lua").c_str());
if(error){ if(error){
Logger::log("luaL_dofile: An error occurred: %s\n", lua_tostring(L, -1)); Logger::log("luaL_dofile: An error occurred: %s\n", lua_tostring(L, -1));
lua_pop(L, 1); lua_pop(L, 1);
@ -283,7 +284,7 @@ bool HelloPolycodeApp::Update() {
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
client::Config &config = g_config; client::Config &config = g_client_config;
const char opts[100] = "hs:p:P:"; const char opts[100] = "hs:p:P:";
const char usagefmt[1000] = const char usagefmt[1000] =

120
src/core/types.h Normal file
View File

@ -0,0 +1,120 @@
#pragma once
#include <string>
#include <vector>
#include <map>
#include <set>
#include <exception>
#include <cstdint>
#include <cinttypes> // PRId64
#include <sstream>
#include <memory>
typedef unsigned int uint;
typedef unsigned char uchar;
typedef std::string ss_;
template<typename T> using sv_ = std::vector<T>;
template<typename T> using set_ = std::set<T>;
template<typename T1, typename T2> using sm_ = std::map<T1, T2>;
typedef const char cc_;
static inline cc_* cs(const ss_ &s){ return s.c_str(); }
template<typename T> using up_ = std::unique_ptr<T>;
template<typename T> using sp_ = std::shared_ptr<T>;
template<typename T> using sil_ = std::initializer_list<T>;
#define IDF "%" PRId64
struct id_ {
int64_t value;
id_(): value(0) {}
id_(int64_t v): value(v) {}
id_& operator=(int64_t v){
value = v;
return *this;
}
bool operator<(const id_ &other) const{
return value < other.value;
}
bool operator==(const id_ &other) const{
return value == other.value;
}
bool operator!=(const id_ &other) const{
return value != other.value;
}
};
static inline std::ostream& operator<<(std::ostream &out, const id_ &v){
return (out<<v.value);
}
struct db_json_ {
std::string value;
db_json_(){}
db_json_(const std::string &value_): value(value_) {}
};
struct Exception: public std::exception {
ss_ msg;
Exception(const ss_ &msg): msg(msg) {}
virtual const char* what() const throw(){
return msg.c_str();
}
};
#define DEFINE_EXCEPTION(name, base) struct name: public base\
{ name(const ss_ &msg=""): base(ss_()+#name+msg) {} }
static inline ss_ itos(int64_t i){
char buf[22];
snprintf(buf, 22, "%" PRId64, i);
return buf;
}
static inline ss_ itos(id_ id){
return itos(id.value);
}
static inline ss_ ftos(float f){
char buf[100];
snprintf(buf, 100, "%f", f);
return buf;
}
#define SLEN(x) (sizeof(x)/sizeof((x)[0]))
static inline ss_ dump(const id_ &id){
char buf[23];
snprintf(buf, 23, "@%" PRId64, id.value);
return buf;
}
template<typename T>
ss_ dump(const sv_<T> &vs){
std::ostringstream os(std::ios::binary);
os<<"[";
bool first = true;
for(const auto &v : vs){
if(!first)
os<<", ";
first = false;
os<<v;
}
os<<"]";
return os.str();
}
template<typename T>
ss_ dump(const std::set<T> &vs){
std::ostringstream os(std::ios::binary);
os<<"(";
bool first = true;
for(const auto &v : vs){
if(!first)
os<<", ";
first = false;
os<<v;
}
os<<")";
return os.str();
}
template<typename T>
static inline cc_* cs(const T &v){
return dump(v).c_str();
}

26
src/interface/core.h Normal file
View File

@ -0,0 +1,26 @@
#pragma once
#include "server/rccpp.h"
class TestClass : public RuntimeClass<TestClass> {
CLASS_INTERNALS(TestClass)
public:
TestClass();
~TestClass();
RUNTIME_VIRTUAL int test_add(int a);
int m_sum;
};
RUNTIME_EXPORT_CLASS(TestClass)
/*class Module : public RuntimeClass<Module> {
CLASS_INTERNALS(Module)
public:
Module();
~Module();
RUNTIME_VIRTUAL int test_add(int a);
int m_sum;
};
RUNTIME_EXPORT_CLASS(Module)*/

12
src/server/config.h Normal file
View File

@ -0,0 +1,12 @@
#pragma once
#include "core/types.h"
namespace server
{
struct Config
{
ss_ rccpp_build_path = "../cache/rccpp_build";
ss_ interface_path = "../src/interface";
};
}

View File

@ -1,8 +1,58 @@
#include "core/types.h"
#include "server/config.h"
#include "server/state.h"
#include <iostream> #include <iostream>
#include <c55_getopt.h>
server::Config g_server_config;
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
server::Config &config = g_server_config;
std::string module_path;
const char opts[100] = "hm:r:i:";
const char usagefmt[1000] =
"Usage: %s [OPTION]...\n"
" -h Show this help\n"
" -m [module_path] Specify module path (for testing a single module)\n"
" -r [rccpp_build_path]Specify runtime compiled C++ build path\n"
" -i [interface_path] Specify path to interface headers\n"
;
int c;
while((c = c55_getopt(argc, argv, opts)) != -1)
{
switch(c)
{
case 'h':
printf(usagefmt, argv[0]);
return 1;
case 'm':
fprintf(stderr, "INFO: module_path: %s\n", c55_optarg);
module_path = c55_optarg;
break;
case 'r':
fprintf(stderr, "INFO: config.rccpp_build_path: %s\n", c55_optarg);
config.rccpp_build_path = c55_optarg;
break;
case 'i':
fprintf(stderr, "INFO: config.interface_path: %s\n", c55_optarg);
config.interface_path = c55_optarg;
break;
default:
fprintf(stderr, "ERROR: Invalid command-line argument\n");
fprintf(stderr, usagefmt, argv[0]);
return 1;
}
}
std::cerr<<"Buildat server"<<std::endl; std::cerr<<"Buildat server"<<std::endl;
up_<server::State> state(server::createState());
state->load_module(module_path);
return 0; return 0;
} }

142
src/server/rccpp.cpp Normal file
View File

@ -0,0 +1,142 @@
#if defined(RCCPP_ENABLED)
#include "rccpp.h"
// Module interface
#include "interface/core.h"
#include <c55_filesys.h>
#include <vector>
#include <string>
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include <dlfcn.h>
// linux
#if 1
static void *library_load(const char *filename) { return dlopen(filename, RTLD_NOW); }
static void library_unload(void *module) { dlclose(module); }
static void *library_get_address(void *module, const char *name) { return dlsym(module, name); }
#elif 0
static void *library_load(const char *filename) { return LoadLibrary(filename); }
static void library_unload(void *module) { FreeLibrary(module); }
static void *library_get_address(void *module, const char *name) { return GetProcAddress(module, name); }
#endif
RCCPP_Compiler::RCCPP_Compiler()
{
}
bool RCCPP_Compiler::compile(const std::string &in_path, const std::string &out_path)
{
//std::string command = "g++ -g -O0 -fPIC -fvisibility=hidden -shared";
std::string command = "g++ -DRCCPP -g -fPIC -fvisibility=hidden -shared";
command += " -std=c++11";
for(const std::string &dir : include_directories) command += " -I" + dir;
for(const std::string &dir : library_directories) command += " -L" + dir;
command += " -o" + out_path;
command += " " + in_path;
//std::cout << ">>> " << command << std::endl;
// Fork for compilation.
int f = fork();
if(f == 0) {
execl("/bin/sh", "sh", "-c", command.c_str(), (const char*)nullptr);
}
// Wait for the forked process to exit.
int exit_status;
while(wait(&exit_status) > 0);
return exit_status == 0;
}
void RCCPP_Compiler::build(const std::string &in_path, const std::string &out_path)
{
std::cout << "Building " << in_path << " -> " << out_path << "... ";
std::string out_dir = c55fs::stripFilename(out_path);
c55fs::CreateAllDirs(out_dir);
if(compile(in_path, out_path)) {
std::cout << "Success!" << std::endl;
void *new_module = library_load(out_path.c_str());
RCCPP_GetInterface GetInterface = (RCCPP_GetInterface)library_get_address(new_module, "rccpp_GetInterface");
if(GetInterface == nullptr) {
std::cout << "GetInterface is missing from the library" << std::endl;
return;
}
RCCPP_Interface *interface = GetInterface();
assert(interface && "Interface is null");
RCCPP_Constructor fun_constructor = interface->constructor;
RCCPP_Destructor fun_destructor = interface->destructor;
RCCPP_PlacementNew fun_placementnew = interface->placementnew;
if(!(fun_constructor && fun_constructor && fun_placementnew)) {
printf("Something failed with the function pointers in the module\n");
printf(" constructor: %p (%s)\n", fun_constructor, (fun_constructor != nullptr ? "ok" : "fail"));
printf(" destructor: %p (%s)\n", fun_destructor, (fun_destructor != nullptr ? "ok" : "fail"));
printf(" placement new: %p (%s)\n", fun_placementnew, (fun_placementnew != nullptr ? "ok" : "fail"));
fflush(stdout);
return;
}
std::string classname = interface->classname;
auto it = component_info_.find(classname);
if(it != component_info_.end()) {
RCCPP_Info &funcs = it->second;
funcs.constructor = fun_constructor;
funcs.destructor = fun_destructor;
funcs.placement_new = fun_placementnew;
if(funcs.module_prev) library_unload(funcs.module_prev);
funcs.module_prev = funcs.module;
funcs.module = new_module;
} else {
RCCPP_Info funcs;
funcs.constructor = fun_constructor;
funcs.destructor = fun_destructor;
funcs.placement_new = fun_placementnew;
funcs.module_prev = nullptr;
funcs.module = new_module;
funcs.size = interface->original_size;
component_info_.emplace(classname, std::move(funcs));
}
changed_classes_.push_back(classname);
} else {
std::cout << "Failed!" << std::endl;
}
}
void *RCCPP_Compiler::construct(const char *name) {
auto component_info_it = component_info_.find(name);
if(component_info_it == component_info_.end()) {
assert(nullptr && "Failed to get class info");
return nullptr;
}
RCCPP_Info &info = component_info_it->second;
RCCPP_Constructor constructor = info.constructor;
void *result = constructor();
auto it = constructed_objects.find(std::string(name));
if(it == constructed_objects.end()) constructed_objects.insert(std::make_pair(name, std::vector<void*>{result}));
else it->second.push_back(result);
return result;
}
#endif

127
src/server/rccpp.h Normal file
View File

@ -0,0 +1,127 @@
#pragma once
#include "core/types.h"
// This is what you get when the RCCPP is not enabled
#if !defined(RCCPP_ENABLED) && !defined(RCCPP)
#define RUNTIME_EXPORT_CLASS(C)
#define RUNTIME_VIRTUAL
#endif
#if defined(RCCPP) || defined(RCCPP_ENABLED)
#define RCCPP_USE_SINGLETON_NEWING
#define RUNTIME_VIRTUAL virtual
#define CLASS_INTERNALS(C) public: constexpr static const char *NAME = #C;
#include <cstddef>
struct RCCPP_Interface;
typedef void *(*RCCPP_Constructor)();
typedef void (*RCCPP_Destructor)(void *component);
typedef void (*RCCPP_PlacementNew)(void *buffer, size_t size);
typedef RCCPP_Interface *(*RCCPP_GetInterface)();
struct RCCPP_Interface {
RCCPP_Constructor constructor;
RCCPP_Destructor destructor;
RCCPP_PlacementNew placementnew;
const char *classname;
size_t original_size;
};
#endif
// This is what the runtime compiler exports for the library.
#if defined(RCCPP) && !defined(RCCPP_ENABLED)
#include <new>
#define EXPORT __attribute__ ((visibility ("default")))
#define RUNTIME_EXPORT_CLASS(C) \
extern "C" { \
static void *rccpp_constructor() { return new C(); } \
static void rccpp_destructor(void *c) { delete reinterpret_cast<C*>(c); } \
static void rccpp_placementnew(void *buffer, size_t size) { new (buffer) C(*(C*)buffer); } \
EXPORT RCCPP_Interface *rccpp_GetInterface() { \
static RCCPP_Interface interface; \
interface.constructor = &rccpp_constructor; \
interface.destructor = &rccpp_destructor; \
interface.placementnew = &rccpp_placementnew; \
interface.classname = #C; \
interface.original_size = sizeof(C); \
return &interface; \
} \
}
#endif
// And this is what your normal compiler sees when you have actually enabled RCCPP.
#if !defined(RCCPP) && defined(RCCPP_ENABLED)
#define RCCPP_CONSTRUCTOR "rccpp_constructor"
#define RCCPP_DESTRUCTOR "rccpp_destructor"
#define RCCPP_PLACEMENT_NEW "rccpp_placement_new"
#define RCCPP_MOVE "rccpp_move"
#define RCCPP_CLASSNAME "rccpp_classname"
#define RUNTIME_EXPORT_CLASS(C)
#define RUNTIME_VIRTUAL virtual
#include <vector>
#include <cassert>
#include <memory>
#include <string>
#include <unordered_map>
#include <algorithm>
struct RCCPP_Info {
void *module;
void *module_prev;
RCCPP_Constructor constructor;
RCCPP_Destructor destructor;
RCCPP_PlacementNew placement_new;
size_t size;
};
class RuntimeClassBase;
class RCCPP_Compiler {
public:
RCCPP_Compiler();
void build(const std::string &in_path, const std::string &out_path);
template<typename T> T *construct() { return (T*)construct(T::NAME); }
void *construct(const char *name);
#if defined(RCCPP_USE_SINGLETON_NEWING)
static RCCPP_Compiler &instance() {
static RCCPP_Compiler i;
return i;
}
#endif
std::vector<std::string> include_directories;
std::vector<std::string> library_directories;
private:
std::unordered_map<std::string, RCCPP_Info> component_info_;
std::unordered_map<std::string, std::vector<void*>> constructed_objects;
std::vector<std::string> changed_classes_;
bool compile(const std::string &in_path, const std::string &out_path);
};
#endif
#if defined(RCCPP_ENABLED)
#include <cstddef>
template<typename T>
class RuntimeClass {
public:
#ifdef RCCPP_USE_SINGLETON_NEWING
void *operator new(size_t size) { return RCCPP_Compiler::instance().construct(T::NAME); }
#endif
};
#ifdef RCCPP_USE_SINGLETON_NEWING
#define RCCPP_Update() RCCPP_Compiler::instance().update();
#endif
#else
template<typename T> class RuntimeClass { };
#endif

32
src/server/state.cpp Normal file
View File

@ -0,0 +1,32 @@
#include "state.h"
#include "rccpp.h"
#include "config.h"
extern server::Config g_server_config;
namespace server {
struct CState: public State
{
RCCPP_Compiler m_compiler;
CState()
{
m_compiler.include_directories.push_back(
g_server_config.interface_path);
m_compiler.include_directories.push_back(
g_server_config.interface_path+"/..");
}
void load_module(const ss_ &path)
{
ss_ build_dst = g_server_config.rccpp_build_path + "/foo.o";
m_compiler.build(path+"/server/main.cpp", build_dst);
}
};
State* createState()
{
return new CState();
}
}

13
src/server/state.h Normal file
View File

@ -0,0 +1,13 @@
#pragma once
#include "core/types.h"
namespace server
{
struct State
{
virtual ~State(){}
virtual void load_module(const ss_ &path) = 0;
};
State* createState();
}

View File

@ -0,0 +1,3 @@
#include <core.h>