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.
|
||||
*/
|
||||
|
||||
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)) };
|
||||
});
|
||||
|
||||
|
|
|
@ -13,7 +13,17 @@
|
|||
#include "game/atlas/ServerDefinitionAtlas.h"
|
||||
|
||||
namespace RegisterBlock {
|
||||
|
||||
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.
|
||||
|
@ -37,44 +47,6 @@ namespace RegisterBlock {
|
|||
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.
|
||||
*
|
||||
|
@ -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");
|
||||
if (!partsOpt) throw std::runtime_error("blockmodel is missing parts table");
|
||||
partsOpt->for_each([&](sol::object key, sol::object value) {
|
||||
|
@ -183,20 +155,17 @@ namespace RegisterBlock {
|
|||
|
||||
// Get the part's texture
|
||||
int tex = std::max(static_cast<int>(meshPartTable.get_or<float>("tex", 1)), 1);
|
||||
|
||||
auto texture = textures[std::min(tex - 1, (int) textures.size() - 1)];
|
||||
unsigned int blendInd = 0;
|
||||
std::string blendMask = "";
|
||||
getMeshPartTexture(texture, blendInd, blendMask);
|
||||
let data = parser.parse(textures[std::min(tex - 1, (int) textures.size() - 1)]);
|
||||
u32 blendInd = data.tint ? *data.tint + 1 : 0;
|
||||
|
||||
// Add texture refs to blockModel if the textures table is provided
|
||||
std::shared_ptr<AtlasRef> textureRef = nullptr, blendMaskRef = nullptr;
|
||||
if (atlas) {
|
||||
textureRef = (*atlas)[texture];
|
||||
textureRef = (*atlas)[data.tex];
|
||||
model.textureRefs.insert(textureRef);
|
||||
|
||||
if (blendInd && !blendMask.empty()) {
|
||||
blendMaskRef = (*atlas)[blendMask];
|
||||
if (blendInd && data.mask) {
|
||||
blendMaskRef = (*atlas)[*data.mask];
|
||||
model.textureRefs.insert(blendMaskRef);
|
||||
}
|
||||
}
|
||||
|
@ -259,14 +228,12 @@ namespace RegisterBlock {
|
|||
std::vector<std::shared_ptr<AtlasRef>> blendMaskRefs;
|
||||
|
||||
for (auto i = 0; i < lowdef_textures.size(); i++) {
|
||||
std::string texture = lowdef_textures[i];
|
||||
unsigned int blendInd = 0;
|
||||
std::string blendMask = "";
|
||||
getMeshPartTexture(texture, blendInd, blendMask);
|
||||
let data = parser.parse(lowdef_textures[i]);
|
||||
u32 blendInd = data.tint ? *data.tint + 1 : 0;
|
||||
|
||||
textureRefs.push_back((*atlas)[texture]);
|
||||
textureRefs.push_back((*atlas)[data.tex]);
|
||||
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);
|
||||
|
@ -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.
|
||||
|
@ -424,11 +412,11 @@ namespace RegisterBlock {
|
|||
*/
|
||||
|
||||
static void server(sol::table& core, ServerSubgame& game, const std::string& identifier) {
|
||||
initParser();
|
||||
registerBlock(core["registered_blocks"], core["registered_blockmodels"],
|
||||
identifier, game.getDefs(), nullptr);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Client method to register a block. Calls registerBlock with the necessary parameters.
|
||||
* Registers a block to the DefinitionAtlas.
|
||||
|
@ -439,6 +427,7 @@ namespace RegisterBlock {
|
|||
*/
|
||||
|
||||
static void client(sol::table& core, LocalSubgame& game, const std::string& identifier) {
|
||||
initParser();
|
||||
registerBlock(core["registered_blocks"], core["registered_blockmodels"],
|
||||
identifier, game.getDefs(), &game.textures);
|
||||
}
|
||||
|
|
|
@ -5,101 +5,192 @@
|
|||
|
||||
#include "util/Types.h"
|
||||
|
||||
/** SFINAE Helpers. */
|
||||
namespace {
|
||||
/** Struct used for identifying variants in SFINAE. */
|
||||
template<typename T> struct is_variant : std::false_type {};
|
||||
|
||||
template<typename... Args>
|
||||
struct is_variant<std::variant<Args...>> : std::true_type {};
|
||||
|
||||
/** Const bool used for identifying variants in SFINAE. */
|
||||
template<typename T>
|
||||
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... Args>
|
||||
struct is_optional<std::optional<Args...>> : std::true_type {};
|
||||
|
||||
/** Const bool used for identifying optionals in SFINAE. */
|
||||
template<typename T>
|
||||
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>
|
||||
class StringParser {
|
||||
|
||||
/** A type alias for a vector of string parameters that will be passed into a Fn. */
|
||||
using STR_ARGS = const vec<std::string_view>&;
|
||||
|
||||
/** 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)>;
|
||||
|
||||
public:
|
||||
|
||||
/** The data type of this parser. */
|
||||
typedef R Data;
|
||||
|
||||
/** The context type of this parser. Will be nullptr_t if no context type is specified. */
|
||||
typedef C Ctx;
|
||||
|
||||
class Fn;
|
||||
|
||||
using EXEC_ARGS = const vec<std::string_view>&;
|
||||
using EXEC_FN = std::function<R(C&, EXEC_ARGS)>;
|
||||
|
||||
struct Fn {
|
||||
Fn(EXEC_FN exec): exec(exec) {};
|
||||
|
||||
R operator()(C& ctx, EXEC_ARGS args) const {
|
||||
return exec(ctx, args);
|
||||
}
|
||||
|
||||
private:
|
||||
EXEC_FN exec;
|
||||
};
|
||||
|
||||
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>
|
||||
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 = {};
|
||||
parseStrArgs<std::tuple<Args...>>(strArgs, args, ctx);
|
||||
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>
|
||||
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 = {};
|
||||
parseStrArgs<std::tuple<Args...>>(strArgs, args, ctx);
|
||||
return std::apply(fn, std::tuple_cat(std::tuple<C&>(ctx), args));
|
||||
});
|
||||
}
|
||||
|
||||
template <typename... Args, typename Func>
|
||||
void addLiteralFn(const Func& fn) {
|
||||
addFn<Args...>("_", fn);
|
||||
/**
|
||||
* Shortcut to add the literal function, which is called when a string literal is found.
|
||||
* 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) {
|
||||
addFnCtx<Args...>("_", fn);
|
||||
/**
|
||||
* Shortcut to add the literal function that has access to the Ctx.
|
||||
* 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 nullptr_t ctx {};
|
||||
str.erase(std::remove_if(str.begin(), str.end(), isspace), str.end());
|
||||
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 {
|
||||
str.erase(std::remove_if(str.begin(), str.end(), isspace), str.end());
|
||||
return std::move(parseRaw(str, ctx));
|
||||
}
|
||||
|
||||
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)) {
|
||||
let func = parseFunction(str);
|
||||
const let f = functions.find(string(func.first));
|
||||
if (f == functions.end()) throw std::invalid_argument("Unknown function '" + string(func.first) + "'!");
|
||||
return f->second(ctx, func.second);
|
||||
if (f == functions.end()) {
|
||||
if (!unknownFnsAreLiteral) throw std::invalid_argument(
|
||||
"Unknown function '" + string(func.first) + "'.");
|
||||
}
|
||||
else {
|
||||
else return f->second(ctx, func.second);
|
||||
}
|
||||
|
||||
const let& f = functions.find("_");
|
||||
if (f == functions.end()) throw std::invalid_argument("No default function handler!");
|
||||
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 {
|
||||
usize levels = 0;
|
||||
|
@ -114,17 +205,29 @@ private:
|
|||
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 {
|
||||
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 {
|
||||
let nextParen = 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);
|
||||
vec<std::string_view> args {};
|
||||
|
||||
|
@ -144,26 +247,87 @@ private:
|
|||
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>
|
||||
T parseStrArg(EXEC_ARGS args, C&) {
|
||||
T parseStrArg(STR_ARGS args, C&) {
|
||||
if (I >= args.size()) throw std::invalid_argument("Not enough parameters.");
|
||||
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>
|
||||
T parseStrArg(EXEC_ARGS args, C&) {
|
||||
T parseStrArg(STR_ARGS args, C&) {
|
||||
if (I >= args.size()) throw std::invalid_argument("Not enough parameters.");
|
||||
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>
|
||||
T parseStrArg(EXEC_ARGS args, C&) {
|
||||
T parseStrArg(STR_ARGS args, C&) {
|
||||
if (I >= args.size()) throw std::invalid_argument("Not enough parameters.");
|
||||
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>
|
||||
T parseStrVariantArg(EXEC_ARGS args, C& ctx) {
|
||||
inline T parseStrVariantArg(STR_ARGS args, C& ctx) {
|
||||
try {
|
||||
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>
|
||||
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.");
|
||||
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>
|
||||
T parseStrArg(EXEC_ARGS args, C& ctx) {
|
||||
T parseStrArg(STR_ARGS args, C& ctx) {
|
||||
if (I >= args.size() || args[I].empty()) return {};
|
||||
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) {
|
||||
if (I >= args.size()) throw std::invalid_argument("Not enough parameters.");
|
||||
return parseRaw(parseStrArg<string, I>(args, ctx), ctx);
|
||||
}
|
||||
/**
|
||||
* Compile-time iterates over a tuple of the argument types and parses them,
|
||||
* inserting the parsed parameters into the args tuple referenced.
|
||||
*
|
||||
* @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>
|
||||
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);
|
||||
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)
|
||||
print('added inventories :)')
|
||||
local inv = player:get_inventory()
|
||||
inv:add_list('hot_wheel_1', 5, 5)
|
||||
inv:add_list('hot_wheel_2', 5, 5)
|
||||
|
|
|
@ -41,9 +41,13 @@ zepha.register_block("zeus:flowers:clover", {
|
|||
solid = false,
|
||||
model = "zeus:flowers:hash",
|
||||
textures = {
|
||||
-- "tint(0, crop(0, 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(0, 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(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,
|
||||
lowdef_render = false,
|
||||
|
|
|
@ -3,7 +3,20 @@
|
|||
-- with multiple layers of topfaces.
|
||||
--
|
||||
|
||||
local offset_amp = 0.2
|
||||
local amp = 0.025
|
||||
|
||||
zepha.register_blockmodel('zeus:flowers:hash', {
|
||||
mesh_mods = {
|
||||
{
|
||||
type = 'offset_x',
|
||||
amplitude = offset_amp,
|
||||
},
|
||||
{
|
||||
type = 'offset_z',
|
||||
amplitude = offset_amp,
|
||||
}
|
||||
},
|
||||
parts = {
|
||||
{
|
||||
face = 'nocull',
|
||||
|
@ -13,6 +26,10 @@ zepha.register_blockmodel('zeus:flowers:hash', {
|
|||
4/16, 0, 1, 1, 1,
|
||||
4/16, 0.5, 1, 1, 0,
|
||||
4/16, 0.5, 0, 0, 0
|
||||
},
|
||||
shader_mod = {
|
||||
type = 'sway_attached',
|
||||
amplitude = amp
|
||||
}
|
||||
}, {
|
||||
face = 'nocull',
|
||||
|
@ -22,6 +39,10 @@ zepha.register_blockmodel('zeus:flowers:hash', {
|
|||
12/16, 0, 1, 0, 1,
|
||||
12/16, 0, 0, 1, 1,
|
||||
12/16, 0.5, 0, 1, 0
|
||||
},
|
||||
shader_mod = {
|
||||
type = 'sway_attached',
|
||||
amplitude = amp
|
||||
}
|
||||
}, {
|
||||
face = 'nocull',
|
||||
|
@ -31,6 +52,10 @@ zepha.register_blockmodel('zeus:flowers:hash', {
|
|||
1, 0, 12/16, 1, 1,
|
||||
1, 0.5, 12/16, 1, 0,
|
||||
0, 0.5, 12/16, 0, 0
|
||||
},
|
||||
shader_mod = {
|
||||
type = 'sway_attached',
|
||||
amplitude = amp
|
||||
}
|
||||
}, {
|
||||
face = 'nocull',
|
||||
|
@ -40,6 +65,10 @@ zepha.register_blockmodel('zeus:flowers:hash', {
|
|||
0, 0.5, 4/16, 1, 0,
|
||||
1, 0.5, 4/16, 0, 0,
|
||||
1, 0, 4/16, 0, 1
|
||||
},
|
||||
shader_mod = {
|
||||
type = 'sway_attached',
|
||||
amplitude = amp
|
||||
}
|
||||
}, {
|
||||
face = 'nocull',
|
||||
|
@ -49,6 +78,10 @@ zepha.register_blockmodel('zeus:flowers:hash', {
|
|||
0, 4/16, 1, 0, 1,
|
||||
1, 4/16, 1, 1, 1,
|
||||
1, 4/16, 0, 1, 0
|
||||
},
|
||||
shader_mod = {
|
||||
type = 'sway_full_block',
|
||||
amplitude = amp
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -59,6 +92,10 @@ zepha.register_blockmodel('zeus:flowers:hash', {
|
|||
0, 3/16, 1, 0, 1,
|
||||
1, 3/16, 1, 1, 1,
|
||||
1, 3/16, 0, 1, 0
|
||||
},
|
||||
shader_mod = {
|
||||
type = 'sway_full_block',
|
||||
amplitude = amp
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -69,6 +106,10 @@ zepha.register_blockmodel('zeus:flowers:hash', {
|
|||
0, 2/16, 1, 0, 1,
|
||||
1, 2/16, 1, 1, 1,
|
||||
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({
|
||||
origin = V(1),
|
||||
probability = 0.0025,
|
||||
probability = 0.00125,
|
||||
layout = {{
|
||||
{ none, none, none },
|
||||
{ none, wood, none },
|
||||
|
@ -91,7 +91,7 @@ local leaf_layer_3 = {
|
|||
|
||||
table.insert(structures, zepha.create_structure({
|
||||
origin = V(2, 2, 2),
|
||||
probability = 0.0005,
|
||||
probability = 0.00025,
|
||||
layout = {
|
||||
-- trunk_layer_0,
|
||||
-- trunk_layer_0,
|
||||
|
@ -121,28 +121,28 @@ table.insert(structures, zepha.create_structure({
|
|||
}
|
||||
}))
|
||||
|
||||
-- for i = 1, 5 do
|
||||
-- table.insert(structures, zepha.create_structure({
|
||||
-- origin = V(),
|
||||
-- probability = 0.1,
|
||||
-- layout = {{{ "zeus:default:tall_grass_" .. tostring(i) }}}
|
||||
-- }))
|
||||
-- end
|
||||
for i = 1, 5 do
|
||||
table.insert(structures, zepha.create_structure({
|
||||
origin = V(),
|
||||
probability = 0.025,
|
||||
layout = {{{ "zeus:default:tall_grass_" .. tostring(i) }}}
|
||||
}))
|
||||
end
|
||||
|
||||
table.insert(structures, zepha.create_structure({
|
||||
origin = V(),
|
||||
probability = 0.1,
|
||||
probability = 0.35,
|
||||
layout = {{{ "zeus:flowers:clover" }}}
|
||||
}))
|
||||
table.insert(structures, zepha.create_structure({
|
||||
origin = V(),
|
||||
probability = 0.025,
|
||||
probability = 0.0125,
|
||||
layout = {{{ "zeus:flowers:flower_geranium" }}}
|
||||
}))
|
||||
|
||||
table.insert(structures, zepha.create_structure({
|
||||
origin = V(),
|
||||
probability = 0.025,
|
||||
probability = 0.0125,
|
||||
layout = {{{ "zeus:flowers:flower_white_dandelion" }}}
|
||||
}))
|
||||
|
||||
|
@ -207,6 +207,7 @@ zepha.register_biome(identifier, {
|
|||
tags = { natural = 1, default = 1 },
|
||||
structures = structures,
|
||||
biome_tint = "#46cfc0",
|
||||
-- biome_tint = "#aaed45",
|
||||
noise = noise
|
||||
})
|
||||
|
||||
|
|
Loading…
Reference in New Issue