Merge branch 'main' into dev
This commit is contained in:
@@ -32,7 +32,7 @@ protected:
|
||||
void goBack(size_t count = 1);
|
||||
void reset();
|
||||
|
||||
int64_t parseSimpleInt(int base);
|
||||
int64_t parseSimpleInt(int base, size_t maxLength = 0xFFFFFFFF);
|
||||
dv::value parseNumber(int sign);
|
||||
dv::value parseNumber();
|
||||
StringT parseString(CharT chr, bool closeRequired = true);
|
||||
|
||||
@@ -349,7 +349,10 @@ std::basic_string<CharT> BasicParser<CharT>::parseXmlName() {
|
||||
}
|
||||
|
||||
template <typename CharT>
|
||||
int64_t BasicParser<CharT>::parseSimpleInt(int base) {
|
||||
int64_t BasicParser<CharT>::parseSimpleInt(int base, size_t maxLength) {
|
||||
if (maxLength == 0) return 0;
|
||||
|
||||
size_t start = pos;
|
||||
CharT c = peek();
|
||||
int index = hexchar2int(c);
|
||||
if (index == -1 || index >= base) {
|
||||
@@ -357,7 +360,7 @@ int64_t BasicParser<CharT>::parseSimpleInt(int base) {
|
||||
}
|
||||
int64_t value = index;
|
||||
pos++;
|
||||
while (hasNext()) {
|
||||
while (hasNext() && pos - start < maxLength) {
|
||||
c = source[pos];
|
||||
while (c == '_') {
|
||||
c = source[++pos];
|
||||
@@ -476,7 +479,7 @@ std::basic_string<CharT> BasicParser<CharT>::parseString(
|
||||
continue;
|
||||
}
|
||||
if (c == 'u' || c == 'x') {
|
||||
int codepoint = parseSimpleInt(16);
|
||||
int codepoint = parseSimpleInt(16, c == 'u' ? 4 : 2);
|
||||
ubyte bytes[4];
|
||||
int size = util::encode_utf8(codepoint, bytes);
|
||||
CharT chars[4];
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#define VC_ENABLE_REFLECTION
|
||||
#include "ContentPack.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
@@ -146,7 +147,7 @@ ContentPack ContentPack::read(const io::path& folder) {
|
||||
std::uint8_t op_size = 0;
|
||||
|
||||
// Two symbol operators
|
||||
if (op == ">=" || op == "=>" || op == "<=" || op == "=<") {
|
||||
if (op == ">=" || op == "<=") {
|
||||
op_size = 2;
|
||||
depVerOperator = op;
|
||||
}
|
||||
@@ -169,7 +170,16 @@ ContentPack ContentPack::read(const io::path& folder) {
|
||||
}
|
||||
}
|
||||
|
||||
pack.dependencies.push_back({level, depName, depVer, depVerOperator});
|
||||
VersionOperator versionOperator;
|
||||
if (VersionOperatorMeta.getItem(depVerOperator, versionOperator)) {
|
||||
pack.dependencies.push_back(
|
||||
{level, depName, depVer, versionOperator}
|
||||
);
|
||||
} else {
|
||||
throw contentpack_error(
|
||||
pack.id, folder, "invalid version operator"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include "typedefs.hpp"
|
||||
#include "content_fwd.hpp"
|
||||
#include "io/io.hpp"
|
||||
#include "util/EnumMetadata.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
|
||||
#include "typedefs.hpp"
|
||||
#include "content_fwd.hpp"
|
||||
#include "io/io.hpp"
|
||||
|
||||
class EnginePaths;
|
||||
|
||||
class contentpack_error : public std::runtime_error {
|
||||
@@ -25,11 +26,19 @@ public:
|
||||
io::path getFolder() const;
|
||||
};
|
||||
|
||||
enum class DependencyVersionOperator {
|
||||
enum class VersionOperator {
|
||||
EQUAL, GREATHER, LESS,
|
||||
GREATHER_OR_EQUAL, LESS_OR_EQUAL
|
||||
};
|
||||
|
||||
VC_ENUM_METADATA(VersionOperator)
|
||||
{"=", VersionOperator::EQUAL},
|
||||
{">", VersionOperator::GREATHER},
|
||||
{"<", VersionOperator::LESS},
|
||||
{">=", VersionOperator::GREATHER_OR_EQUAL},
|
||||
{"<=", VersionOperator::LESS_OR_EQUAL},
|
||||
VC_ENUM_END
|
||||
|
||||
enum class DependencyLevel {
|
||||
REQUIRED, // dependency must be installed
|
||||
OPTIONAL, // dependency will be installed if found
|
||||
@@ -41,7 +50,7 @@ struct DependencyPack {
|
||||
DependencyLevel level;
|
||||
std::string id;
|
||||
std::string version;
|
||||
std::string op;
|
||||
VersionOperator op;
|
||||
};
|
||||
|
||||
struct ContentPackStats {
|
||||
|
||||
@@ -26,26 +26,11 @@ Version::Version(const std::string& version) {
|
||||
if (parts.size() > 2) patch = parts[2];
|
||||
}
|
||||
|
||||
DependencyVersionOperator Version::string_to_operator(const std::string& op) {
|
||||
if (op == "=")
|
||||
return DependencyVersionOperator::EQUAL;
|
||||
else if (op == ">")
|
||||
return DependencyVersionOperator::GREATHER;
|
||||
else if (op == "<")
|
||||
return DependencyVersionOperator::LESS;
|
||||
else if (op == ">=" || op == "=>")
|
||||
return DependencyVersionOperator::GREATHER_OR_EQUAL;
|
||||
else if (op == "<=" || op == "=<")
|
||||
return DependencyVersionOperator::LESS_OR_EQUAL;
|
||||
else
|
||||
return DependencyVersionOperator::EQUAL;
|
||||
}
|
||||
|
||||
bool isNumber(const std::string& s) {
|
||||
return !s.empty() && std::all_of(s.begin(), s.end(), ::is_digit);
|
||||
}
|
||||
|
||||
bool Version::matches_pattern(const std::string& version) {
|
||||
bool Version::matchesPattern(const std::string& version) {
|
||||
for (char c : version) {
|
||||
if (!isdigit(c) && c != '.') {
|
||||
return false;
|
||||
|
||||
@@ -33,25 +33,22 @@ public:
|
||||
return !(*this > other);
|
||||
}
|
||||
|
||||
bool process_operator(const std::string& op, const Version& other) const {
|
||||
auto dep_op = Version::string_to_operator(op);
|
||||
|
||||
switch (dep_op) {
|
||||
case DependencyVersionOperator::EQUAL:
|
||||
bool processOperator(VersionOperator op, const Version& other) const {
|
||||
switch (op) {
|
||||
case VersionOperator::EQUAL:
|
||||
return *this == other;
|
||||
case DependencyVersionOperator::GREATHER:
|
||||
case VersionOperator::GREATHER:
|
||||
return *this > other;
|
||||
case DependencyVersionOperator::LESS:
|
||||
case VersionOperator::LESS:
|
||||
return *this < other;
|
||||
case DependencyVersionOperator::LESS_OR_EQUAL:
|
||||
case VersionOperator::LESS_OR_EQUAL:
|
||||
return *this <= other;
|
||||
case DependencyVersionOperator::GREATHER_OR_EQUAL:
|
||||
case VersionOperator::GREATHER_OR_EQUAL:
|
||||
return *this >= other;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static DependencyVersionOperator string_to_operator(const std::string& op);
|
||||
static bool matches_pattern(const std::string& version);
|
||||
static bool matchesPattern(const std::string& version);
|
||||
};
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#define VC_ENABLE_REFLECTION
|
||||
#include "PacksManager.hpp"
|
||||
|
||||
#include <queue>
|
||||
@@ -109,9 +110,9 @@ static bool resolve_dependencies(
|
||||
|
||||
auto dep_pack = found -> second;
|
||||
|
||||
if (Version::matches_pattern(dep.version) && Version::matches_pattern(dep_pack.version)
|
||||
if (Version::matchesPattern(dep.version) && Version::matchesPattern(dep_pack.version)
|
||||
&& Version(dep_pack.version)
|
||||
.process_operator(dep.op, Version(dep.version))
|
||||
.processOperator(dep.op, Version(dep.version))
|
||||
) {
|
||||
// dependency pack version meets the required one
|
||||
continue;
|
||||
@@ -120,7 +121,11 @@ static bool resolve_dependencies(
|
||||
continue;
|
||||
} else {
|
||||
throw contentpack_error(
|
||||
dep.id, io::path(), "does not meet required version '" + dep.op + dep.version +"' of '" + pack->id + "'"
|
||||
dep.id,
|
||||
io::path(),
|
||||
"does not meet required version '" +
|
||||
VersionOperatorMeta.getNameString(dep.op) + dep.version +
|
||||
"' of '" + pack->id + "'"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -96,12 +96,16 @@ void Shadows::setup(Shader& shader, const Weather& weather) {
|
||||
if (shadows) {
|
||||
const auto& worldInfo = level.getWorld()->getInfo();
|
||||
float cloudsIntensity = glm::max(worldInfo.fog, weather.clouds());
|
||||
float shadowsOpacity = 1.0f - cloudsIntensity;
|
||||
shadowsOpacity *= glm::sqrt(glm::abs(
|
||||
glm::mod((worldInfo.daytime + 0.5f) * 2.0f, 1.0f) * 2.0f - 1.0f
|
||||
));
|
||||
shader.uniform1i("u_screen", 0);
|
||||
shader.uniformMatrix("u_shadowsMatrix[0]", shadowCamera.getProjView());
|
||||
shader.uniformMatrix("u_shadowsMatrix[1]", wideShadowCamera.getProjView());
|
||||
shader.uniform3f("u_sunDir", shadowCamera.front);
|
||||
shader.uniform1i("u_shadowsRes", shadowMap->getResolution());
|
||||
shader.uniform1f("u_shadowsOpacity", 1.0f - cloudsIntensity); // TODO: make it configurable
|
||||
shader.uniform1f("u_shadowsOpacity", shadowsOpacity); // TODO: make it configurable
|
||||
shader.uniform1f("u_shadowsSoftness", 1.0f + cloudsIntensity * 4); // TODO: make it configurable
|
||||
|
||||
glActiveTexture(GL_TEXTURE0 + TARGET_SHADOWS0);
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace markdown {
|
||||
Result<wchar_t> process(std::wstring_view source, bool eraseMarkdown);
|
||||
|
||||
template <typename CharT>
|
||||
inline std::basic_string<CharT> escape(std::string_view source) {
|
||||
inline std::basic_string<CharT> escape(std::basic_string_view<CharT> source) {
|
||||
std::basic_stringstream<CharT> ss;
|
||||
int pos = 0;
|
||||
while (pos < source.size()) {
|
||||
|
||||
@@ -54,7 +54,12 @@ static int l_get_gravity_scale(lua::State* L) {
|
||||
|
||||
static int l_set_gravity_scale(lua::State* L) {
|
||||
if (auto entity = get_entity(L, 1)) {
|
||||
entity->getRigidbody().hitbox.gravityScale = lua::tovec3(L, 2).y;
|
||||
auto& hitbox = entity->getRigidbody().hitbox;
|
||||
if (lua::istable(L, 2)) {
|
||||
hitbox.gravityScale = lua::tovec3(L, 2).y;
|
||||
} else {
|
||||
hitbox.gravityScale = lua::tonumber(L, 2);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
#include <algorithm>
|
||||
#include <filesystem>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <set>
|
||||
#define VC_ENABLE_REFLECTION
|
||||
|
||||
#include "assets/AssetsLoader.hpp"
|
||||
#include "content/Content.hpp"
|
||||
@@ -19,6 +15,12 @@
|
||||
#include "world/World.hpp"
|
||||
#include "api_lua.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <filesystem>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <set>
|
||||
|
||||
using namespace scripting;
|
||||
|
||||
static int l_pack_get_folder(lua::State* L) {
|
||||
@@ -114,8 +116,16 @@ static int l_pack_get_info(
|
||||
default:
|
||||
throw std::runtime_error("");
|
||||
}
|
||||
auto opString = VersionOperatorMeta.getNameString(dpack.op);
|
||||
|
||||
lua::pushfstring(L, "%s%s@%s%s", prefix.c_str(), dpack.id.c_str(), dpack.op.c_str(), dpack.version.c_str());
|
||||
lua::pushfstring(
|
||||
L,
|
||||
"%s%s@%s%s",
|
||||
prefix.c_str(),
|
||||
dpack.id.c_str(),
|
||||
(dpack.op == VersionOperator::EQUAL ? "" : opString).c_str(),
|
||||
dpack.version.c_str()
|
||||
);
|
||||
lua::rawseti(L, i + 1);
|
||||
}
|
||||
lua::setfield(L, "dependencies");
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <random>
|
||||
|
||||
#include "lua_commons.hpp"
|
||||
|
||||
@@ -114,4 +115,20 @@ namespace lua {
|
||||
std::shared_ptr<ImageData> mData;
|
||||
};
|
||||
static_assert(!std::is_abstract<LuaCanvas>());
|
||||
|
||||
class LuaRandom : public Userdata {
|
||||
public:
|
||||
std::mt19937 rng;
|
||||
|
||||
explicit LuaRandom(uint64_t seed) : rng(seed) {}
|
||||
virtual ~LuaRandom() override = default;
|
||||
|
||||
const std::string& getTypeName() const override {
|
||||
return TYPENAME;
|
||||
}
|
||||
|
||||
static int createMetatable(lua::State*);
|
||||
inline static std::string TYPENAME = "__vc_Random";
|
||||
};
|
||||
static_assert(!std::is_abstract<LuaRandom>());
|
||||
}
|
||||
|
||||
@@ -169,5 +169,13 @@ State* lua::create_state(const EnginePaths& paths, StateType stateType) {
|
||||
auto file = "res:scripts/stdmin.lua";
|
||||
auto src = io::read_string(file);
|
||||
lua::pop(L, lua::execute(L, 0, src, "core:scripts/stdmin.lua"));
|
||||
|
||||
newusertype<LuaRandom>(L);
|
||||
if (getglobal(L, "random")) {
|
||||
if (getglobal(L, "__vc_Random")) {
|
||||
setfield(L, "Random");
|
||||
}
|
||||
pop(L);
|
||||
}
|
||||
return L;
|
||||
}
|
||||
|
||||
@@ -275,6 +275,15 @@ namespace lua {
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline T& require_userdata(lua::State* L, int idx) {
|
||||
if (void* rawptr = lua_touserdata(L, idx)) {
|
||||
return *static_cast<T*>(rawptr);
|
||||
}
|
||||
throw std::runtime_error("invalid 'self' value");
|
||||
}
|
||||
|
||||
template <class T, typename... Args>
|
||||
inline int newuserdata(lua::State* L, Args&&... args) {
|
||||
const auto& found = usertypeNames.find(typeid(T));
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
#include "../lua_custom_types.hpp"
|
||||
#include "../lua_util.hpp"
|
||||
|
||||
#include <chrono>
|
||||
|
||||
using namespace lua;
|
||||
using namespace std::chrono;
|
||||
|
||||
static int l_random(lua::State* L) {
|
||||
std::uniform_int_distribution<> dist(0, std::numeric_limits<int>::max());
|
||||
|
||||
auto& rng = require_userdata<LuaRandom>(L, 1).rng;
|
||||
size_t n = touinteger(L, 2);
|
||||
createtable(L, n, 0);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
pushnumber(L, dist(rng) / (double)std::numeric_limits<int>::max());
|
||||
rawseti(L, i + 1);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_seed(lua::State* L) {
|
||||
require_userdata<LuaRandom>(L, 1).rng = std::mt19937(lua::touinteger(L, 2));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_meta_meta_call(lua::State* L) {
|
||||
integer_t seed;
|
||||
if (lua::isnoneornil(L, 1)) {
|
||||
seed = system_clock::now().time_since_epoch().count();
|
||||
} else {
|
||||
seed = tointeger(L, 1);
|
||||
}
|
||||
return newuserdata<LuaRandom>(L, seed);
|
||||
}
|
||||
|
||||
int LuaRandom::createMetatable(lua::State* L) {
|
||||
createtable(L, 0, 3);
|
||||
|
||||
requireglobal(L, "__vc_create_random_methods");
|
||||
createtable(L, 0, 0);
|
||||
pushcfunction(L, wrap<l_random>);
|
||||
setfield(L, "random");
|
||||
pushcfunction(L, wrap<l_seed>);
|
||||
setfield(L, "seed");
|
||||
call(L, 1, 1);
|
||||
|
||||
setfield(L, "__index");
|
||||
|
||||
createtable(L, 0, 1);
|
||||
pushcfunction(L, wrap<l_meta_meta_call>);
|
||||
setfield(L, "__call");
|
||||
setmetatable(L);
|
||||
return 1;
|
||||
}
|
||||
+31
-16
@@ -620,6 +620,26 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
static sockaddr_in resolve_address_dgram(const std::string& address, int port) {
|
||||
sockaddr_in serverAddr{};
|
||||
addrinfo hints {};
|
||||
|
||||
hints.ai_family = AF_INET;
|
||||
hints.ai_socktype = SOCK_DGRAM;
|
||||
|
||||
addrinfo* addrinfo = nullptr;
|
||||
if (int res = getaddrinfo(
|
||||
address.c_str(), nullptr, &hints, &addrinfo
|
||||
)) {
|
||||
throw std::runtime_error(gai_strerror(res));
|
||||
}
|
||||
|
||||
std::memcpy(&serverAddr, addrinfo->ai_addr, sizeof(sockaddr_in));
|
||||
serverAddr.sin_port = htons(port);
|
||||
freeaddrinfo(addrinfo);
|
||||
return serverAddr;
|
||||
}
|
||||
|
||||
class SocketUdpConnection : public UdpConnection {
|
||||
u64id_t id;
|
||||
SOCKET descriptor;
|
||||
@@ -652,13 +672,7 @@ public:
|
||||
throw std::runtime_error("could not create udp socket");
|
||||
}
|
||||
|
||||
sockaddr_in serverAddr{};
|
||||
serverAddr.sin_family = AF_INET;
|
||||
if (inet_pton(AF_INET, address.c_str(), &serverAddr.sin_addr) <= 0) {
|
||||
closesocket(descriptor);
|
||||
throw std::runtime_error("invalid udp address: " + address);
|
||||
}
|
||||
serverAddr.sin_port = htons(port);
|
||||
sockaddr_in serverAddr = resolve_address_dgram(address, port);
|
||||
|
||||
if (::connect(descriptor, (sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) {
|
||||
auto err = handle_socket_error("udp connect failed");
|
||||
@@ -683,6 +697,7 @@ public:
|
||||
while (open) {
|
||||
int size = recv(descriptor, buffer.data(), buffer.size(), 0);
|
||||
if (size <= 0) {
|
||||
logger.error() <<id <<"udp connection " << id << handle_socket_error(" recv error").what();
|
||||
if (!open) break;
|
||||
closesocket(descriptor);
|
||||
state = ConnectionState::CLOSED;
|
||||
@@ -697,11 +712,12 @@ public:
|
||||
}
|
||||
|
||||
int send(const char* buffer, size_t length) override {
|
||||
int len = sendto(descriptor, buffer, length, 0,
|
||||
(sockaddr*)&addr, sizeof(addr));
|
||||
int len = ::send(descriptor, buffer, length, 0);
|
||||
if (len < 0) {
|
||||
auto err = handle_socket_error(" send failed");
|
||||
closesocket(descriptor);
|
||||
state = ConnectionState::CLOSED;
|
||||
logger.error() << "udp connection " << id << err.what();
|
||||
} else totalUpload += len;
|
||||
|
||||
return len;
|
||||
@@ -710,6 +726,7 @@ public:
|
||||
void close(bool discardAll=false) override {
|
||||
if (!open) return;
|
||||
open = false;
|
||||
logger.info() << "closing udp connection "<< id;
|
||||
|
||||
if (state != ConnectionState::CLOSED) {
|
||||
shutdown(descriptor, 2);
|
||||
@@ -789,13 +806,11 @@ public:
|
||||
}
|
||||
|
||||
void sendTo(const std::string& addr, int port, const char* buffer, size_t length) override {
|
||||
sockaddr_in client{};
|
||||
client.sin_family = AF_INET;
|
||||
inet_pton(AF_INET, addr.c_str(), &client.sin_addr);
|
||||
client.sin_port = htons(port);
|
||||
|
||||
sendto(descriptor, buffer, length, 0,
|
||||
reinterpret_cast<sockaddr*>(&client), sizeof(client));
|
||||
sockaddr_in client = resolve_address_dgram(addr, port);
|
||||
if (sendto(descriptor, buffer, length, 0,
|
||||
reinterpret_cast<sockaddr*>(&client), sizeof(client)) < 0) {
|
||||
logger.error() << handle_socket_error("sendto").what();
|
||||
}
|
||||
}
|
||||
|
||||
void close() override {
|
||||
|
||||
+62
-35
@@ -1,6 +1,9 @@
|
||||
#include "command_line.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "io/engine_paths.hpp"
|
||||
#include "util/ArgsReader.hpp"
|
||||
@@ -8,45 +11,69 @@
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
class ArgC {
|
||||
public:
|
||||
std::string keyword;
|
||||
std::function<bool()> execute;
|
||||
std::string help;
|
||||
ArgC(const std::string& keyword, std::function<bool()> execute, const std::string& help) {
|
||||
this->keyword = keyword;
|
||||
this->execute = execute;
|
||||
this->help = help;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static bool perform_keyword(
|
||||
util::ArgsReader& reader, const std::string& keyword, CoreParameters& params
|
||||
) {
|
||||
if (keyword == "--res") {
|
||||
params.resFolder = reader.next();
|
||||
} else if (keyword == "--dir") {
|
||||
params.userFolder = reader.next();
|
||||
} else if (keyword == "--project") {
|
||||
params.projectFolder = reader.next();
|
||||
} else if (keyword == "--help" || keyword == "-h") {
|
||||
std::cout << "VoxelCore v" << ENGINE_VERSION_STRING << "\n\n";
|
||||
std::cout << "command-line arguments:\n";
|
||||
std::cout << " --help - display this help\n";
|
||||
std::cout << " --version - display engine version\n";
|
||||
std::cout << " --res <path> - set resources directory\n";
|
||||
std::cout << " --dir <path> - set userfiles directory\n";
|
||||
std::cout << " --project <path> - set project directory\n";
|
||||
std::cout << " --headless - run in headless mode\n";
|
||||
std::cout << " --test <path> - test script file\n";
|
||||
std::cout << " --script <path> - main script file\n";
|
||||
std::cout << std::endl;
|
||||
return false;
|
||||
} else if (keyword == "--version") {
|
||||
std::cout << ENGINE_VERSION_STRING << std::endl;
|
||||
return false;
|
||||
} else if (keyword == "--headless") {
|
||||
params.headless = true;
|
||||
} else if (keyword == "--test") {
|
||||
auto token = reader.next();
|
||||
params.testMode = true;
|
||||
params.scriptFile = token;
|
||||
} else if (keyword == "--script") {
|
||||
auto token = reader.next();
|
||||
params.testMode = false;
|
||||
params.scriptFile = token;
|
||||
} else {
|
||||
throw std::runtime_error("unknown argument " + keyword);
|
||||
static const std::vector<ArgC> argumentsCommandline = {
|
||||
ArgC("--res", [¶ms, &reader]() -> bool {
|
||||
params.resFolder = reader.next();
|
||||
return true;
|
||||
}, "<path> - set resources directory."),
|
||||
ArgC("--dir", [¶ms, &reader]() -> bool {
|
||||
params.userFolder = reader.next();
|
||||
return true;
|
||||
}, "<path> - set userfiles directory."),
|
||||
ArgC("--project", [¶ms, &reader]() -> bool {
|
||||
params.projectFolder = reader.next();
|
||||
return true;
|
||||
}, "<path> - set project directory."),
|
||||
ArgC("--test", [¶ms, &reader]() -> bool {
|
||||
params.testMode = true;
|
||||
params.scriptFile = reader.next();
|
||||
return true;
|
||||
}, "<path> - test script file."),
|
||||
ArgC("--script", [¶ms, &reader]() -> bool {
|
||||
params.testMode = false;
|
||||
params.scriptFile = reader.next();
|
||||
return true;
|
||||
}, "<path> - main script file."),
|
||||
ArgC("--headless", [¶ms]() -> bool {
|
||||
params.headless = true;
|
||||
return true;
|
||||
}, "- run in headless mode."),
|
||||
ArgC("--version", []() -> bool {
|
||||
std::cout << ENGINE_VERSION_STRING << std::endl;
|
||||
return false;
|
||||
}, "- display the engine version."),
|
||||
ArgC("--help", []() -> bool {
|
||||
std::cout << "VoxelCore v" << ENGINE_VERSION_STRING << "\n\n";
|
||||
std::cout << "Command-line arguments:\n";
|
||||
for (auto& a : argumentsCommandline) {
|
||||
std::cout << a.keyword << " " << a.help << std::endl;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
return false;
|
||||
}, "- display this help.")
|
||||
};
|
||||
for (auto& a : argumentsCommandline) {
|
||||
if (a.keyword == keyword) {
|
||||
return a.execute();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
throw std::runtime_error("unknown argument " + keyword);
|
||||
}
|
||||
|
||||
bool parse_cmdline(int argc, char** argv, CoreParameters& params) {
|
||||
|
||||
@@ -40,7 +40,7 @@ std::string util::escape(std::string_view s, bool escapeUnicode) {
|
||||
uint cpsize;
|
||||
int codepoint = decode_utf8(cpsize, s.data() + pos);
|
||||
if (escapeUnicode) {
|
||||
ss << "\\u" << std::hex << codepoint;
|
||||
ss << "\\u" << std::setw(4) << std::setfill('0') << std::hex << codepoint;
|
||||
} else {
|
||||
ss << std::string(s.data() + pos, cpsize);
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
static debug::Logger logger("window");
|
||||
|
||||
static std::unordered_set<std::string> supported_gl_extensions;
|
||||
static void window_size_callback(GLFWwindow* window, int width, int height);
|
||||
|
||||
static void init_gl_extensions_list() {
|
||||
GLint numExtensions = 0;
|
||||
@@ -418,7 +419,7 @@ public:
|
||||
if (fullscreen) {
|
||||
glfwGetWindowPos(window, &posX, &posY);
|
||||
glfwSetWindowMonitor(
|
||||
window, monitor, 0, 0, mode->width, mode->height, GLFW_DONT_CARE
|
||||
window, monitor, 0, 0, mode->width, mode->height, mode->refreshRate
|
||||
);
|
||||
} else {
|
||||
glfwSetWindowMonitor(
|
||||
@@ -430,6 +431,7 @@ public:
|
||||
settings->height.get(),
|
||||
GLFW_DONT_CARE
|
||||
);
|
||||
window_size_callback(window, settings->width.get(), settings->height.get());
|
||||
}
|
||||
|
||||
double xPos, yPos;
|
||||
@@ -596,6 +598,17 @@ static void cursor_pos_callback(GLFWwindow* window, double xpos, double ypos) {
|
||||
handler->input.setCursorPosition(xpos, ypos);
|
||||
}
|
||||
|
||||
static void iconify_callback(GLFWwindow* window, int iconified) {
|
||||
auto handler = static_cast<GLFWWindow*>(glfwGetWindowUserPointer(window));
|
||||
if (handler->isFullscreen() && iconified == 0) {
|
||||
GLFWmonitor* monitor = glfwGetPrimaryMonitor();
|
||||
const GLFWvidmode* mode = glfwGetVideoMode(monitor);
|
||||
glfwSetWindowMonitor(
|
||||
window, monitor, 0, 0, mode->width, mode->height, mode->refreshRate
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static void create_standard_cursors() {
|
||||
for (int i = 0; i <= static_cast<int>(CursorShape::LAST); i++) {
|
||||
int cursor = GLFW_ARROW_CURSOR + i;
|
||||
@@ -615,6 +628,7 @@ static void setup_callbacks(GLFWwindow* window) {
|
||||
glfwSetWindowSizeCallback(window, window_size_callback);
|
||||
glfwSetCharCallback(window, character_callback);
|
||||
glfwSetScrollCallback(window, scroll_callback);
|
||||
glfwSetWindowIconifyCallback(window, iconify_callback);
|
||||
}
|
||||
|
||||
std::tuple<
|
||||
|
||||
Reference in New Issue
Block a user