mirror of
https://git.minetest.land/VoxeLibre/VoxeLibre.git
synced 2024-11-28 05:21:05 +01:00
Implement comparator accurately and remove WIP, remove ABMs for comparators and make updates triggered instead of polled, changes to redstone power transmission
This commit is contained in:
parent
e970a5f414
commit
13888236d6
5 changed files with 109 additions and 126 deletions
|
@ -1,4 +1,6 @@
|
||||||
local S = minetest.get_translator(minetest.get_current_modname())
|
local S = minetest.get_translator(minetest.get_current_modname())
|
||||||
|
mcl_comparators = {}
|
||||||
|
local mod = mcl_comparators
|
||||||
|
|
||||||
-- Functions that get the input/output rules of the comparator
|
-- Functions that get the input/output rules of the comparator
|
||||||
|
|
||||||
|
@ -10,7 +12,6 @@ local function comparator_get_output_rules(node)
|
||||||
return rules
|
return rules
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local function comparator_get_input_rules(node)
|
local function comparator_get_input_rules(node)
|
||||||
local rules = {
|
local rules = {
|
||||||
-- we rely on this order in update_self below
|
-- we rely on this order in update_self below
|
||||||
|
@ -24,117 +25,73 @@ local function comparator_get_input_rules(node)
|
||||||
return rules
|
return rules
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local POSSIBLE_COMPARATOR_POSITIONS = {
|
||||||
-- Functions that are called after the delay time
|
vector.new( 1,0, 0),
|
||||||
|
vector.new(-1,0, 0),
|
||||||
local function comparator_turnon(params)
|
vector.new( 0,0, 1),
|
||||||
local rules = comparator_get_output_rules(params.node)
|
vector.new( 0,0,-1),
|
||||||
mesecon.receptor_on(params.pos, rules)
|
}
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
local function comparator_turnoff(params)
|
|
||||||
local rules = comparator_get_output_rules(params.node)
|
|
||||||
mesecon.receptor_off(params.pos, rules)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
-- Functions that set the correct node type an schedule a turnon/off
|
|
||||||
|
|
||||||
local function comparator_activate(pos, node)
|
|
||||||
local def = minetest.registered_nodes[node.name]
|
|
||||||
local onstate = def.comparator_onstate
|
|
||||||
if onstate then
|
|
||||||
minetest.swap_node(pos, { name = onstate, param2 = node.param2 })
|
|
||||||
end
|
|
||||||
minetest.after(0.1, comparator_turnon , {pos = pos, node = node})
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
local function comparator_deactivate(pos, node)
|
|
||||||
local def = minetest.registered_nodes[node.name]
|
|
||||||
local offstate = def.comparator_offstate
|
|
||||||
if offstate then
|
|
||||||
minetest.swap_node(pos, { name = offstate, param2 = node.param2 })
|
|
||||||
end
|
|
||||||
minetest.after(0.1, comparator_turnoff, {pos = pos, node = node})
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
-- weather pos has an inventory that contains at least one item
|
|
||||||
local function container_inventory_nonempty(pos)
|
|
||||||
local invnode = minetest.get_node(pos)
|
|
||||||
local invnodedef = minetest.registered_nodes[invnode.name]
|
|
||||||
-- Ignore stale nodes
|
|
||||||
if not invnodedef then return false end
|
|
||||||
|
|
||||||
-- Only accept containers. When a container is dug, it's inventory
|
|
||||||
-- seems to stay. and we don't want to accept the inventory of an air
|
|
||||||
-- block
|
|
||||||
if not invnodedef.groups.container then return false end
|
|
||||||
|
|
||||||
local inv = minetest.get_inventory({type="node", pos=pos})
|
|
||||||
if not inv then return false end
|
|
||||||
|
|
||||||
for listname, _ in pairs(inv:get_lists()) do
|
|
||||||
if not inv:is_empty(listname) then return true end
|
|
||||||
end
|
|
||||||
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
-- weather pos has an constant signal output for the comparator
|
|
||||||
local function static_signal_output(pos)
|
|
||||||
local node = minetest.get_node(pos)
|
|
||||||
local g = minetest.get_item_group(node.name, "comparator_signal")
|
|
||||||
return g > 0
|
|
||||||
end
|
|
||||||
|
|
||||||
-- whether the comparator should be on according to its inputs
|
|
||||||
local function comparator_desired_on(pos, node)
|
|
||||||
local my_input_rules = comparator_get_input_rules(node);
|
|
||||||
local back_rule = my_input_rules[1]
|
|
||||||
local state
|
|
||||||
if back_rule then
|
|
||||||
local back_pos = vector.add(pos, back_rule)
|
|
||||||
state = mesecon.is_power_on(back_pos) or container_inventory_nonempty(back_pos) or static_signal_output(back_pos)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- if back input if off, we don't need to check side inputs
|
|
||||||
if not state then return false end
|
|
||||||
|
|
||||||
-- without power levels, side inputs have no influence on output in compare
|
|
||||||
-- mode
|
|
||||||
local mode = minetest.registered_nodes[node.name].comparator_mode
|
|
||||||
if mode == "comp" then return state end
|
|
||||||
|
|
||||||
-- subtract mode, subtract max(side_inputs) from back input
|
|
||||||
local side_state = false
|
|
||||||
for ri = 2,3 do
|
|
||||||
if my_input_rules[ri] then
|
|
||||||
side_state = mesecon.is_power_on(vector.add(pos, my_input_rules[ri]))
|
|
||||||
end
|
|
||||||
if side_state then break end
|
|
||||||
end
|
|
||||||
-- state is known to be true
|
|
||||||
return not side_state
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
-- update comparator state, if needed
|
-- update comparator state, if needed
|
||||||
local function update_self(pos, node)
|
local function update_self(pos, node)
|
||||||
node = node or minetest.get_node(pos)
|
node = node or minetest.get_node(pos)
|
||||||
local old_state = mesecon.is_receptor_on(node.name)
|
|
||||||
local new_state = comparator_desired_on(pos, node)
|
-- Find the node we are pointing at
|
||||||
if new_state ~= old_state then
|
local input_rules = comparator_get_input_rules(node);
|
||||||
if new_state then
|
local back_rule = input_rules[1]
|
||||||
comparator_activate(pos, node)
|
local back_pos = vector.add(pos, back_rule)
|
||||||
else
|
local back_node = minetest.get_node(back_pos)
|
||||||
comparator_deactivate(pos, node)
|
local back_nodedef = minetest.registered_nodes[back_node.name]
|
||||||
|
|
||||||
|
-- Get the comparator mode
|
||||||
|
local mode = minetest.registered_nodes[node.name].comparator_mode
|
||||||
|
|
||||||
|
-- Get a comparator reading from the block at the back of the comparator
|
||||||
|
local power_level = 0
|
||||||
|
if back_nodedef and back_nodedef._mcl_comparators_get_reading then
|
||||||
|
power_level = back_nodedef._mcl_comparators_get_reading(back_pos)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Get the maximum side power level
|
||||||
|
local side_power_level = 0
|
||||||
|
for i=2,3 do
|
||||||
|
local pl = vl_redstone.get_power_level(vector.add(pos,input_rules[i]))
|
||||||
|
if pl > side_power_level then
|
||||||
|
side_power_level = pl
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Apply subtraction or comparison
|
||||||
|
if mode == "sub" then
|
||||||
|
power_level = power_level - side_power_level
|
||||||
|
if power_level < 0 then power_level = 0 end
|
||||||
|
elseif mode == "comp" then
|
||||||
|
if side_power_level > power_level then
|
||||||
|
power_level = 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
vl_redstone.set_power(pos, power_level)
|
||||||
|
end
|
||||||
|
|
||||||
|
function mod.trigger_update(pos)
|
||||||
|
-- try to find a comparator with the back rule leading to pos
|
||||||
|
for i = 1,#POSSIBLE_COMPARATOR_POSITIONS do
|
||||||
|
local candidate = vector.add(pos, POSSIBLE_COMPARATOR_POSITIONS[i])
|
||||||
|
local node = minetest.get_node(candidate)
|
||||||
|
if minetest.get_item_group(node.name,"mcl_comparator") ~= 0 then
|
||||||
|
update_self(candidate, node)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function mod.read_inventory(inv, inv_name)
|
||||||
|
local stacks = inv:get_list(inv_name)
|
||||||
|
local count = 0
|
||||||
|
for i=1,#stacks do
|
||||||
|
count = count + ( stacks[i]:get_count() / stacks[i]:get_stack_max() )
|
||||||
|
end
|
||||||
|
return math.floor(count * 16 / 5)
|
||||||
|
end
|
||||||
|
|
||||||
-- compute tile depending on state and mode
|
-- compute tile depending on state and mode
|
||||||
local function get_tiles(state, mode)
|
local function get_tiles(state, mode)
|
||||||
|
@ -215,6 +172,7 @@ local groups = {
|
||||||
destroy_by_lava_flow = 1,
|
destroy_by_lava_flow = 1,
|
||||||
dig_by_piston = 1,
|
dig_by_piston = 1,
|
||||||
attached_node = 1,
|
attached_node = 1,
|
||||||
|
mcl_comparator = 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
local on_rotate
|
local on_rotate
|
||||||
|
@ -309,7 +267,7 @@ for _, mode in pairs{"comp", "sub"} do
|
||||||
end
|
end
|
||||||
|
|
||||||
minetest.register_node(nodename, nodedef)
|
minetest.register_node(nodename, nodedef)
|
||||||
mcl_wip.register_wip_item(nodename)
|
--mcl_wip.register_wip_item(nodename)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -327,6 +285,7 @@ minetest.register_craft({
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
--[[
|
||||||
-- Register active block handlers
|
-- Register active block handlers
|
||||||
minetest.register_abm({
|
minetest.register_abm({
|
||||||
label = "Comparator signal input check (comparator is off)",
|
label = "Comparator signal input check (comparator is off)",
|
||||||
|
@ -352,7 +311,7 @@ minetest.register_abm({
|
||||||
chance = 1,
|
chance = 1,
|
||||||
action = update_self,
|
action = update_self,
|
||||||
})
|
})
|
||||||
|
]]
|
||||||
|
|
||||||
-- Add entry aliases for the Help
|
-- Add entry aliases for the Help
|
||||||
if minetest.get_modpath("doc") then
|
if minetest.get_modpath("doc") then
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
name = mcl_comparators
|
name = mcl_comparators
|
||||||
depends = mcl_wip, mesecons, mcl_sounds
|
depends = mesecons, mcl_sounds, vl_redstone
|
||||||
optional_depends = doc, screwdriver
|
optional_depends = doc, screwdriver
|
||||||
|
|
|
@ -4,7 +4,6 @@ vl_redstone = {}
|
||||||
local mod = vl_redstone
|
local mod = vl_redstone
|
||||||
|
|
||||||
local REDSTONE_POWER_META = modname .. ".power"
|
local REDSTONE_POWER_META = modname .. ".power"
|
||||||
local REDSTONE_POWER_META_LAST_STATE = modname .. ".last-power"
|
|
||||||
local REDSTONE_POWER_META_SOURCE = REDSTONE_POWER_META.."."
|
local REDSTONE_POWER_META_SOURCE = REDSTONE_POWER_META.."."
|
||||||
|
|
||||||
local function update_sink(pos)
|
local function update_sink(pos)
|
||||||
|
@ -33,10 +32,10 @@ local function update_sink(pos)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local last_strength = meta:get_int(REDSTONE_POWER_META_LAST_STATE)
|
local last_strength = meta:get_int(REDSTONE_POWER_META)
|
||||||
|
|
||||||
if last_strength ~= strength then
|
if last_strength ~= strength then
|
||||||
print("Updating "..node.name.." at "..vector.to_string(pos).."("..tostring(last_strength).."->"..tostring(strength)..")")
|
--print("Updating "..node.name.." at "..vector.to_string(pos).."("..tostring(last_strength).."->"..tostring(strength)..")")
|
||||||
-- Inform the node of changes
|
-- Inform the node of changes
|
||||||
if strength > 0 then
|
if strength > 0 then
|
||||||
-- Handle activation
|
-- Handle activation
|
||||||
|
@ -54,7 +53,7 @@ local function update_sink(pos)
|
||||||
-- TODO: handle signal level change notification
|
-- TODO: handle signal level change notification
|
||||||
|
|
||||||
-- Update the state as the last thing in case there is a crash in the above code
|
-- Update the state as the last thing in case there is a crash in the above code
|
||||||
meta:set_int(REDSTONE_POWER_META_LAST_STATE, strength)
|
meta:set_int(REDSTONE_POWER_META, strength)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -90,34 +89,35 @@ local function get_positions_from_node_rules(pos, rules_type, list, powered)
|
||||||
rules = POWERED_BLOCK_RULES
|
rules = POWERED_BLOCK_RULES
|
||||||
end
|
end
|
||||||
|
|
||||||
print("rules="..dump(rules))
|
--print("rules="..dump(rules))
|
||||||
|
|
||||||
-- Convert to absolute positions
|
-- Convert to absolute positions
|
||||||
for i=1,#rules do
|
for i=1,#rules do
|
||||||
local next_pos = vector.add(pos, rules[i])
|
local next_pos = vector.add(pos, rules[i])
|
||||||
local next_pos_str = vector.to_string(next_pos)
|
local next_pos_str = vector.to_string(next_pos)
|
||||||
print("\tnext: "..next_pos_str..", prev="..tostring(list[next_pos_str]))
|
--print("\tnext: "..next_pos_str..", prev="..tostring(list[next_pos_str]))
|
||||||
list[next_pos_str] = true
|
list[next_pos_str] = true
|
||||||
|
|
||||||
-- Power solid blocks
|
-- Power solid blocks
|
||||||
if rules[i].spread then
|
if rules[i].spread then
|
||||||
powered[next_pos_str] = true
|
powered[next_pos_str] = true
|
||||||
print("powering "..next_pos_str)
|
--print("powering "..next_pos_str)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return list
|
return list
|
||||||
end
|
end
|
||||||
|
|
||||||
vl_scheduler.register_function("vl_redstone:flow_power",function(task, source_pos, strength, distance)
|
vl_scheduler.register_function("vl_redstone:flow_power",function(task, source_pos, source_strength, distance)
|
||||||
print("Flowing lv"..tostring(strength).." power from "..vector.to_string(source_pos).." for "..tostring(distance).." blocks")
|
print("Flowing lv"..tostring(source_strength).." power from "..vector.to_string(source_pos).." for "..tostring(distance).." blocks")
|
||||||
local processed = {}
|
local processed = {}
|
||||||
local powered = {}
|
local powered = {}
|
||||||
local source_pos_str = vector.to_string(source_pos)
|
local source_pos_str = vector.to_string(source_pos)
|
||||||
|
processed[source_pos_str] = true
|
||||||
|
|
||||||
-- Update the source node's redstone power
|
-- Update the source node's redstone power
|
||||||
local meta = minetest.get_meta(source_pos)
|
local meta = minetest.get_meta(source_pos)
|
||||||
meta:set_int(REDSTONE_POWER_META, strength)
|
meta:set_int(REDSTONE_POWER_META, source_strength)
|
||||||
|
|
||||||
-- Get rules
|
-- Get rules
|
||||||
local list = {}
|
local list = {}
|
||||||
|
@ -126,11 +126,11 @@ vl_scheduler.register_function("vl_redstone:flow_power",function(task, source_po
|
||||||
|
|
||||||
for i=1,distance do
|
for i=1,distance do
|
||||||
local next_list = {}
|
local next_list = {}
|
||||||
local strength = strength - (i - 1)
|
local strength = source_strength - (i - 1)
|
||||||
if strength < 0 then strength = 0 end
|
if strength < 0 then strength = 0 end
|
||||||
|
|
||||||
for pos_str,dir in pairs(list) do
|
for pos_str,dir in pairs(list) do
|
||||||
print("Processing "..pos_str)
|
--print("Processing "..pos_str)
|
||||||
|
|
||||||
if not processed[pos_str] then
|
if not processed[pos_str] then
|
||||||
processed[pos_str] = true
|
processed[pos_str] = true
|
||||||
|
@ -140,7 +140,7 @@ vl_scheduler.register_function("vl_redstone:flow_power",function(task, source_po
|
||||||
|
|
||||||
-- Update node power directly
|
-- Update node power directly
|
||||||
meta:set_int(REDSTONE_POWER_META.."."..source_pos_str, strength)
|
meta:set_int(REDSTONE_POWER_META.."."..source_pos_str, strength)
|
||||||
print("pos="..vector.to_string(pos)..", strength="..tostring(strength))
|
--print("pos="..vector.to_string(pos)..", strength="..tostring(strength))
|
||||||
|
|
||||||
-- handle spread
|
-- handle spread
|
||||||
get_positions_from_node_rules(pos, "conductor", next_list, powered)
|
get_positions_from_node_rules(pos, "conductor", next_list, powered)
|
||||||
|
@ -158,10 +158,23 @@ end)
|
||||||
function vl_redstone.set_power(pos, strength)
|
function vl_redstone.set_power(pos, strength)
|
||||||
local meta = minetest.get_meta(pos)
|
local meta = minetest.get_meta(pos)
|
||||||
local distance = meta:get_int(REDSTONE_POWER_META)
|
local distance = meta:get_int(REDSTONE_POWER_META)
|
||||||
|
|
||||||
|
-- Don't perform an update if the power level is the same as before
|
||||||
|
if distance == strength then return end
|
||||||
|
|
||||||
|
print("previous="..tostring(distance)..", new="..tostring(strength))
|
||||||
|
|
||||||
|
-- Make the update distance the maximum of the new strength and the old strength
|
||||||
if distance < strength then
|
if distance < strength then
|
||||||
distance = strength
|
distance = strength
|
||||||
end
|
end
|
||||||
|
|
||||||
vl_scheduler.add_task(0, "vl_redstone:flow_power", 2, {pos, strength, distance})
|
-- Schedule an update
|
||||||
|
vl_scheduler.add_task(0, "vl_redstone:flow_power", 2, {pos, strength, distance + 1})
|
||||||
|
end
|
||||||
|
|
||||||
|
function vl_redstone.get_power_level(pos)
|
||||||
|
local meta = minetest.get_meta(pos)
|
||||||
|
return meta:get_int(REDSTONE_POWER_META)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -283,14 +283,17 @@ local def_hopper = {
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
on_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
|
on_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
|
||||||
|
mcl_comparators.trigger_update(pos)
|
||||||
minetest.log("action", player:get_player_name() ..
|
minetest.log("action", player:get_player_name() ..
|
||||||
" moves stuff in mcl_hoppers at " .. minetest.pos_to_string(pos))
|
" moves stuff in mcl_hoppers at " .. minetest.pos_to_string(pos))
|
||||||
end,
|
end,
|
||||||
on_metadata_inventory_put = function(pos, listname, index, stack, player)
|
on_metadata_inventory_put = function(pos, listname, index, stack, player)
|
||||||
|
mcl_comparators.trigger_update(pos)
|
||||||
minetest.log("action", player:get_player_name() ..
|
minetest.log("action", player:get_player_name() ..
|
||||||
" moves stuff to mcl_hoppers at " .. minetest.pos_to_string(pos))
|
" moves stuff to mcl_hoppers at " .. minetest.pos_to_string(pos))
|
||||||
end,
|
end,
|
||||||
on_metadata_inventory_take = function(pos, listname, index, stack, player)
|
on_metadata_inventory_take = function(pos, listname, index, stack, player)
|
||||||
|
mcl_comparators.trigger_update(pos)
|
||||||
minetest.log("action", player:get_player_name() ..
|
minetest.log("action", player:get_player_name() ..
|
||||||
" takes stuff from mcl_hoppers at " .. minetest.pos_to_string(pos))
|
" takes stuff from mcl_hoppers at " .. minetest.pos_to_string(pos))
|
||||||
end,
|
end,
|
||||||
|
@ -334,6 +337,11 @@ local def_hopper = {
|
||||||
|
|
||||||
return true
|
return true
|
||||||
end,
|
end,
|
||||||
|
_mcl_comparators_get_reading = function (pos)
|
||||||
|
local meta = minetest.get_meta(pos)
|
||||||
|
local inv = meta:get_inventory()
|
||||||
|
return mcl_comparators.read_inventory(inv, "main")
|
||||||
|
end,
|
||||||
sounds = mcl_sounds.node_sound_metal_defaults(),
|
sounds = mcl_sounds.node_sound_metal_defaults(),
|
||||||
|
|
||||||
_mcl_blast_resistance = 4.8,
|
_mcl_blast_resistance = 4.8,
|
||||||
|
@ -525,16 +533,19 @@ local def_hopper_side = {
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
on_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
|
on_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
|
||||||
|
mcl_comparators.trigger_update(pos)
|
||||||
minetest.log("action", player:get_player_name() ..
|
minetest.log("action", player:get_player_name() ..
|
||||||
" moves stuff in mcl_hoppers at " .. minetest.pos_to_string(pos))
|
" moves stuff in mcl_hoppers at (1) " .. minetest.pos_to_string(pos))
|
||||||
end,
|
end,
|
||||||
on_metadata_inventory_put = function(pos, listname, index, stack, player)
|
on_metadata_inventory_put = function(pos, listname, index, stack, player)
|
||||||
|
mcl_comparators.trigger_update(pos)
|
||||||
minetest.log("action", player:get_player_name() ..
|
minetest.log("action", player:get_player_name() ..
|
||||||
" moves stuff to mcl_hoppers at " .. minetest.pos_to_string(pos))
|
" moves stuff to mcl_hoppers at (2) " .. minetest.pos_to_string(pos))
|
||||||
end,
|
end,
|
||||||
on_metadata_inventory_take = function(pos, listname, index, stack, player)
|
on_metadata_inventory_take = function(pos, listname, index, stack, player)
|
||||||
|
mcl_comparators.trigger_update(pos)
|
||||||
minetest.log("action", player:get_player_name() ..
|
minetest.log("action", player:get_player_name() ..
|
||||||
" takes stuff from mcl_hoppers at " .. minetest.pos_to_string(pos))
|
" takes stuff from mcl_hoppers at (3) " .. minetest.pos_to_string(pos))
|
||||||
end,
|
end,
|
||||||
on_rotate = on_rotate,
|
on_rotate = on_rotate,
|
||||||
sounds = mcl_sounds.node_sound_metal_defaults(),
|
sounds = mcl_sounds.node_sound_metal_defaults(),
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
name = mcl_hoppers
|
name = mcl_hoppers
|
||||||
description = It's just a clone of Minecraft hoppers, functions nearly identical to them minus mesecons making them stop and the way they're placed.
|
description = It's just a clone of Minecraft hoppers, functions nearly identical to them minus mesecons making them stop and the way they're placed.
|
||||||
depends = mcl_core, mcl_formspec, mcl_sounds, mcl_util, mcl_dye
|
depends = mcl_core, mcl_formspec, mcl_sounds, mcl_util, mcl_dye, mcl_comparators
|
||||||
optional_depends = doc, screwdriver
|
optional_depends = doc, screwdriver
|
||||||
|
|
Loading…
Reference in a new issue