Document StringParser because otherwise I'd have no idea what it's doing in two months.
parent
29a082aa9c
commit
05af3222ee
|
@ -60,7 +60,7 @@ TextureAtlas::TextureAtlas(uvec2 size) :
|
||||||
* @param tex - The string of the texture to convert.
|
* @param tex - The string of the texture to convert.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
parser.addLiteralFnCtx<string>([](TexParser::Ctx& ctx, string tex) {
|
parser.addLiteralFnCtx([](TexParser::Ctx& ctx, string tex) {
|
||||||
return TexParser::Data { std::make_shared<RawTexData>(ctx.atlas.getBytesOfTex(tex)) };
|
return TexParser::Data { std::make_shared<RawTexData>(ctx.atlas.getBytesOfTex(tex)) };
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,17 @@
|
||||||
#include "game/atlas/ServerDefinitionAtlas.h"
|
#include "game/atlas/ServerDefinitionAtlas.h"
|
||||||
|
|
||||||
namespace RegisterBlock {
|
namespace RegisterBlock {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
struct TintParserData {
|
||||||
|
string tex;
|
||||||
|
optional<u32> tint;
|
||||||
|
optional<string> mask;
|
||||||
|
};
|
||||||
|
|
||||||
|
using TintParser = StringParser<TintParserData>;
|
||||||
|
TintParser parser {};
|
||||||
|
bool parserReady = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes a lua selection box table list, and returns a vector of selection boxes.
|
* Takes a lua selection box table list, and returns a vector of selection boxes.
|
||||||
|
@ -37,44 +47,6 @@ namespace RegisterBlock {
|
||||||
return boxes;
|
return boxes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given a textures string, attempts to find a tint() texture modifier and modifies the inputted parameters
|
|
||||||
* to describe it. Does nothing to the passed in variables if there is tint() is not used.
|
|
||||||
*
|
|
||||||
* @param texture - The texture string, will be replaced with the inner string if tint() is used.
|
|
||||||
* @param blendInd - A variable reference that will be assigned the index of the tint blend, if there is one.
|
|
||||||
* @param blendMask - A variable reference to the blend mask texture, which will be assigned if one is found.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static inline void getMeshPartTexture(std::string& texture, unsigned int& blendInd, std::string& blendMask) {
|
|
||||||
if (strncmp(texture.data(), "tint(", 5) == 0 && texture.find_last_of(')') != std::string::npos) {
|
|
||||||
// Biome tinting time
|
|
||||||
texture.erase(std::remove_if(texture.begin(), texture.end(), isspace), texture.end());
|
|
||||||
|
|
||||||
std::string::size_type paramsBegin = texture.find_first_of('(');
|
|
||||||
std::string::size_type paramsEnd = texture.find_last_of(')');
|
|
||||||
|
|
||||||
std::string paramsString = texture.substr(paramsBegin + 1, paramsEnd - paramsBegin - 1);
|
|
||||||
|
|
||||||
std::vector<std::string> params;
|
|
||||||
std::string::size_type pos;
|
|
||||||
while ((pos = paramsString.find(',')) != std::string::npos) {
|
|
||||||
params.push_back(paramsString.substr(0, pos));
|
|
||||||
paramsString.erase(0, pos + 1);
|
|
||||||
}
|
|
||||||
params.push_back(paramsString);
|
|
||||||
|
|
||||||
if (params.size() < 2)
|
|
||||||
throw std::runtime_error("Invalid biome tint values. Must have at least 2 params.");
|
|
||||||
|
|
||||||
texture = params[1];
|
|
||||||
blendInd = atoi(params[0].data()) + 1; //TODO: support multiple blend colors
|
|
||||||
blendMask = (params.size() >= 3 ? params[2] : "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates near and far models for a block based on the passed in parameters.
|
* Creates near and far models for a block based on the passed in parameters.
|
||||||
*
|
*
|
||||||
|
@ -141,7 +113,7 @@ namespace RegisterBlock {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse through all of the parts and add them to the model
|
// Parse through all the parts and add them to the model
|
||||||
auto partsOpt = modelTable.get<sol::optional<sol::table>>("parts");
|
auto partsOpt = modelTable.get<sol::optional<sol::table>>("parts");
|
||||||
if (!partsOpt) throw std::runtime_error("blockmodel is missing parts table");
|
if (!partsOpt) throw std::runtime_error("blockmodel is missing parts table");
|
||||||
partsOpt->for_each([&](sol::object key, sol::object value) {
|
partsOpt->for_each([&](sol::object key, sol::object value) {
|
||||||
|
@ -183,20 +155,17 @@ namespace RegisterBlock {
|
||||||
|
|
||||||
// Get the part's texture
|
// Get the part's texture
|
||||||
int tex = std::max(static_cast<int>(meshPartTable.get_or<float>("tex", 1)), 1);
|
int tex = std::max(static_cast<int>(meshPartTable.get_or<float>("tex", 1)), 1);
|
||||||
|
let data = parser.parse(textures[std::min(tex - 1, (int) textures.size() - 1)]);
|
||||||
auto texture = textures[std::min(tex - 1, (int) textures.size() - 1)];
|
u32 blendInd = data.tint ? *data.tint + 1 : 0;
|
||||||
unsigned int blendInd = 0;
|
|
||||||
std::string blendMask = "";
|
|
||||||
getMeshPartTexture(texture, blendInd, blendMask);
|
|
||||||
|
|
||||||
// Add texture refs to blockModel if the textures table is provided
|
// Add texture refs to blockModel if the textures table is provided
|
||||||
std::shared_ptr<AtlasRef> textureRef = nullptr, blendMaskRef = nullptr;
|
std::shared_ptr<AtlasRef> textureRef = nullptr, blendMaskRef = nullptr;
|
||||||
if (atlas) {
|
if (atlas) {
|
||||||
textureRef = (*atlas)[texture];
|
textureRef = (*atlas)[data.tex];
|
||||||
model.textureRefs.insert(textureRef);
|
model.textureRefs.insert(textureRef);
|
||||||
|
|
||||||
if (blendInd && !blendMask.empty()) {
|
if (blendInd && data.mask) {
|
||||||
blendMaskRef = (*atlas)[blendMask];
|
blendMaskRef = (*atlas)[*data.mask];
|
||||||
model.textureRefs.insert(blendMaskRef);
|
model.textureRefs.insert(blendMaskRef);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -259,14 +228,12 @@ namespace RegisterBlock {
|
||||||
std::vector<std::shared_ptr<AtlasRef>> blendMaskRefs;
|
std::vector<std::shared_ptr<AtlasRef>> blendMaskRefs;
|
||||||
|
|
||||||
for (auto i = 0; i < lowdef_textures.size(); i++) {
|
for (auto i = 0; i < lowdef_textures.size(); i++) {
|
||||||
std::string texture = lowdef_textures[i];
|
let data = parser.parse(lowdef_textures[i]);
|
||||||
unsigned int blendInd = 0;
|
u32 blendInd = data.tint ? *data.tint + 1 : 0;
|
||||||
std::string blendMask = "";
|
|
||||||
getMeshPartTexture(texture, blendInd, blendMask);
|
|
||||||
|
|
||||||
textureRefs.push_back((*atlas)[texture]);
|
textureRefs.push_back((*atlas)[data.tex]);
|
||||||
blendInds.push_back(blendInd);
|
blendInds.push_back(blendInd);
|
||||||
blendMaskRefs.push_back(blendMask != "" ? (*atlas)[blendMask] : nullptr);
|
blendMaskRefs.push_back(data.mask ? (*atlas)[*data.mask] : nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
farModel = BlockModel::createCube(textureRefs, blendInds, blendMaskRefs);
|
farModel = BlockModel::createCube(textureRefs, blendInds, blendMaskRefs);
|
||||||
|
@ -413,6 +380,27 @@ namespace RegisterBlock {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the parser with the necessary parse functions.
|
||||||
|
* In the future, this could be cleaned up, but as it is it's totally fine.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void initParser() {
|
||||||
|
if (parserReady) return;
|
||||||
|
|
||||||
|
parser.setUnknownFnsAreLiteral(true);
|
||||||
|
|
||||||
|
parser.addFn<u32, TintParserData, optional<TintParserData>>("tint",
|
||||||
|
[](u32 tint, TintParserData tex, optional<TintParserData> mask) {
|
||||||
|
return TintParserData { tex.tex, tint, mask ? optional(mask->tex) : std::nullopt };
|
||||||
|
});
|
||||||
|
|
||||||
|
parser.addLiteralFn([](string tex) {
|
||||||
|
return TintParserData { tex, std::nullopt, std::nullopt };
|
||||||
|
});
|
||||||
|
|
||||||
|
parserReady = true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Server method to register a block. Calls registerBlock with the necessary parameters.
|
* Server method to register a block. Calls registerBlock with the necessary parameters.
|
||||||
|
@ -424,11 +412,11 @@ namespace RegisterBlock {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void server(sol::table& core, ServerSubgame& game, const std::string& identifier) {
|
static void server(sol::table& core, ServerSubgame& game, const std::string& identifier) {
|
||||||
|
initParser();
|
||||||
registerBlock(core["registered_blocks"], core["registered_blockmodels"],
|
registerBlock(core["registered_blocks"], core["registered_blockmodels"],
|
||||||
identifier, game.getDefs(), nullptr);
|
identifier, game.getDefs(), nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Client method to register a block. Calls registerBlock with the necessary parameters.
|
* Client method to register a block. Calls registerBlock with the necessary parameters.
|
||||||
* Registers a block to the DefinitionAtlas.
|
* Registers a block to the DefinitionAtlas.
|
||||||
|
@ -439,6 +427,7 @@ namespace RegisterBlock {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void client(sol::table& core, LocalSubgame& game, const std::string& identifier) {
|
static void client(sol::table& core, LocalSubgame& game, const std::string& identifier) {
|
||||||
|
initParser();
|
||||||
registerBlock(core["registered_blocks"], core["registered_blockmodels"],
|
registerBlock(core["registered_blocks"], core["registered_blockmodels"],
|
||||||
identifier, game.getDefs(), &game.textures);
|
identifier, game.getDefs(), &game.textures);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,102 +5,193 @@
|
||||||
|
|
||||||
#include "util/Types.h"
|
#include "util/Types.h"
|
||||||
|
|
||||||
|
/** SFINAE Helpers. */
|
||||||
namespace {
|
namespace {
|
||||||
|
/** Struct used for identifying variants in SFINAE. */
|
||||||
template<typename T> struct is_variant : std::false_type {};
|
template<typename T> struct is_variant : std::false_type {};
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
struct is_variant<std::variant<Args...>> : std::true_type {};
|
struct is_variant<std::variant<Args...>> : std::true_type {};
|
||||||
|
|
||||||
|
/** Const bool used for identifying variants in SFINAE. */
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline constexpr bool is_variant_v = is_variant<T>::value;
|
inline constexpr bool is_variant_v = is_variant<T>::value;
|
||||||
|
|
||||||
|
/** Struct used for identifying optionals in SFINAE. */
|
||||||
template<typename T> struct is_optional : std::false_type {};
|
template<typename T> struct is_optional : std::false_type {};
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
struct is_optional<std::optional<Args...>> : std::true_type {};
|
struct is_optional<std::optional<Args...>> : std::true_type {};
|
||||||
|
|
||||||
|
/** Const bool used for identifying optionals in SFINAE. */
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline constexpr bool is_optional_v = is_optional<T>::value;
|
inline constexpr bool is_optional_v = is_optional<T>::value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exposes a method to parse a string containing recursive functions,
|
||||||
|
* e.g: "tint(0, crop(0, 0, 16, 16, my_texture))".
|
||||||
|
* Functions are defined using template parameters and coerced from the string,
|
||||||
|
* executed in the order that they are used in the string and used to create an output.
|
||||||
|
*
|
||||||
|
* @tparam R - The type that parse() and all declared functions will return.
|
||||||
|
* @tparam C - An optional context type, which an instance of can be passed to parse() and accessed in functions.
|
||||||
|
*/
|
||||||
|
|
||||||
template <typename R, typename C = nullptr_t>
|
template <typename R, typename C = nullptr_t>
|
||||||
class StringParser {
|
class StringParser {
|
||||||
public:
|
|
||||||
typedef R Data;
|
|
||||||
typedef C Ctx;
|
|
||||||
|
|
||||||
class Fn;
|
/** A type alias for a vector of string parameters that will be passed into a Fn. */
|
||||||
|
using STR_ARGS = const vec<std::string_view>&;
|
||||||
using EXEC_ARGS = const vec<std::string_view>&;
|
|
||||||
using EXEC_FN = std::function<R(C&, EXEC_ARGS)>;
|
/** A wrapped function that will accept an STR_ARGS and a Context, and execute a defined function with them. */
|
||||||
|
using PARSE_FN = std::function<R(C&, STR_ARGS)>;
|
||||||
struct Fn {
|
|
||||||
Fn(EXEC_FN exec): exec(exec) {};
|
public:
|
||||||
|
|
||||||
R operator()(C& ctx, EXEC_ARGS args) const {
|
/** The data type of this parser. */
|
||||||
return exec(ctx, args);
|
typedef R Data;
|
||||||
}
|
|
||||||
|
/** The context type of this parser. Will be nullptr_t if no context type is specified. */
|
||||||
private:
|
typedef C Ctx;
|
||||||
EXEC_FN exec;
|
|
||||||
};
|
|
||||||
|
|
||||||
explicit StringParser() = default;
|
explicit StringParser() = default;
|
||||||
|
|
||||||
|
/** If set to true, when an unknown function is read it will be passed to the literal function as a string. */
|
||||||
|
void setUnknownFnsAreLiteral(bool state) {
|
||||||
|
unknownFnsAreLiteral = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a function to the functions map.
|
||||||
|
* For a function to be valid, it must only have parameters that are
|
||||||
|
* integral, floating point, strings, the Data type, or optionals & variants of them.
|
||||||
|
* It must also return a Data type. The Args type parameter must match the function's types.
|
||||||
|
* If the function needs access to the Context, use addFnCtx() instead.
|
||||||
|
*
|
||||||
|
* @tparam Args - The argument types of the function.
|
||||||
|
* @param name - The name of the function.
|
||||||
|
* @param fn - The function lambda.
|
||||||
|
*/
|
||||||
|
|
||||||
template <typename... Args, typename Func>
|
template <typename... Args, typename Func>
|
||||||
void addFn(const string& name, const Func& fn) {
|
void addFn(const string& name, const Func& fn) {
|
||||||
functions.emplace(name, [=, this](C& ctx, EXEC_ARGS strArgs) {
|
functions.emplace(name, [=, this](C& ctx, STR_ARGS strArgs) {
|
||||||
std::tuple<Args...> args = {};
|
std::tuple<Args...> args = {};
|
||||||
parseStrArgs<std::tuple<Args...>>(strArgs, args, ctx);
|
parseStrArgs<std::tuple<Args...>>(strArgs, args, ctx);
|
||||||
return std::apply(fn, args);
|
return std::apply(fn, args);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a function to the functions map that has access to the Ctx.
|
||||||
|
* The same restrictions for a function apply, but the function
|
||||||
|
* must also accept a reference to a Ctx before all other arguments.
|
||||||
|
* This parameter should not be specified in Args.
|
||||||
|
*
|
||||||
|
* @tparam Args - The argument types of the function.
|
||||||
|
* @param name - The name of the function.
|
||||||
|
* @param fn - The function lambda.
|
||||||
|
*/
|
||||||
|
|
||||||
template <typename... Args, typename Func>
|
template <typename... Args, typename Func>
|
||||||
void addFnCtx(const string& name, const Func& fn) {
|
void addFnCtx(const string& name, const Func& fn) {
|
||||||
functions.emplace(name, [=, this](C& ctx, EXEC_ARGS strArgs) {
|
functions.emplace(name, [=, this](C& ctx, STR_ARGS strArgs) {
|
||||||
std::tuple<Args...> args = {};
|
std::tuple<Args...> args = {};
|
||||||
parseStrArgs<std::tuple<Args...>>(strArgs, args, ctx);
|
parseStrArgs<std::tuple<Args...>>(strArgs, args, ctx);
|
||||||
return std::apply(fn, std::tuple_cat(std::tuple<C&>(ctx), args));
|
return std::apply(fn, std::tuple_cat(std::tuple<C&>(ctx), args));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename... Args, typename Func>
|
/**
|
||||||
void addLiteralFn(const Func& fn) {
|
* Shortcut to add the literal function, which is called when a string literal is found.
|
||||||
addFn<Args...>("_", fn);
|
* This is shorthand for calling addFn<string>("_", ...).
|
||||||
|
* The literal function must only accept a single string parameter.
|
||||||
|
*
|
||||||
|
* @param fn - The literal function lambda.
|
||||||
|
*/
|
||||||
|
|
||||||
|
template <typename Func>
|
||||||
|
inline void addLiteralFn(const Func& fn) {
|
||||||
|
addFn<string>("_", fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename... Args, typename Func>
|
/**
|
||||||
void addLiteralFnCtx(const Func& fn) {
|
* Shortcut to add the literal function that has access to the Ctx.
|
||||||
addFnCtx<Args...>("_", fn);
|
* The same restrictions for a literal function apply, but the function
|
||||||
|
* must also accept a reference to a Ctx before the string parameter.
|
||||||
|
*
|
||||||
|
* @param fn - The literal function lambda.
|
||||||
|
*/
|
||||||
|
|
||||||
|
template <typename Func>
|
||||||
|
inline void addLiteralFnCtx(const Func& fn) {
|
||||||
|
addFnCtx<string>("_", fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a string using the functions defined.
|
||||||
|
* This method may only be called if no context was specified.
|
||||||
|
*
|
||||||
|
* @param str - The string to parse.
|
||||||
|
* @returns the parsed result.
|
||||||
|
*/
|
||||||
|
|
||||||
const R parse(string str) const {
|
const R parse(string str) const {
|
||||||
const nullptr_t ctx {};
|
const nullptr_t ctx {};
|
||||||
str.erase(std::remove_if(str.begin(), str.end(), isspace), str.end());
|
str.erase(std::remove_if(str.begin(), str.end(), isspace), str.end());
|
||||||
return std::move(parseRaw(str, const_cast<C&>(ctx)));
|
return std::move(parseRaw(str, const_cast<C&>(ctx)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a string using the functions defined.
|
||||||
|
*
|
||||||
|
* @param str - The string to parse.
|
||||||
|
* @param ctx - The context to parse with, passed to all functions that use Ctx.
|
||||||
|
* @returns the parsed result.
|
||||||
|
*/
|
||||||
|
|
||||||
const R parse(string str, C& ctx) const {
|
const R parse(string str, C& ctx) const {
|
||||||
str.erase(std::remove_if(str.begin(), str.end(), isspace), str.end());
|
str.erase(std::remove_if(str.begin(), str.end(), isspace), str.end());
|
||||||
return std::move(parseRaw(str, ctx));
|
return std::move(parseRaw(str, ctx));
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const R parseRaw(const std::string_view str, C& ctx = {}) const {
|
|
||||||
|
/**
|
||||||
|
* Parses a the string segment provided as a function or string literal.
|
||||||
|
*
|
||||||
|
* @param str - The string segment to parse.
|
||||||
|
* @param ctx - The context to parse with.
|
||||||
|
* @returns the parsed result.
|
||||||
|
*/
|
||||||
|
|
||||||
|
inline const R parseRaw(const std::string_view str, C& ctx) const {
|
||||||
if (strIsFunction(str)) {
|
if (strIsFunction(str)) {
|
||||||
let func = parseFunction(str);
|
let func = parseFunction(str);
|
||||||
const let f = functions.find(string(func.first));
|
const let f = functions.find(string(func.first));
|
||||||
if (f == functions.end()) throw std::invalid_argument("Unknown function '" + string(func.first) + "'!");
|
if (f == functions.end()) {
|
||||||
return f->second(ctx, func.second);
|
if (!unknownFnsAreLiteral) throw std::invalid_argument(
|
||||||
}
|
"Unknown function '" + string(func.first) + "'.");
|
||||||
else {
|
}
|
||||||
const let& f = functions.find("_");
|
else return f->second(ctx, func.second);
|
||||||
if (f == functions.end()) throw std::invalid_argument("No default function handler!");
|
|
||||||
return f->second(ctx, { str });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const let& f = functions.find("_");
|
||||||
|
if (f == functions.end()) throw std::invalid_argument("Literal specified with no literal function.");
|
||||||
|
return f->second(ctx, { str });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a string segment starting and a start position pointing to an open parenthesis,
|
||||||
|
* finds the index of matching closing parenthesis.
|
||||||
|
*
|
||||||
|
* @param str - The string segment to search through.
|
||||||
|
* @param start - The position of the opening parenthesis to start at.
|
||||||
|
* @returns the index of the start parenthesis' closing parenthesis.
|
||||||
|
* @throws if the parentheses are unbalanced.
|
||||||
|
*/
|
||||||
|
|
||||||
const usize findClosingParen(const std::string_view& str, usize start) const {
|
const usize findClosingParen(const std::string_view& str, usize start) const {
|
||||||
usize levels = 0;
|
usize levels = 0;
|
||||||
for (usize i = start + 1; i < str.size(); i++) {
|
for (usize i = start + 1; i < str.size(); i++) {
|
||||||
|
@ -114,17 +205,29 @@ private:
|
||||||
throw std::invalid_argument("Mismatched parentheses.");
|
throw std::invalid_argument("Mismatched parentheses.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the string segment provided is a function call.
|
||||||
|
*
|
||||||
|
* @param str - the string segment to check.
|
||||||
|
* @returns a boolean indicating if the string segment is a function call.
|
||||||
|
*/
|
||||||
|
|
||||||
const bool strIsFunction(const std::string_view& str) const {
|
const bool strIsFunction(const std::string_view& str) const {
|
||||||
return str.find_first_of('(') != string::npos;
|
return str.find_first_of('(') != string::npos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a function and finds its name and parameters.
|
||||||
|
* Assumes that the string is a function, which should be checked beforehand with strIsFunction.
|
||||||
|
*
|
||||||
|
* @param str - The string to parse as a function.
|
||||||
|
* @returns a pair containing the function name, and a vector of parameter strings.
|
||||||
|
*/
|
||||||
|
|
||||||
const std::pair<std::string_view, vec<std::string_view>> parseFunction(const std::string_view& str) const {
|
const std::pair<std::string_view, vec<std::string_view>> parseFunction(const std::string_view& str) const {
|
||||||
let nextParen = str.find_first_of('(');
|
let nextParen = str.find_first_of('(');
|
||||||
let nextComma = str.find_first_of(',');
|
let nextComma = str.find_first_of(',');
|
||||||
|
|
||||||
if (nextParen == string::npos || (nextComma != string::npos && nextComma < nextParen))
|
|
||||||
throw std::invalid_argument("Not a function");
|
|
||||||
|
|
||||||
let name = str.substr(0, nextParen);
|
let name = str.substr(0, nextParen);
|
||||||
vec<std::string_view> args {};
|
vec<std::string_view> args {};
|
||||||
|
|
||||||
|
@ -144,26 +247,87 @@ private:
|
||||||
return { name, args };
|
return { name, args };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a string argument from an STR_ARGS.
|
||||||
|
*
|
||||||
|
* @tparam T - std::string
|
||||||
|
* @tparam I - The index of the parameter to parse in the args vector.
|
||||||
|
* @param args - An STR_ARGS to pull the parameter from.
|
||||||
|
* @returns the string value.
|
||||||
|
* @throws if the parameter cannot be interpreted as a string, or if there were not enough parameters.
|
||||||
|
*/
|
||||||
|
|
||||||
template <typename T, usize I, std::enable_if_t<std::is_same_v<T, string>, bool> = true>
|
template <typename T, usize I, std::enable_if_t<std::is_same_v<T, string>, bool> = true>
|
||||||
T parseStrArg(EXEC_ARGS args, C&) {
|
T parseStrArg(STR_ARGS args, C&) {
|
||||||
if (I >= args.size()) throw std::invalid_argument("Not enough parameters.");
|
if (I >= args.size()) throw std::invalid_argument("Not enough parameters.");
|
||||||
return string(args[I]);
|
return string(args[I]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses an integral argument from an STR_ARGS.
|
||||||
|
*
|
||||||
|
* @tparam T - An integral type, e.g u8, i32, usize...
|
||||||
|
* @tparam I - The index of the parameter to parse in the args vector.
|
||||||
|
* @param args - An STR_ARGS to pull the parameter from.
|
||||||
|
* @returns the integral value.
|
||||||
|
* @throws if the parameter cannot be interpreted as an integer, or if there were not enough parameters.
|
||||||
|
*/
|
||||||
|
|
||||||
template <typename T, usize I, std::enable_if_t<std::is_integral_v<T>, bool> = true>
|
template <typename T, usize I, std::enable_if_t<std::is_integral_v<T>, bool> = true>
|
||||||
T parseStrArg(EXEC_ARGS args, C&) {
|
T parseStrArg(STR_ARGS args, C&) {
|
||||||
if (I >= args.size()) throw std::invalid_argument("Not enough parameters.");
|
if (I >= args.size()) throw std::invalid_argument("Not enough parameters.");
|
||||||
return std::stoi(args[I].data());
|
return std::stoi(args[I].data());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a floating point argument from an STR_ARGS.
|
||||||
|
*
|
||||||
|
* @tparam T - A floating point type, i.e f32 or f64.
|
||||||
|
* @tparam I - The index of the parameter to parse in the args vector.
|
||||||
|
* @param args - An STR_ARGS to pull the parameter from.
|
||||||
|
* @returns the floating point value.
|
||||||
|
* @throws if the parameter cannot be interpreted as a floating point, or if there were not enough parameters.
|
||||||
|
*/
|
||||||
|
|
||||||
template <typename T, usize I, std::enable_if_t<std::is_floating_point_v<T>, bool> = true>
|
template <typename T, usize I, std::enable_if_t<std::is_floating_point_v<T>, bool> = true>
|
||||||
T parseStrArg(EXEC_ARGS args, C&) {
|
T parseStrArg(STR_ARGS args, C&) {
|
||||||
if (I >= args.size()) throw std::invalid_argument("Not enough parameters.");
|
if (I >= args.size()) throw std::invalid_argument("Not enough parameters.");
|
||||||
return std::stod(args[I].data());
|
return std::stod(args[I].data());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a Data type argument from an STR_ARGS.
|
||||||
|
* A parse function will have a Data type argument if it wants to accept the output from another function.
|
||||||
|
*
|
||||||
|
* @tparam T - The Data type.
|
||||||
|
* @tparam I - The index of the parameter to parse in the args vector.
|
||||||
|
* @param args - An STR_ARGS to pull the parameter from.
|
||||||
|
* @param ctx - The context to pass into the parse functions.
|
||||||
|
* @returns the Data result from whatever inner functions were executed.
|
||||||
|
* @throws if the parameter cannot be parsed as a Data type, or if there were not enough parameters.
|
||||||
|
*/
|
||||||
|
|
||||||
|
template <typename T, usize I, std::enable_if_t<std::is_same_v<T, R>, bool> = true>
|
||||||
|
T parseStrArg(STR_ARGS args, C& ctx) {
|
||||||
|
if (I >= args.size()) throw std::invalid_argument("Not enough parameters.");
|
||||||
|
return parseRaw(parseStrArg<string, I>(args, ctx), ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compile-time iterates over a variant type, checking if the parameter specified
|
||||||
|
* matches any of the types in it. If one matches, it is parsed and returned.
|
||||||
|
*
|
||||||
|
* @tparam T - A variant type containing other parsable types.
|
||||||
|
* @tparam I - The index of the parameter to parse in the **args vector.**
|
||||||
|
* @tparam VI - The index of the variant to try to parse.
|
||||||
|
* @param args - An STR_ARGS to pull the parameter from.
|
||||||
|
* @param ctx - The context to pass into the parse functions.
|
||||||
|
* @returns a variant containing the first type that the parameter can be parsed as.
|
||||||
|
* @throws if the parameter cannot be parsed as any of the variant types.
|
||||||
|
*/
|
||||||
|
|
||||||
template <typename T, usize I, usize VI = 0>
|
template <typename T, usize I, usize VI = 0>
|
||||||
T parseStrVariantArg(EXEC_ARGS args, C& ctx) {
|
inline T parseStrVariantArg(STR_ARGS args, C& ctx) {
|
||||||
try {
|
try {
|
||||||
return parseStrArg<std::variant_alternative_t<VI, T>, I>(args, ctx);
|
return parseStrArg<std::variant_alternative_t<VI, T>, I>(args, ctx);
|
||||||
}
|
}
|
||||||
|
@ -176,29 +340,63 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a variant argument from an STR_ARGS.
|
||||||
|
* The variant can contain any other parsable types.
|
||||||
|
*
|
||||||
|
* @tparam T - The variant type.
|
||||||
|
* @tparam I - The index of the parameter to parse in the args vector.
|
||||||
|
* @param args - An STR_ARGS to pull the parameter from.
|
||||||
|
* @param ctx - The context to pass into the parse functions.
|
||||||
|
* @returns a variant containing the first type that the parameter can be parsed as.
|
||||||
|
* @throws if the parameter cannot be parsed as any of the variant types, or if there were not enough parameters.
|
||||||
|
*/
|
||||||
|
|
||||||
template<typename T, usize I, std::enable_if_t<is_variant_v<T>, bool> = true>
|
template<typename T, usize I, std::enable_if_t<is_variant_v<T>, bool> = true>
|
||||||
T parseStrArg(EXEC_ARGS args, C& ctx) {
|
T parseStrArg(STR_ARGS args, C& ctx) {
|
||||||
if (I >= args.size()) throw std::invalid_argument("Not enough parameters.");
|
if (I >= args.size()) throw std::invalid_argument("Not enough parameters.");
|
||||||
return parseStrVariantArg<T, I>(args, ctx);
|
return parseStrVariantArg<T, I>(args, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses an optional argument from an STR_ARGS.
|
||||||
|
* The optional can contain any parsable type, including variants and other optionals.*
|
||||||
|
* * but why the hell would you do that?
|
||||||
|
*
|
||||||
|
* @tparam T - The optional type.
|
||||||
|
* @tparam I - The index of the parameter to parse in the args vector.
|
||||||
|
* @param args - An STR_ARGS to pull the parameter from.
|
||||||
|
* @param ctx - The context to pass into the parse function.
|
||||||
|
* @returns an optional that may contain a value.
|
||||||
|
*/
|
||||||
|
|
||||||
template<typename T, usize I, std::enable_if_t<is_optional_v<T>, bool> = true>
|
template<typename T, usize I, std::enable_if_t<is_optional_v<T>, bool> = true>
|
||||||
T parseStrArg(EXEC_ARGS args, C& ctx) {
|
T parseStrArg(STR_ARGS args, C& ctx) {
|
||||||
if (I >= args.size() || args[I].empty()) return {};
|
if (I >= args.size() || args[I].empty()) return {};
|
||||||
return parseStrArg<typename T::value_type, I>(args, ctx);
|
return parseStrArg<typename T::value_type, I>(args, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, usize I, std::enable_if_t<std::is_same_v<T, R>, bool> = true>
|
/**
|
||||||
T parseStrArg(EXEC_ARGS args, C& ctx) {
|
* Compile-time iterates over a tuple of the argument types and parses them,
|
||||||
if (I >= args.size()) throw std::invalid_argument("Not enough parameters.");
|
* inserting the parsed parameters into the args tuple referenced.
|
||||||
return parseRaw(parseStrArg<string, I>(args, ctx), ctx);
|
*
|
||||||
}
|
* @tparam T - The tuple type of the arguments.
|
||||||
|
* @tparam I - The index of the current parameter being parsed. Used for iterating.
|
||||||
|
* @param strArgs - The STR_ARGS storing the string parameters.
|
||||||
|
* @param args - The args tuple to insert the parsed arguments into.
|
||||||
|
* @param ctx - The context to pass into parse functions.
|
||||||
|
* @throws if any of the parameters cannot be parsed, see parseStrArg implementations for details.
|
||||||
|
*/
|
||||||
|
|
||||||
template <typename T, usize I = 0>
|
template <typename T, usize I = 0>
|
||||||
void parseStrArgs(EXEC_ARGS strArgs, T& args, C& ctx) {
|
inline void parseStrArgs(STR_ARGS strArgs, T& args, C& ctx) {
|
||||||
std::get<I>(args) = parseStrArg<std::tuple_element_t<I, T>, I>(strArgs, ctx);
|
std::get<I>(args) = parseStrArg<std::tuple_element_t<I, T>, I>(strArgs, ctx);
|
||||||
if constexpr (I + 1 < std::tuple_size_v<T>) parseStrArgs<T, I + 1>(strArgs, args, ctx);
|
if constexpr (I + 1 < std::tuple_size_v<T>) parseStrArgs<T, I + 1>(strArgs, args, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unordered_map<string, Fn> functions {};
|
/** A map of parse functions, indexed by their name. */
|
||||||
|
std::unordered_map<string, PARSE_FN> functions {};
|
||||||
|
|
||||||
|
/** If true, unknown functions will be parsed as string literals, if false, an error will be thrown. */
|
||||||
|
bool unknownFnsAreLiteral = false;
|
||||||
};
|
};
|
|
@ -1,5 +1,4 @@
|
||||||
zepha.bind('new_player', function(player)
|
zepha.bind('new_player', function(player)
|
||||||
print('added inventories :)')
|
|
||||||
local inv = player:get_inventory()
|
local inv = player:get_inventory()
|
||||||
inv:add_list('hot_wheel_1', 5, 5)
|
inv:add_list('hot_wheel_1', 5, 5)
|
||||||
inv:add_list('hot_wheel_2', 5, 5)
|
inv:add_list('hot_wheel_2', 5, 5)
|
||||||
|
|
|
@ -41,9 +41,13 @@ zepha.register_block("zeus:flowers:clover", {
|
||||||
solid = false,
|
solid = false,
|
||||||
model = "zeus:flowers:hash",
|
model = "zeus:flowers:hash",
|
||||||
textures = {
|
textures = {
|
||||||
-- "tint(0, crop(0, 0, 16, 16, zeus:flowers:clover))",
|
"tint(0, crop(0, 0, 16, 16, zeus:flowers:clover))",
|
||||||
-- "tint(0, crop(16, 0, 16, 16, zeus:flowers:clover))",
|
"tint(0, crop(16, 0, 16, 16, zeus:flowers:clover))",
|
||||||
-- "tint(0, crop(32, 0, 16, 16, zeus:flowers:clover))"
|
"tint(0, crop(32, 0, 16, 16, zeus:flowers:clover))",
|
||||||
|
"tint(0, crop(0, 16, 16, 8, zeus:flowers:clover))",
|
||||||
|
"tint(0, crop(16, 16, 16, 8, zeus:flowers:clover))",
|
||||||
|
"tint(0, crop(0, 24, 16, 8, zeus:flowers:clover))",
|
||||||
|
"tint(0, crop(16, 24, 16, 8, zeus:flowers:clover))"
|
||||||
},
|
},
|
||||||
light_propagates = true,
|
light_propagates = true,
|
||||||
lowdef_render = false,
|
lowdef_render = false,
|
||||||
|
|
|
@ -3,7 +3,20 @@
|
||||||
-- with multiple layers of topfaces.
|
-- with multiple layers of topfaces.
|
||||||
--
|
--
|
||||||
|
|
||||||
|
local offset_amp = 0.2
|
||||||
|
local amp = 0.025
|
||||||
|
|
||||||
zepha.register_blockmodel('zeus:flowers:hash', {
|
zepha.register_blockmodel('zeus:flowers:hash', {
|
||||||
|
mesh_mods = {
|
||||||
|
{
|
||||||
|
type = 'offset_x',
|
||||||
|
amplitude = offset_amp,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type = 'offset_z',
|
||||||
|
amplitude = offset_amp,
|
||||||
|
}
|
||||||
|
},
|
||||||
parts = {
|
parts = {
|
||||||
{
|
{
|
||||||
face = 'nocull',
|
face = 'nocull',
|
||||||
|
@ -13,6 +26,10 @@ zepha.register_blockmodel('zeus:flowers:hash', {
|
||||||
4/16, 0, 1, 1, 1,
|
4/16, 0, 1, 1, 1,
|
||||||
4/16, 0.5, 1, 1, 0,
|
4/16, 0.5, 1, 1, 0,
|
||||||
4/16, 0.5, 0, 0, 0
|
4/16, 0.5, 0, 0, 0
|
||||||
|
},
|
||||||
|
shader_mod = {
|
||||||
|
type = 'sway_attached',
|
||||||
|
amplitude = amp
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
face = 'nocull',
|
face = 'nocull',
|
||||||
|
@ -22,6 +39,10 @@ zepha.register_blockmodel('zeus:flowers:hash', {
|
||||||
12/16, 0, 1, 0, 1,
|
12/16, 0, 1, 0, 1,
|
||||||
12/16, 0, 0, 1, 1,
|
12/16, 0, 0, 1, 1,
|
||||||
12/16, 0.5, 0, 1, 0
|
12/16, 0.5, 0, 1, 0
|
||||||
|
},
|
||||||
|
shader_mod = {
|
||||||
|
type = 'sway_attached',
|
||||||
|
amplitude = amp
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
face = 'nocull',
|
face = 'nocull',
|
||||||
|
@ -31,6 +52,10 @@ zepha.register_blockmodel('zeus:flowers:hash', {
|
||||||
1, 0, 12/16, 1, 1,
|
1, 0, 12/16, 1, 1,
|
||||||
1, 0.5, 12/16, 1, 0,
|
1, 0.5, 12/16, 1, 0,
|
||||||
0, 0.5, 12/16, 0, 0
|
0, 0.5, 12/16, 0, 0
|
||||||
|
},
|
||||||
|
shader_mod = {
|
||||||
|
type = 'sway_attached',
|
||||||
|
amplitude = amp
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
face = 'nocull',
|
face = 'nocull',
|
||||||
|
@ -40,6 +65,10 @@ zepha.register_blockmodel('zeus:flowers:hash', {
|
||||||
0, 0.5, 4/16, 1, 0,
|
0, 0.5, 4/16, 1, 0,
|
||||||
1, 0.5, 4/16, 0, 0,
|
1, 0.5, 4/16, 0, 0,
|
||||||
1, 0, 4/16, 0, 1
|
1, 0, 4/16, 0, 1
|
||||||
|
},
|
||||||
|
shader_mod = {
|
||||||
|
type = 'sway_attached',
|
||||||
|
amplitude = amp
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
face = 'nocull',
|
face = 'nocull',
|
||||||
|
@ -49,6 +78,10 @@ zepha.register_blockmodel('zeus:flowers:hash', {
|
||||||
0, 4/16, 1, 0, 1,
|
0, 4/16, 1, 0, 1,
|
||||||
1, 4/16, 1, 1, 1,
|
1, 4/16, 1, 1, 1,
|
||||||
1, 4/16, 0, 1, 0
|
1, 4/16, 0, 1, 0
|
||||||
|
},
|
||||||
|
shader_mod = {
|
||||||
|
type = 'sway_full_block',
|
||||||
|
amplitude = amp
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -59,7 +92,11 @@ zepha.register_blockmodel('zeus:flowers:hash', {
|
||||||
0, 3/16, 1, 0, 1,
|
0, 3/16, 1, 0, 1,
|
||||||
1, 3/16, 1, 1, 1,
|
1, 3/16, 1, 1, 1,
|
||||||
1, 3/16, 0, 1, 0
|
1, 3/16, 0, 1, 0
|
||||||
}
|
},
|
||||||
|
shader_mod = {
|
||||||
|
type = 'sway_full_block',
|
||||||
|
amplitude = amp
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
face = 'nocull',
|
face = 'nocull',
|
||||||
|
@ -69,6 +106,10 @@ zepha.register_blockmodel('zeus:flowers:hash', {
|
||||||
0, 2/16, 1, 0, 1,
|
0, 2/16, 1, 0, 1,
|
||||||
1, 2/16, 1, 1, 1,
|
1, 2/16, 1, 1, 1,
|
||||||
1, 2/16, 0, 1, 0
|
1, 2/16, 0, 1, 0
|
||||||
|
},
|
||||||
|
shader_mod = {
|
||||||
|
type = 'sway_full_block',
|
||||||
|
amplitude = amp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 8.6 KiB |
|
@ -21,7 +21,7 @@ local structures = {}
|
||||||
|
|
||||||
table.insert(structures, zepha.create_structure({
|
table.insert(structures, zepha.create_structure({
|
||||||
origin = V(1),
|
origin = V(1),
|
||||||
probability = 0.0025,
|
probability = 0.00125,
|
||||||
layout = {{
|
layout = {{
|
||||||
{ none, none, none },
|
{ none, none, none },
|
||||||
{ none, wood, none },
|
{ none, wood, none },
|
||||||
|
@ -91,7 +91,7 @@ local leaf_layer_3 = {
|
||||||
|
|
||||||
table.insert(structures, zepha.create_structure({
|
table.insert(structures, zepha.create_structure({
|
||||||
origin = V(2, 2, 2),
|
origin = V(2, 2, 2),
|
||||||
probability = 0.0005,
|
probability = 0.00025,
|
||||||
layout = {
|
layout = {
|
||||||
-- trunk_layer_0,
|
-- trunk_layer_0,
|
||||||
-- trunk_layer_0,
|
-- trunk_layer_0,
|
||||||
|
@ -121,28 +121,28 @@ table.insert(structures, zepha.create_structure({
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|
||||||
-- for i = 1, 5 do
|
for i = 1, 5 do
|
||||||
-- table.insert(structures, zepha.create_structure({
|
table.insert(structures, zepha.create_structure({
|
||||||
-- origin = V(),
|
origin = V(),
|
||||||
-- probability = 0.1,
|
probability = 0.025,
|
||||||
-- layout = {{{ "zeus:default:tall_grass_" .. tostring(i) }}}
|
layout = {{{ "zeus:default:tall_grass_" .. tostring(i) }}}
|
||||||
-- }))
|
}))
|
||||||
-- end
|
end
|
||||||
|
|
||||||
table.insert(structures, zepha.create_structure({
|
table.insert(structures, zepha.create_structure({
|
||||||
origin = V(),
|
origin = V(),
|
||||||
probability = 0.1,
|
probability = 0.35,
|
||||||
layout = {{{ "zeus:flowers:clover" }}}
|
layout = {{{ "zeus:flowers:clover" }}}
|
||||||
}))
|
}))
|
||||||
table.insert(structures, zepha.create_structure({
|
table.insert(structures, zepha.create_structure({
|
||||||
origin = V(),
|
origin = V(),
|
||||||
probability = 0.025,
|
probability = 0.0125,
|
||||||
layout = {{{ "zeus:flowers:flower_geranium" }}}
|
layout = {{{ "zeus:flowers:flower_geranium" }}}
|
||||||
}))
|
}))
|
||||||
|
|
||||||
table.insert(structures, zepha.create_structure({
|
table.insert(structures, zepha.create_structure({
|
||||||
origin = V(),
|
origin = V(),
|
||||||
probability = 0.025,
|
probability = 0.0125,
|
||||||
layout = {{{ "zeus:flowers:flower_white_dandelion" }}}
|
layout = {{{ "zeus:flowers:flower_white_dandelion" }}}
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
@ -207,6 +207,7 @@ zepha.register_biome(identifier, {
|
||||||
tags = { natural = 1, default = 1 },
|
tags = { natural = 1, default = 1 },
|
||||||
structures = structures,
|
structures = structures,
|
||||||
biome_tint = "#46cfc0",
|
biome_tint = "#46cfc0",
|
||||||
|
-- biome_tint = "#aaed45",
|
||||||
noise = noise
|
noise = noise
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue