New base for a configuration system
This commit is contained in:
parent
d5182d09c1
commit
82e0ff612a
@ -121,8 +121,8 @@ struct Module: public interface::Module, public main_context::Interface
|
||||
const interface::ServerConfig &server_config = m_server->get_config();
|
||||
|
||||
sv_<ss_> resource_paths = {
|
||||
server_config.urho3d_path+"/Bin/CoreData",
|
||||
server_config.urho3d_path+"/Bin/Data",
|
||||
server_config.get<ss_>("urho3d_path")+"/Bin/CoreData",
|
||||
server_config.get<ss_>("urho3d_path")+"/Bin/Data",
|
||||
};
|
||||
auto *fs = interface::getGlobalFilesystem();
|
||||
ss_ resource_paths_s;
|
||||
|
10
doc/todo.txt
10
doc/todo.txt
@ -19,9 +19,6 @@ Buildat TODO
|
||||
- Support Cereal's shared pointer serialization in Lua
|
||||
- Automatically fetch and build and patch Urho3D when building buildat
|
||||
- Maybe no
|
||||
- Automatic buildat root detection so that the server and the client can
|
||||
generally be started with any working directory in either the in-source or
|
||||
windows-installed configuration
|
||||
- Precompiled mode
|
||||
- Singleplayer UI
|
||||
- Show all exceptions and errors on client using ui_utils.show_message_dialog
|
||||
@ -68,3 +65,10 @@ Buildat TODO
|
||||
- If loading a pre-built module fails even while files haven't been modified,
|
||||
try building it again (this is sometimes needed when buildat_core is updated
|
||||
without header modifications)
|
||||
|
||||
Doing now:
|
||||
- Automatic buildat root detection so that the server and the client can
|
||||
generally be started with any working directory in either the in-source or
|
||||
windows-installed configuration
|
||||
- Allow developing a game outside of the buildat source tree without hassle
|
||||
|
||||
|
66
src/core/config.h
Normal file
66
src/core/config.h
Normal file
@ -0,0 +1,66 @@
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Copyright 2014 Perttu Ahola <celeron55@gmail.com>
|
||||
#pragma once
|
||||
#include "core/types.h"
|
||||
#include "core/json.h"
|
||||
|
||||
namespace core
|
||||
{
|
||||
struct Config
|
||||
{
|
||||
json::Value defaults;
|
||||
json::Value values;
|
||||
|
||||
Config():
|
||||
defaults(json::object()),
|
||||
values(json::object())
|
||||
{}
|
||||
|
||||
template<typename T>
|
||||
void set_default(const ss_ &name, const T &native_v)
|
||||
{
|
||||
json::Value new_v(native_v);
|
||||
|
||||
const json::Value ¤t_v = values.get(name);
|
||||
if(!current_v.is_undefined() &&
|
||||
current_v.get_type() != new_v.get_type()){
|
||||
throw Exception(ss_()+"Cannot set defaults["+name+"] with type "+
|
||||
new_v.desc_type()+"; value already exists with type "+
|
||||
current_v.desc_type());
|
||||
}
|
||||
|
||||
defaults.set(name, new_v);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void set(const ss_ &name, const T &native_v)
|
||||
{
|
||||
json::Value new_v(native_v);
|
||||
|
||||
const json::Value &default_v = defaults.get(name);
|
||||
if(!default_v.is_undefined() &&
|
||||
new_v.get_type() != default_v.get_type()){
|
||||
throw Exception(ss_()+"Cannot set values["+name+"] with type "+
|
||||
new_v.desc_type()+"; default determines required type "+
|
||||
default_v.desc_type());
|
||||
}
|
||||
|
||||
values.set(name, new_v);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const T& get(const ss_ &name) const
|
||||
{
|
||||
const json::Value ¤t_v = values.get(name);
|
||||
if(current_v.is_undefined()){
|
||||
// Try default
|
||||
const json::Value &default_v = defaults.get(name);
|
||||
if(!default_v.is_undefined())
|
||||
return default_v.as<T>();
|
||||
throw Exception("Configuration value \""+name+"\" not found");
|
||||
}
|
||||
return current_v.as<T>();
|
||||
}
|
||||
};
|
||||
}
|
||||
// vim: set noet ts=4 sw=4:
|
@ -89,6 +89,7 @@ struct ValuePrivate
|
||||
std::string s;
|
||||
std::vector<Value> a;
|
||||
std::map<std::string, Value> o;
|
||||
double number; // Used if integer value is referenced as const double
|
||||
};
|
||||
}
|
||||
|
||||
@ -175,6 +176,20 @@ Value& json::Value::operator=(const Value &other)
|
||||
return *this;
|
||||
}
|
||||
|
||||
const char* json::Value::desc_type() const {
|
||||
switch(type){
|
||||
case T_UNDEFINED: return "UNDEFINED";
|
||||
case T_NULL: return "NULL";
|
||||
case T_BOOL: return "BOOL";
|
||||
case T_INT: return "INT";
|
||||
case T_FLOAT: return "FLOAT";
|
||||
case T_STRING: return "STRING";
|
||||
case T_ARRAY: return "ARRAY";
|
||||
case T_OBJECT: return "OBJECT";
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
bool json::Value::is_undefined() const {
|
||||
return type == T_UNDEFINED;
|
||||
}
|
||||
@ -266,9 +281,9 @@ const Value& json::Value::get(const std::string &key) const {
|
||||
return it->second;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return dummy;
|
||||
}
|
||||
default:
|
||||
return dummy;
|
||||
}
|
||||
}
|
||||
|
||||
Value& json::Value::operator[](const char *key){
|
||||
@ -283,9 +298,9 @@ Value& json::Value::operator[](const std::string &key){
|
||||
return it->second;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw MutableDoesNotExist();
|
||||
}
|
||||
default:
|
||||
throw MutableDoesNotExist();
|
||||
}
|
||||
}
|
||||
|
||||
void json::Value::clear(){
|
||||
@ -307,7 +322,8 @@ const char* json::Value::as_cstring() const {
|
||||
return p->s.c_str();
|
||||
}
|
||||
}
|
||||
std::string json::Value::as_string(const std::string &default_value) const {
|
||||
const std::string& json::Value::as_string() const {
|
||||
static std::string default_value;
|
||||
switch(type){
|
||||
default:
|
||||
return default_value;
|
||||
@ -315,7 +331,8 @@ std::string json::Value::as_string(const std::string &default_value) const {
|
||||
return p->s;
|
||||
}
|
||||
}
|
||||
int json::Value::as_integer(int default_value) const {
|
||||
const int64_t& json::Value::as_integer() const {
|
||||
static int64_t default_value = 0;
|
||||
switch(type){
|
||||
default:
|
||||
return default_value;
|
||||
@ -323,7 +340,8 @@ int json::Value::as_integer(int default_value) const {
|
||||
return value.i;
|
||||
}
|
||||
}
|
||||
double json::Value::as_real(double default_value) const {
|
||||
const double& json::Value::as_real() const {
|
||||
static double default_value = 0;
|
||||
switch(type){
|
||||
default:
|
||||
return default_value;
|
||||
@ -331,17 +349,21 @@ double json::Value::as_real(double default_value) const {
|
||||
return value.f;
|
||||
}
|
||||
}
|
||||
double json::Value::as_number(double default_value) const {
|
||||
const double& json::Value::as_number() const {
|
||||
static double default_value = 0.0;
|
||||
switch(type){
|
||||
default:
|
||||
return default_value;
|
||||
case T_INT:
|
||||
return value.i;
|
||||
p = new ValuePrivate();
|
||||
p->number = value.i;
|
||||
return p->number;
|
||||
case T_FLOAT:
|
||||
return value.f;
|
||||
}
|
||||
}
|
||||
bool json::Value::as_boolean(bool default_value) const {
|
||||
const bool& json::Value::as_boolean() const {
|
||||
static bool default_value = false;
|
||||
switch(type){
|
||||
default:
|
||||
return default_value;
|
||||
@ -696,4 +718,5 @@ const Value json::load_file(const char *path, json_error_t *error){
|
||||
t.read(&buffer[0], size);
|
||||
return json::load_string(buffer.c_str(), error);
|
||||
}
|
||||
// codestyle:disable (muh beautiful alignments)
|
||||
// vim: set noet ts=4 sw=4:
|
||||
|
@ -21,13 +21,7 @@ namespace json
|
||||
struct ValuePrivate;
|
||||
class Value
|
||||
{
|
||||
friend const Value json::object();
|
||||
friend const Value json::array();
|
||||
friend const Value json::null();
|
||||
friend const Value json::load_sajson(const sajson::value &src);
|
||||
friend class Iterator;
|
||||
|
||||
ValuePrivate *p;
|
||||
public:
|
||||
enum Type {
|
||||
T_UNDEFINED,
|
||||
T_NULL,
|
||||
@ -38,7 +32,16 @@ namespace json
|
||||
T_ARRAY,
|
||||
T_OBJECT,
|
||||
//T_RAW,
|
||||
} type;
|
||||
};
|
||||
private:
|
||||
friend const Value json::object();
|
||||
friend const Value json::array();
|
||||
friend const Value json::null();
|
||||
friend const Value json::load_sajson(const sajson::value &src);
|
||||
friend class Iterator;
|
||||
|
||||
mutable ValuePrivate *p;
|
||||
Type type;
|
||||
union {
|
||||
bool b;
|
||||
int64_t i;
|
||||
@ -60,6 +63,11 @@ namespace json
|
||||
// assignment operator
|
||||
Value& operator=(const Value &value);
|
||||
|
||||
// get type
|
||||
Type get_type() const {return type;}
|
||||
// describe type
|
||||
const char* desc_type() const;
|
||||
|
||||
// check value type
|
||||
bool is_undefined() const;
|
||||
bool is_object() const;
|
||||
@ -95,12 +103,14 @@ namespace json
|
||||
|
||||
// get value cast to specified type
|
||||
const char* as_cstring() const;
|
||||
std::string as_string(const std::string &default_value =
|
||||
std::string()) const;
|
||||
int as_integer(int default_value = 0) const;
|
||||
double as_real(double default_value = 0.0) const;
|
||||
double as_number(double default_value = 0.0) const;
|
||||
bool as_boolean(bool default_value = false) const;
|
||||
const std::string& as_string() const;
|
||||
const int64_t& as_integer() const;
|
||||
const double& as_real() const;
|
||||
const double& as_number() const;
|
||||
const bool& as_boolean() const;
|
||||
|
||||
// get value according to template type
|
||||
template<typename T> const T& as() const;
|
||||
|
||||
// set an object property (converts value to object is not one already)
|
||||
Value& set_key(const char *key, const Value &value);
|
||||
@ -136,6 +146,22 @@ namespace json
|
||||
const Value deepcopy() const;
|
||||
};
|
||||
|
||||
template<> inline const json::Value& Value::as<json::Value>() const {
|
||||
return *this;
|
||||
}
|
||||
template<> inline const std::string& Value::as<std::string>() const {
|
||||
return as_string();
|
||||
}
|
||||
template<> inline const int64_t& Value::as<int64_t>() const {
|
||||
return as_integer();
|
||||
}
|
||||
template<> inline const double& Value::as<double> () const {
|
||||
return as_number();
|
||||
}
|
||||
template<> inline const bool& Value::as<bool> () const {
|
||||
return as_boolean();
|
||||
}
|
||||
|
||||
// iterators over a JSON object
|
||||
struct IteratorPrivate;
|
||||
class Iterator {
|
||||
@ -204,5 +230,5 @@ namespace json
|
||||
}
|
||||
|
||||
#define JSON_INDENT(x) // Dummy for now
|
||||
|
||||
// codestyle:disable (muh beautiful alignments)
|
||||
// vim: set noet ts=4 sw=4:
|
||||
|
@ -43,8 +43,24 @@ static bool check_runnable(const ss_ &command)
|
||||
}
|
||||
}
|
||||
|
||||
Config::Config()
|
||||
{
|
||||
set_default("rccpp_build_path", "../cache/rccpp_build");
|
||||
set_default("interface_path", "../src/interface");
|
||||
set_default("share_path", "..");
|
||||
set_default("urho3d_path", "../../Urho3D");
|
||||
set_default("compiler_command", "c++");
|
||||
set_default("skip_compiling_modules", json::object());
|
||||
}
|
||||
|
||||
bool Config::check_paths()
|
||||
{
|
||||
ss_ rccpp_build_path = get<ss_>("rccpp_build_path");
|
||||
ss_ interface_path = get<ss_>("interface_path");
|
||||
ss_ share_path = get<ss_>("share_path");
|
||||
ss_ urho3d_path = get<ss_>("urho3d_path");
|
||||
ss_ compiler_command = get<ss_>("compiler_command");
|
||||
|
||||
bool fail = false;
|
||||
|
||||
if(!check_file_readable(share_path+"/builtin/network/network.cpp")){
|
||||
@ -85,5 +101,4 @@ bool Config::check_paths()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// vim: set noet ts=4 sw=4:
|
||||
|
@ -2,17 +2,13 @@
|
||||
// Copyright 2014 Perttu Ahola <celeron55@gmail.com>
|
||||
#pragma once
|
||||
#include "core/types.h"
|
||||
#include "core/config.h"
|
||||
|
||||
namespace server
|
||||
{
|
||||
struct Config
|
||||
struct Config: public core::Config
|
||||
{
|
||||
ss_ rccpp_build_path = "../cache/rccpp_build";
|
||||
ss_ interface_path = "../src/interface";
|
||||
ss_ share_path = "..";
|
||||
ss_ urho3d_path = "../../Urho3D";
|
||||
ss_ compiler_command = "c++";
|
||||
set_<ss_> skip_compiling_modules;
|
||||
Config();
|
||||
|
||||
bool check_paths();
|
||||
};
|
||||
|
@ -2,6 +2,7 @@
|
||||
// Copyright 2014 Perttu Ahola <celeron55@gmail.com>
|
||||
#include "core/types.h"
|
||||
#include "core/log.h"
|
||||
#include "core/config.h"
|
||||
#include "server/config.h"
|
||||
#include "server/state.h"
|
||||
#include "interface/server.h"
|
||||
@ -104,23 +105,23 @@ int main(int argc, char *argv[])
|
||||
break;
|
||||
case 'r':
|
||||
fprintf(stderr, "INFO: config.rccpp_build_path: %s\n", c55_optarg);
|
||||
config.rccpp_build_path = c55_optarg;
|
||||
config.set("rccpp_build_path", c55_optarg);
|
||||
break;
|
||||
case 'i':
|
||||
fprintf(stderr, "INFO: config.interface_path: %s\n", c55_optarg);
|
||||
config.interface_path = c55_optarg;
|
||||
config.set("interface_path", c55_optarg);
|
||||
break;
|
||||
case 'S':
|
||||
fprintf(stderr, "INFO: config.share_path: %s\n", c55_optarg);
|
||||
config.share_path = c55_optarg;
|
||||
config.set("share_path", c55_optarg);
|
||||
break;
|
||||
case 'U':
|
||||
fprintf(stderr, "INFO: config.urho3d_path: %s\n", c55_optarg);
|
||||
config.urho3d_path = c55_optarg;
|
||||
config.set("urho3d_path", c55_optarg);
|
||||
break;
|
||||
case 'c':
|
||||
fprintf(stderr, "INFO: config.compiler_command: %s\n", c55_optarg);
|
||||
config.compiler_command = c55_optarg;
|
||||
config.set("compiler_command", c55_optarg);
|
||||
break;
|
||||
case 'l':
|
||||
log_set_max_level(atoi(c55_optarg));
|
||||
@ -131,7 +132,11 @@ int main(int argc, char *argv[])
|
||||
case 'C':
|
||||
fprintf(stderr, "INFO: config.skip_compiling_modules += %s\n",
|
||||
c55_optarg);
|
||||
config.skip_compiling_modules.insert(c55_optarg);
|
||||
{
|
||||
auto v = config.get<json::Value>("skip_compiling_modules");
|
||||
v.set(c55_optarg, json::Value(true));
|
||||
config.set("skip_compiling_modules", v);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "ERROR: Invalid command-line argument\n");
|
||||
|
@ -352,7 +352,7 @@ struct CState: public State, public interface::Server
|
||||
up_<interface::Thread> m_file_watch_thread;
|
||||
|
||||
CState():
|
||||
m_compiler(rccpp::createCompiler(g_server_config.compiler_command)),
|
||||
m_compiler(rccpp::createCompiler(g_server_config.get<ss_>("compiler_command"))),
|
||||
m_thread_pool(interface::thread_pool::createThreadPool())
|
||||
{
|
||||
m_thread_pool->start(4); // TODO: Configurable
|
||||
@ -367,14 +367,14 @@ struct CState: public State, public interface::Server
|
||||
// We don't want to directly add the interface path as it contains
|
||||
// stuff like mutex.h which match on Windows to Urho3D's Mutex.h
|
||||
m_compiler->include_directories.push_back(
|
||||
g_server_config.interface_path+"/..");
|
||||
g_server_config.get<ss_>("interface_path")+"/..");
|
||||
m_compiler->include_directories.push_back(
|
||||
g_server_config.interface_path+"/../../3rdparty/cereal/include");
|
||||
g_server_config.get<ss_>("interface_path")+"/../../3rdparty/cereal/include");
|
||||
m_compiler->include_directories.push_back(
|
||||
g_server_config.interface_path+
|
||||
g_server_config.get<ss_>("interface_path")+
|
||||
"/../../3rdparty/polyvox/library/PolyVoxCore/include");
|
||||
m_compiler->include_directories.push_back(
|
||||
g_server_config.share_path+"/builtin");
|
||||
g_server_config.get<ss_>("share_path")+"/builtin");
|
||||
|
||||
// Setup Urho3D in RCC++
|
||||
|
||||
@ -385,15 +385,15 @@ struct CState: public State, public interface::Server
|
||||
};
|
||||
for(const ss_ &subdir : urho3d_subdirs){
|
||||
m_compiler->include_directories.push_back(
|
||||
g_server_config.urho3d_path+"/Source/Engine/"+subdir);
|
||||
g_server_config.get<ss_>("urho3d_path")+"/Source/Engine/"+subdir);
|
||||
}
|
||||
m_compiler->include_directories.push_back(
|
||||
g_server_config.urho3d_path+"/Build/Engine"); // Urho3D.h
|
||||
g_server_config.get<ss_>("urho3d_path")+"/Build/Engine"); // Urho3D.h
|
||||
m_compiler->library_directories.push_back(
|
||||
g_server_config.urho3d_path+"/Lib");
|
||||
g_server_config.get<ss_>("urho3d_path")+"/Lib");
|
||||
m_compiler->libraries.push_back("-lUrho3D");
|
||||
m_compiler->include_directories.push_back(
|
||||
g_server_config.urho3d_path+"/Source/ThirdParty/Bullet/src");
|
||||
g_server_config.get<ss_>("urho3d_path")+"/Source/ThirdParty/Bullet/src");
|
||||
}
|
||||
~CState()
|
||||
{
|
||||
@ -521,7 +521,8 @@ struct CState: public State, public interface::Server
|
||||
log_d(MODULE, "extra_cxxflags: %s", cs(extra_cxxflags));
|
||||
log_d(MODULE, "extra_ldflags: %s", cs(extra_ldflags));
|
||||
|
||||
bool skip_compile = g_server_config.skip_compiling_modules.count(info.name);
|
||||
bool skip_compile = g_server_config.get<json::Value>(
|
||||
"skip_compiling_modules").get(info.name).as_boolean();
|
||||
|
||||
sv_<ss_> files_to_hash = {init_cpp_path};
|
||||
files_to_hash.insert(
|
||||
@ -532,12 +533,12 @@ struct CState: public State, public interface::Server
|
||||
#ifdef _WIN32
|
||||
// On Windows, we need a new name for each modification of the module
|
||||
// because Windows caches DLLs by name
|
||||
ss_ build_dst = g_server_config.rccpp_build_path +
|
||||
ss_ build_dst = g_server_config.get<ss_>("rccpp_build_path") +
|
||||
"/"+info.name+"_"+interface::sha1::hex(content_hash)+"."+
|
||||
MODULE_EXTENSION;
|
||||
// TODO: Delete old ones
|
||||
#else
|
||||
ss_ build_dst = g_server_config.rccpp_build_path +
|
||||
ss_ build_dst = g_server_config.get<ss_>("rccpp_build_path") +
|
||||
"/"+info.name+"."+MODULE_EXTENSION;
|
||||
#endif
|
||||
|
||||
@ -795,7 +796,7 @@ struct CState: public State, public interface::Server
|
||||
|
||||
ss_ get_builtin_modules_path()
|
||||
{
|
||||
return g_server_config.share_path+"/builtin";
|
||||
return g_server_config.get<ss_>("share_path")+"/builtin";
|
||||
}
|
||||
|
||||
ss_ get_module_path(const ss_ &module_name)
|
||||
|
Loading…
x
Reference in New Issue
Block a user