WIP
This commit is contained in:
parent
9406265c5e
commit
d355b436e6
1
.gitignore
vendored
1
.gitignore
vendored
@ -4,3 +4,4 @@
|
||||
*.tar.gz
|
||||
|
||||
/build
|
||||
/cache
|
||||
|
2
3rdparty/c55lib/CMakeLists.txt
vendored
2
3rdparty/c55lib/CMakeLists.txt
vendored
@ -1,3 +1,3 @@
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
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
344
3rdparty/c55lib/c55_filesys.cpp
vendored
Normal 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
49
3rdparty/c55lib/c55_filesys.h
vendored
Normal 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
|
||||
|
@ -63,9 +63,13 @@ TARGET_LINK_LIBRARIES(${CLIENT_EXE_NAME}
|
||||
set(SERVER_EXE_NAME buildat_server)
|
||||
set(SERVER_SRCS
|
||||
src/server/main.cpp
|
||||
src/server/state.cpp
|
||||
src/server/rccpp.cpp
|
||||
)
|
||||
add_executable(${SERVER_EXE_NAME} ${SERVER_SRCS})
|
||||
TARGET_LINK_LIBRARIES(${SERVER_EXE_NAME}
|
||||
c55lib
|
||||
dl
|
||||
)
|
||||
add_definitions(-DRCCPP_ENABLED=1)
|
||||
|
||||
|
@ -2,6 +2,8 @@ Buildat
|
||||
=======
|
||||
A Minecraft clone with vast extendability.
|
||||
|
||||
License: MIT
|
||||
|
||||
Client
|
||||
------
|
||||
Built using Polycode C++.
|
||||
|
@ -1,11 +1,12 @@
|
||||
#include <string>
|
||||
#pragma once
|
||||
#include "core/types.h"
|
||||
|
||||
namespace client
|
||||
{
|
||||
struct Config
|
||||
{
|
||||
std::string server_address;
|
||||
std::string polycode_path = "/home/celeron55/softat/polycode/";
|
||||
std::string share_path = "../share";
|
||||
ss_ server_address;
|
||||
ss_ polycode_path = "/home/celeron55/softat/polycode/";
|
||||
ss_ share_path = "../share";
|
||||
};
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
#include "core/types.h"
|
||||
#include "client/config.h"
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wsign-compare"
|
||||
@ -13,24 +14,24 @@ using Polycode::SDLCore;
|
||||
using Polycode::Logger;
|
||||
using Polycode::String;
|
||||
|
||||
client::Config g_config;
|
||||
client::Config g_client_config;
|
||||
|
||||
int MyLoader(lua_State* pState)
|
||||
{
|
||||
// TODO: Security
|
||||
std::string module = lua_tostring(pState, 1);
|
||||
ss_ module = lua_tostring(pState, 1);
|
||||
|
||||
module += ".lua";
|
||||
//Logger::log("Loading custom class: %s\n", module.c_str());
|
||||
|
||||
std::vector<std::string> defaultPaths = {
|
||||
g_config.polycode_path+"/Bindings/Contents/LUA/API/",
|
||||
g_config.polycode_path+"/Modules/Bindings/2DPhysics/API/",
|
||||
g_config.polycode_path+"/Modules/Bindings/3DPhysics/API/",
|
||||
g_config.polycode_path+"/Modules/Bindings/UI/API/",
|
||||
std::vector<ss_> defaultPaths = {
|
||||
g_client_config.polycode_path+"/Bindings/Contents/LUA/API/",
|
||||
g_client_config.polycode_path+"/Modules/Bindings/2DPhysics/API/",
|
||||
g_client_config.polycode_path+"/Modules/Bindings/3DPhysics/API/",
|
||||
g_client_config.polycode_path+"/Modules/Bindings/UI/API/",
|
||||
};
|
||||
|
||||
for(std::string defaultPath : defaultPaths){
|
||||
for(ss_ defaultPath : defaultPaths){
|
||||
defaultPath.append(module);
|
||||
|
||||
const char* fullPath = module.c_str();
|
||||
@ -54,7 +55,7 @@ int MyLoader(lua_State* pState)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
std::string err = "\n\tError - Could could not find ";
|
||||
ss_ err = "\n\tError - Could could not find ";
|
||||
err += module;
|
||||
err += ".";
|
||||
lua_pushstring(pState, err.c_str());
|
||||
@ -191,7 +192,7 @@ HelloPolycodeApp::HelloPolycodeApp(Polycode::PolycodeView *view):
|
||||
// SDLCore for Linux
|
||||
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);
|
||||
|
||||
scene = new Polycode::Scene(Polycode::Scene::SCENE_2D);
|
||||
@ -263,7 +264,7 @@ HelloPolycodeApp::HelloPolycodeApp(Polycode::PolycodeView *view):
|
||||
//luaopen_Physics3D(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){
|
||||
Logger::log("luaL_dofile: An error occurred: %s\n", lua_tostring(L, -1));
|
||||
lua_pop(L, 1);
|
||||
@ -283,7 +284,7 @@ bool HelloPolycodeApp::Update() {
|
||||
|
||||
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 usagefmt[1000] =
|
||||
|
120
src/core/types.h
Normal file
120
src/core/types.h
Normal 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
26
src/interface/core.h
Normal 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
12
src/server/config.h
Normal 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";
|
||||
};
|
||||
}
|
||||
|
@ -1,8 +1,58 @@
|
||||
#include "core/types.h"
|
||||
#include "server/config.h"
|
||||
#include "server/state.h"
|
||||
#include <iostream>
|
||||
#include <c55_getopt.h>
|
||||
|
||||
server::Config g_server_config;
|
||||
|
||||
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;
|
||||
|
||||
up_<server::State> state(server::createState());
|
||||
state->load_module(module_path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
142
src/server/rccpp.cpp
Normal file
142
src/server/rccpp.cpp
Normal 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
127
src/server/rccpp.h
Normal 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
32
src/server/state.cpp
Normal 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
13
src/server/state.h
Normal 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();
|
||||
}
|
3
test/testmodule1/server/main.cpp
Normal file
3
test/testmodule1/server/main.cpp
Normal file
@ -0,0 +1,3 @@
|
||||
#include <core.h>
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user