From 0de53a9dcbef2175741b28a7c1428559f73b045e Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Thu, 11 Mar 2021 16:28:11 +0100 Subject: [PATCH] Refactor datapack code --- mods/CORE/class/init.lua | 45 ++++++++++ mods/CORE/class/mod.conf | 3 + mods/CORE/mcl_numbers/api.lua | 27 ------ mods/CORE/mcl_predicates/api.lua | 84 ------------------ mods/CORE/mcl_predicates/mod.conf | 4 - mods/{CORE => DATA}/mcl_loottables/api.lua | 42 +++------ .../{CORE => DATA}/mcl_loottables/entries.lua | 0 mods/{CORE => DATA}/mcl_loottables/init.lua | 0 mods/{CORE => DATA}/mcl_loottables/mod.conf | 2 +- mods/DATA/mcl_numbers/api.lua | 19 ++++ mods/{CORE => DATA}/mcl_numbers/init.lua | 0 mods/{CORE => DATA}/mcl_numbers/mod.conf | 0 mods/DATA/mcl_predicates/api.lua | 15 ++++ mods/{CORE => DATA}/mcl_predicates/init.lua | 18 ++-- mods/DATA/mcl_predicates/mod.conf | 4 + mods/DATA/mcl_types/init.lua | 88 +++++++++++++++++++ mods/DATA/mcl_types/mod.conf | 3 + mods/DATA/modpack.conf | 2 + 18 files changed, 198 insertions(+), 158 deletions(-) create mode 100644 mods/CORE/class/init.lua create mode 100644 mods/CORE/class/mod.conf delete mode 100644 mods/CORE/mcl_numbers/api.lua delete mode 100644 mods/CORE/mcl_predicates/api.lua delete mode 100644 mods/CORE/mcl_predicates/mod.conf rename mods/{CORE => DATA}/mcl_loottables/api.lua (74%) rename mods/{CORE => DATA}/mcl_loottables/entries.lua (100%) rename mods/{CORE => DATA}/mcl_loottables/init.lua (100%) rename mods/{CORE => DATA}/mcl_loottables/mod.conf (58%) create mode 100644 mods/DATA/mcl_numbers/api.lua rename mods/{CORE => DATA}/mcl_numbers/init.lua (100%) rename mods/{CORE => DATA}/mcl_numbers/mod.conf (100%) create mode 100644 mods/DATA/mcl_predicates/api.lua rename mods/{CORE => DATA}/mcl_predicates/init.lua (87%) create mode 100644 mods/DATA/mcl_predicates/mod.conf create mode 100644 mods/DATA/mcl_types/init.lua create mode 100644 mods/DATA/mcl_types/mod.conf create mode 100644 mods/DATA/modpack.conf diff --git a/mods/CORE/class/init.lua b/mods/CORE/class/init.lua new file mode 100644 index 000000000..907342374 --- /dev/null +++ b/mods/CORE/class/init.lua @@ -0,0 +1,45 @@ +local Object = {} + +function Object:__define_getter(name, cached, get, cmp) + local key = "_" .. name + self[name] = function (self, expected) + local value + + if cached then + value = self[key] + end + + if not value then + value = get(self) + end + + if cached then + self[key] = value + end + + if expected ~= nil then + if cmp then + return cmp(value, expected) + else + return value == expected + end + else + return value + end + end +end + +function class(super) + return setmetatable({}, { + __call = function(_class, ...) + local instance = setmetatable({}, { + __index = _class, + }) + if instance.constructor then + instance:constructor(...) + end + return instance + end, + __index = super or Object, + }) +end diff --git a/mods/CORE/class/mod.conf b/mods/CORE/class/mod.conf new file mode 100644 index 000000000..5618757dc --- /dev/null +++ b/mods/CORE/class/mod.conf @@ -0,0 +1,3 @@ +name = class +author = Fleckenstein +description = A class system for MineClone2 diff --git a/mods/CORE/mcl_numbers/api.lua b/mods/CORE/mcl_numbers/api.lua deleted file mode 100644 index 160001697..000000000 --- a/mods/CORE/mcl_numbers/api.lua +++ /dev/null @@ -1,27 +0,0 @@ -mcl_numbers.register_provider = mcl_util.registration_function(mcl_numbers.providers) - -function mcl_numbers.get_number(provider, data) - return mcl_util.switch_type(provider, { - ["number"] = function() - return provider - end, - ["table"] = function() - local func = mcl_numbers.providers[data.type] - return func(provider, data) - end, - }, "number provider") -end - -function mcl_numbers.check_bounds(actual, expected, data) - return mcl_util.switch_type(actual, { - ["nil"] = function() - return true - end, - ["number"] = function() - return actual == expected - end, - ["table"] = function() - return actual <= mcl_numbers.get_number(expected.max, data) and actual >= mcl_numbers.get_number(expected.min, data) - end, - }, "range") -end diff --git a/mods/CORE/mcl_predicates/api.lua b/mods/CORE/mcl_predicates/api.lua deleted file mode 100644 index 163911b41..000000000 --- a/mods/CORE/mcl_predicates/api.lua +++ /dev/null @@ -1,84 +0,0 @@ -mcl_predicates.register_predicate = mcl_util.registration_function(mcl_predicates.predicates) - -function mcl_predicates.get_predicate(id) - return mcl_util.switch_type(id, { - ["function"] = function(v) - return v, - end, - ["string"] = function(v) - return mcl_predicates.predicates[v] - end, - }, "predicate") -end - -function mcl_predicates.do_predicates(predicates, data, or_mode) - or_mode = or_mode or false - for _, def in ipairs() do - local func = mcl_predicates.get_predicate(def.condition) - local failure = func and not func(def, data) or false - if or_mode ~= failure then - return or_mode - end - end - return not or_mode or #predicates == 0 -end - -function mcl_predicates.match_block(location, block, properties) - local node = minetest.get_node(location) - if node.name ~= block then - return false - end - if properties then - local meta = minetest.get_meta(location) - for k, v in pairs(properties) do - if meta:get_string(k) ~= v then - return false - end - end - end - return true -end - - -function mcl_predicates.match_tool(itemstack, predicate) - itemstack = itemstack or ItemStack() - - local itemname = itemstack:get_name() - - local expected_name = predicate.item - - if expected_name and itemname ~= expected_name then - return false - end - - local tag = predicate.tag - - if tag and minetest.get_item_group(itemname, predicate) == 0 then - return false - end - - if not mcl_numbers.check_bounds(itemstack:get_count(), predicate.count, data) then - return false - end - - -- ToDo: Durability, needs research, needs abstraction ? - -- ToDo: potions, "nbt" aka metadata - - local enchantments, stored_enchantments = predicate.enchantments, predicate.stored_enchantments - - if enchantments and stored_enchantments then - enchantments = table.copy(enchantments) - table.insert_all(enchantments, stored_enchantments) - elseif stored_enchantments then - enchantments = stored_enchantments - end - if enchantments then - local actual_enchantments = mcl_enchanting.get_enchantments(itemstack) - for _, def in ipairs(actual_enchantments) do - local level = actual_enchantments[def.enchantment] - if not mcl_numbers.check_bounds(level, def.levels or {min = 1, max = math.huge}, data) then - return false - end - end - end -end diff --git a/mods/CORE/mcl_predicates/mod.conf b/mods/CORE/mcl_predicates/mod.conf deleted file mode 100644 index 843c06afb..000000000 --- a/mods/CORE/mcl_predicates/mod.conf +++ /dev/null @@ -1,4 +0,0 @@ -name = mcl_predicates -author = Fleckenstein -description = Provides MC-like predicates -depends = mcl_util, mcl_number diff --git a/mods/CORE/mcl_loottables/api.lua b/mods/DATA/mcl_loottables/api.lua similarity index 74% rename from mods/CORE/mcl_loottables/api.lua rename to mods/DATA/mcl_loottables/api.lua index edec0e5bc..de2785687 100644 --- a/mods/CORE/mcl_loottables/api.lua +++ b/mods/DATA/mcl_loottables/api.lua @@ -9,21 +9,6 @@ mcl_loottables.register_table = mcl_util.registration_function(mcl_loottables.ta set_parents(def) end) - -function mcl_loottables.get_table(def) - return mcl_util.switch_type(def, { - ["nil"] = function() - return {} - end, - ["string"] = function() - return mcl_loottables.tables[def], "table" - end, - ["table"] = function() - return def - end, - }, "loot table") -end - function mcl_loottables.get_entry_type(entry) return mcl_loottables.entries[entry.type] end @@ -32,7 +17,7 @@ function mcl_loottables.get_candidates(entries, data, func) local candidates = {} for _, entry in ipairs(entries) do local success = mcl_predicates.do_predicates(entry.conditions, data) - + if success then local children = entry.children @@ -52,7 +37,7 @@ end function mcl_loottables.do_item_modifiers(itemstack, node, data) if node then - mcl_functions.do_item_modifiers(itemstack, node.functions, data) + mcl_item_modifiers.do_item_modifiers(itemstack, node.functions, data) mcl_loottables.do_item_modifiers(itemstack, node.parent, data) end end @@ -61,8 +46,8 @@ function mcl_loottables.do_pools(pools, functions, data) local luck = data.luck or 0 local stacks = {} for _, pool in ipairs(pools or {}) do - if mcl_conditions.do_conditions(pool.conditions, data) do - local rolls = mcl_loottables.get_number(pool.rolls, data) + mcl_loottables.get_number(pool.bonus_rolls, data) * luck + if mcl_predicates.do_predicates(pool.conditions, data) do + local rolls = mcl_numbers.get_number(pool.rolls, data) + mcl_numbers.get_number(pool.bonus_rolls, data) * luck for i = 1, rolls do local candidates = mcl_loottables.get_candidates(pool.entries, data) @@ -73,7 +58,7 @@ function mcl_loottables.do_pools(pools, functions, data) total_weight = total_weight + math.floor((candidate.weight or 1) + (candidate.quality or 0) * luck) table.insert(weights, total_weight) end - + local selected local rnd = mcl_util.rand(data.pr, 0, weight - 1) for i, w in ipairs(weights) do @@ -82,14 +67,13 @@ function mcl_loottables.do_pools(pools, functions, data) break end end - - local func = mcl_loottables.get_entry_type(entry).process - local stacks = func(selected, data) - for _, stack in ipairs(stacks) do + local pool_stacks = mcl_loottables.get_entry_type(entry).process(selected, data) + + for _, stack in ipairs(pool_stacks) do mcl_item_modifiers.do_item_modifiers(stack, selected, data) end - table.insert_all(stacks, stack) + table.insert_all(stacks, pool_stacks) end end end @@ -98,7 +82,9 @@ function mcl_loottables.do_pools(pools, functions, data) end function mcl_loottables.get_loot(def, data) - def = mcl_loottables.get_table(def) + if type(def) == "string" then + def = mcl_loottables.tables[def] + end return mcl_loottables.do_pools(def.pools) end @@ -113,7 +99,3 @@ function mcl_loottables.drop_loot(def, data) end return loot end - -function mcl_loottables.fill_chest(def, data) - local loot = mcl_loottables.get_loot(def, data) -end diff --git a/mods/CORE/mcl_loottables/entries.lua b/mods/DATA/mcl_loottables/entries.lua similarity index 100% rename from mods/CORE/mcl_loottables/entries.lua rename to mods/DATA/mcl_loottables/entries.lua diff --git a/mods/CORE/mcl_loottables/init.lua b/mods/DATA/mcl_loottables/init.lua similarity index 100% rename from mods/CORE/mcl_loottables/init.lua rename to mods/DATA/mcl_loottables/init.lua diff --git a/mods/CORE/mcl_loottables/mod.conf b/mods/DATA/mcl_loottables/mod.conf similarity index 58% rename from mods/CORE/mcl_loottables/mod.conf rename to mods/DATA/mcl_loottables/mod.conf index 668ba6bd2..7c595f865 100644 --- a/mods/CORE/mcl_loottables/mod.conf +++ b/mods/DATA/mcl_loottables/mod.conf @@ -1,4 +1,4 @@ name = mcl_loot author = Fleckenstein description = Provides Minecraft-like loot table definitions -depends = mcl_util, mcl_predicates, mcl_item_modifiers +depends = mcl_util, mcl_predicates, mcl_item_modifiers, mcl_groupcache diff --git a/mods/DATA/mcl_numbers/api.lua b/mods/DATA/mcl_numbers/api.lua new file mode 100644 index 000000000..aace8444d --- /dev/null +++ b/mods/DATA/mcl_numbers/api.lua @@ -0,0 +1,19 @@ +mcl_numbers.register_provider = mcl_util.registration_function(mcl_numbers.providers) + +function mcl_numbers.get_number(provider, data) + if type(provider) == "number" then + return provider + else + mcl_numbers.providers[data.type](provider, data) + end +end + +function mcl_numbers.match_bounds(actual, expected, data) + if type(expected) == "table" then + expected = { + min = mcl_numbers.get_number(expected.min, data), + max = mcl_numbers.get_number(expected.max, data) + } + end + return mcl_util.match_bounds(actual, expected) +end diff --git a/mods/CORE/mcl_numbers/init.lua b/mods/DATA/mcl_numbers/init.lua similarity index 100% rename from mods/CORE/mcl_numbers/init.lua rename to mods/DATA/mcl_numbers/init.lua diff --git a/mods/CORE/mcl_numbers/mod.conf b/mods/DATA/mcl_numbers/mod.conf similarity index 100% rename from mods/CORE/mcl_numbers/mod.conf rename to mods/DATA/mcl_numbers/mod.conf diff --git a/mods/DATA/mcl_predicates/api.lua b/mods/DATA/mcl_predicates/api.lua new file mode 100644 index 000000000..b8b42ca81 --- /dev/null +++ b/mods/DATA/mcl_predicates/api.lua @@ -0,0 +1,15 @@ +mcl_predicates.register_predicate = mcl_util.registration_function(mcl_predicates.predicates) + +function mcl_predicates.do_predicates(predicates, data, or_mode) + or_mode = or_mode or false + for _, func in ipairs(predicates) do + if type(func) == "string" then + func = mcl_predicates.predicates[func] + end + local failure = func and not func(def, data) or false + if or_mode ~= failure then + return or_mode + end + end + return not or_mode or #predicates == 0 +end diff --git a/mods/CORE/mcl_predicates/init.lua b/mods/DATA/mcl_predicates/init.lua similarity index 87% rename from mods/CORE/mcl_predicates/init.lua rename to mods/DATA/mcl_predicates/init.lua index 56457c366..addd8e8d0 100644 --- a/mods/CORE/mcl_predicates/init.lua +++ b/mods/DATA/mcl_predicates/init.lua @@ -10,8 +10,8 @@ mcl_predicates.register_predicate("alternative", function(predicate, data) return mcl_predicates.do_predicates(predicate.terms, data, true) end) -mcl_predicates.register_predicate("block_state_property", function(predicate, data) - return mcl_predicates.match_block(predicate.block, predicate.properties, data.location) +mcl_predicates.register_predicate("match_node", function(predicate, data) + return mcl_types.match_node(data.node or minetest.get_node(data.pos), predicate, data.pos, data.nodemeta) end) mcl_predicates.register_predicate("damage_source_properties", function(predicate, data) @@ -24,7 +24,7 @@ mcl_predicates.register_predicate("entity_properties", function(predicate, data) if not entity or (entity ~= "this" and entity ~= "killer" and entity ~= "killer_player") then return false end - + local ref = data[entity] if not ref then return false @@ -48,14 +48,8 @@ mcl_predicates.register_predicate("killed_by_player", function(predicate, data) end) mcl_predicates.register_predicate("location_check", function(predicate, data) - local location = vector.new(data.location) - - location.x = location.x + (data.offsetX or 0) - location.y = location.y + (data.offsetY or 0) - location.z = location.z + (data.offsetZ or 0) - - -- ToDo, needs abstraction? - return nil + local pos = vector.add(data.pos), vector.new(predicate.offset_x or 0, predicate.offset_y or 0, predicate.offset_z or 0)) + return mcl_location(pos, data.nodemeta):match(predicate.predicate) end) mcl_predicates.register_predicate("match_tool", function(predicate, data) @@ -94,7 +88,7 @@ end) mcl_predicates.register_predicate("weather_check", function(predicate, data) local weather = mcl_weather.get_weather() - + if predicate.thundering then return weather == "thunder" elseif predicate.raining then diff --git a/mods/DATA/mcl_predicates/mod.conf b/mods/DATA/mcl_predicates/mod.conf new file mode 100644 index 000000000..4af4dd564 --- /dev/null +++ b/mods/DATA/mcl_predicates/mod.conf @@ -0,0 +1,4 @@ +name = mcl_predicates +author = Fleckenstein +description = Provides MC-like predicates +depends = mcl_util, mcl_numbers diff --git a/mods/DATA/mcl_types/init.lua b/mods/DATA/mcl_types/init.lua new file mode 100644 index 000000000..2eb5441ad --- /dev/null +++ b/mods/DATA/mcl_types/init.lua @@ -0,0 +1,88 @@ +mcl_types = {} + +function mcl_types.match_bounds(actual, expected) + if type(expected) == "table" then + return actual <= expected.max and actual >= expected.min + else + return actual == expected + end +end + +function mcl_types.match_meta(actual, expected) + for k, v in pairs(expected) do + if actual:get_string(k) ~= v then + return false + end + end + return true +end + +function mcl_types.match_vector(actual, expected) + for k, v in pairs(expected) do + if not mcl_types.match_bounds(actual[k], expected[k]) then + return false + end + end + return true +end + +function mcl_types.match_enchantments(actual, expected) + for _, v in ipairs(expected) do + if not mcl_types.match_bounds(actual[v.enchantment] or 0, v.levels or {min = 1, max = math.huge}) then + return false + end + end + return true +end + +function mcl_util.match_item(actual, expected) + actual = actual or ItemStack() + + if expected.item and actual:get_name() ~= expected.item then + return false + elseif expected.group and minetest.get_item_group(actual:get_name(), expected.group) == 0 then + return false + elseif expected.count and not mcl_types.match_bounds(actual:get_count(), expected.count) then + return false + elseif expected.wear and not mcl_types.match_bounds(actual:get_wear(), expected.wear) then + return false + elseif expected.enchantments and not mcl_types.match_enchantments(mcl_enchanting.get_enchantments(actual), expected.enchantments) then + return false + elseif expected.meta and not mcl_types.match_meta(actual:get_meta(), expected.meta) then + return false + else + return true + end +end + +function mcl_util.match_node(actual, expected, pos, meta) + if expected.node and actual.name ~= expected.node then + return false + elseif expected.group and minetest.get_item_group(actual.name, expected.group) == 0 then + return false + elseif expected.param1 and actual.param1 ~= compare.param1 then + return false + elseif expected.param2 and actual.param2 ~= compare.param2 then + return false + elseif expected.meta and not mcl_types.match_meta(meta or minetest.get_meta(pos), expected.meta) then + return false + else + return true + end +end + +function mcl_types.match_pos(actual, expected, meta) + if expected.pos and not mcl_types.match_vector(actual, expected.pos) then + return false + elseif expected.dimension and mcl_worlds.pos_to_dimension(actual) ~= expected.dimension then + return false + elseif expected.biome and minetest.get_biome_name(minetest.get_biome_data(actual).biome) ~= expected.biome then + return false + elseif expected.node and not mcl_types.match_node(minetest.get_node(actual), expected.node, actual, meta) + return false + elseif expected.light and not mcl_types.match_bounds(minetest.get_node_light(actual), expected.light) then + return false + else + return true + end +end diff --git a/mods/DATA/mcl_types/mod.conf b/mods/DATA/mcl_types/mod.conf new file mode 100644 index 000000000..28e5a19d5 --- /dev/null +++ b/mods/DATA/mcl_types/mod.conf @@ -0,0 +1,3 @@ +name = mcl_types +author = Fleckenstein +description = Offers compare functions for many types, used for MineClone2 datapacks diff --git a/mods/DATA/modpack.conf b/mods/DATA/modpack.conf new file mode 100644 index 000000000..c2b4a8504 --- /dev/null +++ b/mods/DATA/modpack.conf @@ -0,0 +1,2 @@ +name = DATA +description = Meta-modpack containing the datapack system for MineClone 2