From e63f016fc303d259f6dadd7bac47d40253ff3f73 Mon Sep 17 00:00:00 2001 From: FaceDeer Date: Tue, 27 Aug 2019 20:23:02 -0600 Subject: [PATCH] implement rotation. Broke builders in the process. --- controller.lua | 107 +++++++++++++--------------- functions.lua | 147 ++++++++++++++++++++++----------------- geometry.lua | 146 ++++++++++++++++++++++++++++++++++++++ init.lua | 1 + util_item_place_node.lua | 10 --- 5 files changed, 281 insertions(+), 130 deletions(-) create mode 100644 geometry.lua diff --git a/controller.lua b/controller.lua index 31b92db..0da3c5a 100644 --- a/controller.lua +++ b/controller.lua @@ -58,13 +58,13 @@ local get_controller_assembled_formspec = function(digtron_id, player_name) end local inv_tab = function(inv_list) - return "size[9,9]" + return "size[8,9]" .. "position[0.025,0.1]" .. "anchor[0,0]" - .. "container[0.5,0]" + .. "container[0,0]" .. "list[detached:" .. digtron_id .. ";"..inv_list..";0,0;8,4]" -- TODO: paging system for inventory .. "container_end[]" - .. "container[0.5,5]list[current_player;main;0,0;8,1;]list[current_player;main;0,1.25;8,3;8]container_end[]" + .. "container[0,5]list[current_player;main;0,0;8,1;]list[current_player;main;0,1.25;8,3;8]container_end[]" .. "listring[current_player;main]" .. "listring[detached:" .. digtron_id .. ";"..inv_list.."]" end @@ -94,16 +94,14 @@ local get_controller_assembled_formspec = function(digtron_id, player_name) .. "container[4,1]" .. "box[0,0;3,2;#CCCCCC]" .. "label[1.3,0.825;Rotate]" - .. "button[0.1,0.1;1,1;rot_clockwise;Clockwise]" - .. "button[2.1,0.1;1,1;rot_counterclockwise;Widdershins]" + .. "button[0.1,0.1;1,1;rot_counterclockwise;Widdershins]" + .. "button[2.1,0.1;1,1;rot_clockwise;Clockwise]" .. "button[1.1,0.1;1,1;rot_up;Pitch Up]" .. "button[1.1,1.1;1,1;rot_down;Pitch Down]" .. "button[0.1,1.1;1,1;rot_left;Yaw Left]" .. "button[2.1,1.1;1,1;rot_right;Yaw Right]" .. "container_end[]" - - minetest.chat_send_all(dump(context)) if context.current_tab == 1 then return controls .. tabs else @@ -141,32 +139,6 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) end end) - -local get_down = function(facedir) - local top = { - [0]={x=0,y=-1,z=0}, - {x=0,y=0,z=1}, - {x=0,y=0,z=-1}, - {x=1,y=0,y=0}, - {x=-1,y=0,z=0}, - {x=0,y=1,z=0}, - } - return top[math.floor(facedir/4)] -end -function crossProduct( a, b ) - local x, y, z - x = a.y * (b.z or 0) - (a.z or 0) * b.y - y = (a.z or 0) * b.x - a.x * (b.z or 0) - z = a.x * b.y - a.y * b.x - return { x=x, y=y, z=z } -end -local facedir_to_right = {} -for i = 0, 23 do - local dir = minetest.facedir_to_dir(i) - local down = get_down(i) - facedir_to_right[i] = crossProduct(dir, down) -end - -- Controlling a fully armed and operational Digtron minetest.register_on_player_receive_fields(function(player, formname, fields) if formname ~= "digtron:controller_assembled" then @@ -175,15 +147,29 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) local player_name = player:get_player_name() local context = player_interacting_with_digtron_id[player_name] if context == nil then + minetest.chat_send_all("no context") return end local digtron_id = context.digtron_id if digtron_id == nil then + minetest.chat_send_all("no id") return end + local pos = digtron.get_pos(digtron_id) + if pos == nil then + minetest.chat_send_all("no pos") + return + end + local node = minetest.get_node(pos) + if node.name ~= "digtron:controller" then + minetest.chat_send_all("not controller " .. node.name .. " " .. minetest.pos_to_string(pos)) + -- this happened somehow in testing, Digtron needs to be able to recover from this situation. + -- TODO catch this on_rightclick and try remapping the layout to the new position. + return + end + local refresh = false - if fields.tab_header then local new_tab = tonumber(fields.tab_header) if new_tab <= #(context.tabs) + 1 then @@ -204,27 +190,35 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) end end - local pos = digtron.get_pos(digtron_id) - if pos then - local node = minetest.get_node(pos) - if node.name == "digtron:controller" then - local facedir = node.param2 - if fields.move_forward then - digtron.move(digtron_id, vector.add(pos, minetest.facedir_to_dir(facedir)), player_name) - elseif fields.move_back then - digtron.move(digtron_id, vector.add(pos, vector.multiply(minetest.facedir_to_dir(facedir), -1)), player_name) - elseif fields.move_up then - digtron.move(digtron_id, vector.add(pos, vector.multiply(get_down(facedir), -1)), player_name) - elseif fields.move_down then - digtron.move(digtron_id, vector.add(pos, get_down(facedir)), player_name) - elseif fields.move_left then - digtron.move(digtron_id, vector.add(pos, vector.multiply(facedir_to_right[facedir % 23], -1)), player_name) - elseif fields.move_right then - digtron.move(digtron_id, vector.add(pos, facedir_to_right[facedir % 23]), player_name) - end - end - end - + local facedir = node.param2 + -- Translation + if fields.move_forward then + digtron.move(digtron_id, vector.add(pos, digtron.facedir_to_dir(facedir)), player_name) + elseif fields.move_back then + digtron.move(digtron_id, vector.add(pos, vector.multiply(digtron.facedir_to_dir(facedir), -1)), player_name) + elseif fields.move_up then + digtron.move(digtron_id, vector.add(pos, digtron.facedir_to_up(facedir)), player_name) + elseif fields.move_down then + digtron.move(digtron_id, vector.add(pos, vector.multiply(digtron.facedir_to_up(facedir), -1)), player_name) + elseif fields.move_left then + digtron.move(digtron_id, vector.add(pos, vector.multiply(digtron.facedir_to_right(facedir), -1)), player_name) + elseif fields.move_right then + digtron.move(digtron_id, vector.add(pos, digtron.facedir_to_right(facedir)), player_name) + -- Rotation + elseif fields.rot_counterclockwise then + digtron.rotate(digtron_id, vector.multiply(digtron.facedir_to_dir(facedir), -1), player_name) + elseif fields.rot_clockwise then + digtron.rotate(digtron_id, digtron.facedir_to_dir(facedir), player_name) + elseif fields.rot_up then + digtron.rotate(digtron_id, digtron.facedir_to_right(facedir), player_name) + elseif fields.rot_down then + digtron.rotate(digtron_id, vector.multiply(digtron.facedir_to_right(facedir), -1), player_name) + elseif fields.rot_left then + digtron.rotate(digtron_id, vector.multiply(digtron.facedir_to_up(facedir), -1), player_name) + elseif fields.rot_right then + digtron.rotate(digtron_id, digtron.facedir_to_up(facedir), player_name) + end + if fields.test_dig then digtron.execute_cycle(digtron_id, player_name) end @@ -243,8 +237,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) minetest.show_formspec(player_name, "digtron:controller_assembled", get_controller_assembled_formspec(digtron_id, player_name)) - end - + end end) diff --git a/functions.lua b/functions.lua index 239fee1..58b2aa3 100644 --- a/functions.lua +++ b/functions.lua @@ -29,7 +29,7 @@ digtron.retrieve_inventory = retrieve_inventory -- used by formspecs -------------------------------------------------------------------------------------- local create_new_id = function() - local digtron_id = "digtron" .. tostring(math.random(1, 2^21)) -- TODO: use SecureRandom() + local digtron_id = "digtron" .. tostring(math.random(1, 2^21)) -- It's super unlikely that we'll get a collision, but what the heck - maybe something will go -- wrong with the random number source while mod_meta:get_string(digtron_id..":layout") ~= "" do @@ -114,34 +114,10 @@ digtron.get_pos = retrieve_pos ------------------------------------------------------------------------------------------------------- -- Layout creation helpers -local cardinal_dirs = { - {x= 0, y=0, z= 1}, - {x= 1, y=0, z= 0}, - {x= 0, y=0, z=-1}, - {x=-1, y=0, z= 0}, - {x= 0, y=-1, z= 0}, - {x= 0, y=1, z= 0}, -} -digtron.cardinal_dirs = cardinal_dirs -- used by builder entities as well --- Mapping from facedir value to index in cardinal_dirs. -local facedir_to_dir_map = digtron.facedir_to_dir_map - --- Turn the cardinal directions into a set of integers you can add to a hash to step in that direction. -local cardinal_dirs_hash = {} -for i, dir in ipairs(cardinal_dirs) do - cardinal_dirs_hash[i] = minetest.hash_node_position(dir) - minetest.hash_node_position({x=0, y=0, z=0}) -end - --- Given a facedir, returns an index into either cardinal_dirs or cardinal_dirs_hash that --- can be used to determine what this node is "aimed" at -local facedir_to_dir_index = function(param2) - return facedir_to_dir_map[param2 % 32] -end - -- recursive function searches out all connected unassigned digtron nodes local get_all_digtron_nodes get_all_digtron_nodes = function(pos, digtron_nodes, digtron_adjacent, player_name) - for _, dir in ipairs(cardinal_dirs) do + for _, dir in ipairs(digtron.cardinal_dirs) do local test_pos = vector.add(pos, dir) local test_hash = minetest.hash_node_position(test_pos) if not (digtron_nodes[test_hash] or digtron_adjacent[test_hash]) then -- don't test twice @@ -204,15 +180,15 @@ local refresh_adjacent = function(digtron_id) local adjacent_to_diggers = {} local adjacent_to_builders = {} for hash, data in pairs(layout) do - for _, dir_hash in ipairs(cardinal_dirs_hash) do - local potential_adjacent = hash+dir_hash + for _, dir_hash in ipairs(digtron.cardinal_dirs_hash) do + local potential_adjacent = hash + dir_hash if layout[potential_adjacent] == nil then adjacent[potential_adjacent] = true end end if minetest.get_item_group(data.node.name, "digtron") == 3 then - local dir_hash = cardinal_dirs_hash[facedir_to_dir_index(data.node.param2)] + local dir_hash = digtron.facedir_to_dir_hash(data.node.param2) local potential_target = hash + dir_hash -- pointed at this hash if layout[potential_target] == nil then -- not pointed at another Digtron node local fields = data.meta.fields @@ -224,7 +200,7 @@ local refresh_adjacent = function(digtron_id) end end if minetest.get_item_group(data.node.name, "digtron") == 4 then - local dir_hash = cardinal_dirs_hash[facedir_to_dir_index(data.node.param2)] + local dir_hash = digtron.facedir_to_dir_hash(data.node.param2) local potential_target = hash + dir_hash if layout[potential_target] == nil then local fields = data.meta.fields @@ -307,7 +283,8 @@ digtron.assemble = function(root_pos, player_name) local layout = {} for hash, node in pairs(digtron_nodes) do - local relative_hash = hash - root_hash + local relative_hash = minetest.hash_node_position(vector.subtract(minetest.get_position_from_hash(hash), root_pos)) + local current_meta if hash == root_hash then current_meta = root_meta -- we're processing the controller, we already have a reference to its meta @@ -385,9 +362,8 @@ end -- Returns pos, node, and meta for the digtron node provided the in-world node matches the layout -- returns nil otherwise -local get_valid_data = function(digtron_id, root_hash, hash, data, function_name) - local node_hash = hash + root_hash -- TODO may want to return this as well? - local node_pos = minetest.get_position_from_hash(node_hash) +local get_valid_data = function(digtron_id, root_pos, hash, data, function_name) + local node_pos = vector.add(minetest.get_position_from_hash(hash), root_pos) local node = minetest.get_node(node_pos) local node_meta = minetest.get_meta(node_pos) local target_digtron_id = node_meta:get_string("digtron_id") @@ -440,11 +416,9 @@ digtron.disassemble = function(digtron_id, player_name) return end - local root_hash = minetest.hash_node_position(root_pos) - -- Write metadata and inventory to in-world node at this location for hash, data in pairs(layout) do - local node_pos, node, node_meta = get_valid_data(digtron_id, root_hash, hash, data, "digtron.disassemble") + local node_pos, node, node_meta = get_valid_data(digtron_id, root_pos, hash, data, "digtron.disassemble") if node_pos then local node_inv = node_meta:get_inventory() @@ -515,10 +489,9 @@ digtron.remove_from_world = function(digtron_id, player_name) return {} end - local root_hash = minetest.hash_node_position(root_pos) local nodes_to_destroy = {} for hash, data in pairs(layout) do - local node_pos = get_valid_data(digtron_id, root_hash, hash, data, "digtron.destroy") + local node_pos = get_valid_data(digtron_id, root_pos, hash, data, "digtron.remove_from_world") if node_pos then table.insert(nodes_to_destroy, node_pos) end @@ -542,12 +515,12 @@ digtron.is_buildable_to = function(digtron_id, root_pos, player_name, ignore_nod -- If this digtron is already in-world, we're likely testing as part of a movement attempt. -- Record its existing node locations, they will be treated as buildable_to - local old_pos = retrieve_pos(digtron_id) + local old_root_pos = retrieve_pos(digtron_id) local ignore_hashes = {} - if old_pos then - local old_root_hash = minetest.hash_node_position(old_pos) - for layout_hash, _ in pairs(layout) do - ignore_hashes[layout_hash + old_root_hash] = true + if old_root_pos then + for hash, _ in pairs(layout) do + local old_hash = minetest.hash_node_position(vector.add(minetest.get_position_from_hash(hash), old_root_pos)) + ignore_hashes[old_hash] = true end end if ignore_nodes then @@ -556,15 +529,14 @@ digtron.is_buildable_to = function(digtron_id, root_pos, player_name, ignore_nod end end - local root_hash = minetest.hash_node_position(root_pos) local succeeded = {} local failed = {} local permitted = true - for layout_hash, data in pairs(layout) do + for hash, data in pairs(layout) do -- Don't use get_valid_data, the Digtron isn't in-world yet - local node_hash = layout_hash + root_hash - local node_pos = minetest.get_position_from_hash(node_hash) + local node_pos = vector.add(minetest.get_position_from_hash(hash), root_pos) + local node_hash = minetest.hash_node_position(node_pos) local node = minetest.get_node(node_pos) local node_def = minetest.registered_nodes[node.name] -- TODO: lots of testing needed here @@ -590,11 +562,10 @@ end -- Places the Digtron into the world. digtron.build_to_world = function(digtron_id, root_pos, player_name) local layout = retrieve_layout(digtron_id) - local root_hash = minetest.hash_node_position(root_pos) for hash, data in pairs(layout) do -- Don't use get_valid_data, the Digtron isn't in-world yet - local node_pos = minetest.get_position_from_hash(hash + root_hash) + local node_pos = vector.add(minetest.get_position_from_hash(hash), root_pos) minetest.set_node(node_pos, data.node) local meta = minetest.get_meta(node_pos) for field, value in pairs(data.meta.fields) do @@ -623,6 +594,61 @@ digtron.move = function(digtron_id, dest_pos, player_name) end end + + +------------------------------------------------------------------------ +-- Rotation + +local rotate_layout = function(digtron_id, axis) + local layout = retrieve_layout(digtron_id) + local axis_hash = minetest.hash_node_position(axis) + local rotated_layout = {} + for hash, data in pairs(layout) do + -- Facings + local node_name = data.node.name + local node_def = minetest.registered_nodes[node_name] + if node_def.paramtype2 == "wallmounted" then + data.node.param2 = digtron.rotate_wallmounted(axis_hash, data.node.param2) + elseif node_def.paramtype2 == "facedir" then + data.node.param2 = digtron.rotate_facedir(axis_hash, data.node.param2) + end + + -- Rotate builder item facings + if minetest.get_item_group(node_name, "digtron") == 4 then + local build_item = data.meta.fields.item + local build_item_def = minetest.registered_items[build_item] + if build_item_def.paramtype2 == "wallmounted" then + data.meta.fields.facing = digtron.rotate_wallmounted(axis_hash, tonumber(data.meta.fields.facing)) + elseif build_item_def.paramtype2 == "facedir" then + data.meta.fields.facing = digtron.rotate_facedir(axis_hash, tonumber(data.meta.fields.facing)) + end + end + + -- Position + local pos = minetest.get_position_from_hash(hash) + pos = digtron.rotate_pos(axis_hash, pos) + local new_hash = minetest.hash_node_position(pos) + rotated_layout[new_hash] = data + end + + invalidate_layout_cache(digtron_id) + persist_layout(digtron_id, rotated_layout) +end + +digtron.rotate = function(digtron_id, axis, player_name) + -- TODO: rotation version of is_buildable_to + local root_pos = retrieve_pos(digtron_id) + local removed = digtron.remove_from_world(digtron_id, player_name) + rotate_layout(digtron_id, axis) + digtron.build_to_world(digtron_id, root_pos, player_name) + -- Don't need to do fancy callback checking for digtron nodes since I made all those + -- nodes and I know they don't have anything that needs to be done for them. + -- Just check for falling nodes. + for _, removed_pos in ipairs(removed) do + minetest.check_for_falling(removed_pos) + end +end + ------------------------------------------------------------------------------------ -- Digging @@ -634,14 +660,13 @@ local predict_dig = function(digtron_id, player_name, controlling_coordinate) .."a predictive inventory or a root position for " .. digtron_id) return end - local root_hash = minetest.hash_node_position(root_pos) local leftovers = {} local dug_positions = {} local cost = 0 for target_hash, digger_data in pairs(retrieve_all_digger_targets(digtron_id)) do - local target_pos = minetest.get_position_from_hash(target_hash + root_hash + digger_data.dir_hash) + local target_pos = vector.add(minetest.get_position_from_hash(target_hash + digger_data.dir_hash), root_pos) local target_node = minetest.get_node(target_pos) local target_name = target_node.name local targetdef = minetest.registered_nodes[target_name] @@ -751,15 +776,14 @@ end ------------------------------------------------------------------------------------------------------ -- Building --- need to provide new_pos because Digtron moves before building -local predict_build = function(digtron_id, new_pos, player_name, ignore_nodes, controlling_coordinate) +-- need to provide root_pos because Digtron moves before building +local predict_build = function(digtron_id, root_pos, player_name, ignore_nodes, controlling_coordinate) local predictive_inv = get_predictive_inventory(digtron_id) if not predictive_inv then minetest.log("error", "[Digtron] predict_build failed to retrieve " .."a predictive inventory for " .. digtron_id) return end - local root_hash = minetest.hash_node_position(new_pos) local ignore_hashes = {} if ignore_nodes then @@ -773,11 +797,10 @@ local predict_build = function(digtron_id, new_pos, player_name, ignore_nodes, c local cost = 0 for target_hash, builder_data in pairs(retrieve_all_builder_targets(digtron_id)) do - local absolute_hash = target_hash + root_hash local dir_hash = builder_data.dir_hash local periodicity_permitted = nil for i = 1, builder_data.extrusion do - local target_pos = minetest.get_position_from_hash(absolute_hash + i * dir_hash) + local target_pos = vector.add(minetest.get_position_from_hash(target_hash + i * dir_hash), root_pos) if periodicity_permitted == nil then -- test periodicity and offset once periodicity_permitted = (target_pos[controlling_coordinate] + builder_data.offset) % builder_data.period == 0 @@ -883,7 +906,7 @@ end -- Used to determine which coordinate is being checked for periodicity. eg, if the digtron is moving in the z direction, then periodicity is checked for every n nodes in the z axis. local get_controlling_coordinate = function(facedir) -- used for determining builder period and offset - local dir = facedir_to_dir_map[facedir] + local dir = digtron.facedir_to_dir_map[facedir] if dir == 1 or dir == 3 then return "z" elseif dir == 2 or dir == 4 then @@ -913,7 +936,7 @@ digtron.execute_cycle = function(digtron_id, player_name) local controlling_coordinate = get_controlling_coordinate(root_facedir) local dig_leftovers, nodes_to_dig, dig_cost = predict_dig(digtron_id, player_name, controlling_coordinate) - local new_root_pos = vector.add(old_root_pos, cardinal_dirs[facedir_to_dir_index(root_facedir)]) + local new_root_pos = vector.add(old_root_pos, digtron.facedir_to_dir(root_facedir)) -- TODO: convert nodes_to_dig into a hash map here and pass that in to reduce duplication? local buildable_to, succeeded, failed = digtron.is_buildable_to(digtron_id, new_root_pos, player_name, nodes_to_dig) local missing_items, built_nodes, build_cost = predict_build(digtron_id, new_root_pos, player_name, nodes_to_dig, controlling_coordinate) @@ -952,7 +975,7 @@ digtron.execute_cycle = function(digtron_id, player_name) else clear_predictive_inventory(digtron_id) digtron.show_buildable_nodes({}, failed) - minetest.sound_play("digtron_squeal", {gain = 0.5, pos=new_pos}) + minetest.sound_play("digtron_squeal", {gain = 0.5, pos=new_root_pos}) end end @@ -989,9 +1012,7 @@ digtron.can_dig = function(pos, digger) return true end - local root_hash = minetest.hash_node_position(root_pos) - local here_hash = minetest.hash_node_position(pos) - local layout_hash = here_hash - root_hash + local layout_hash = minetest.hash_node_position(vector.subtract(pos, root_pos)) local layout_data = layout[layout_hash] if layout_data == nil or layout_data.node == nil then minetest.log("error", "[Digtron] can_dig was called on a " .. node.name .. " at location " diff --git a/geometry.lua b/geometry.lua new file mode 100644 index 0000000..82ca5a0 --- /dev/null +++ b/geometry.lua @@ -0,0 +1,146 @@ +local cardinal_dirs = { + {x = 0, y = 0, z = 1}, + {x = 1, y = 0, z = 0}, + {x = 0, y = 0, z = -1}, + {x = -1, y = 0, z = 0}, + {x = 0, y = -1, z = 0}, + {x = 0, y = 1, z = 0}, +} +-- Turn the cardinal directions into a set of integers you can add to a hash to step in that direction. +local cardinal_dirs_hash = {} +for i, dir in ipairs(cardinal_dirs) do + cardinal_dirs_hash[i] = minetest.hash_node_position(dir) - minetest.hash_node_position({x = 0, y = 0, z = 0}) +end + +-- Mapping from facedir value to index in cardinal_dirs. +local facedir_to_dir_map = { + [0] = 1, 2, 3, 4, + 5, 2, 6, 4, + 6, 2, 5, 4, + 1, 5, 3, 6, + 1, 6, 3, 5, + 1, 4, 3, 2, +} + +local facedir_to_up_map = { + [0] = 6, 6, 6, 6, + 3, 3, 3, 3, + 1, 1, 1, 1, + 4, 4, 4, 4, + 2, 2, 2, 2, + 5, 5, 5, 5, +} + +local facedir_to_right_map = { + [0] = 2, 3, 4, 1, + 2, 6, 4, 6, + 2, 5, 4, 6, + 5, 3, 6, 1, + 6, 3, 5, 1, + 4, 3, 2, 1, +} + +local facedir_to_dir = function(facedir) + return cardinal_dirs[facedir_to_dir_map[facedir % 32]] +end +local facedir_to_dir_hash = function(facedir) + return cardinal_dirs_hash[facedir_to_dir_map[facedir % 32]] +end +local facedir_to_up = function(facedir) + return cardinal_dirs[facedir_to_up_map[facedir % 32]] +end +local facedir_to_up_hash = function(facedir) + return cardinal_dirs_hash[facedir_to_up_map[facedir % 32]] +end +local facedir_to_right = function(facedir) + return cardinal_dirs[facedir_to_right_map[facedir % 32]] +end +local facedir_to_right_hash = function(facedir) + return cardinal_dirs_hash[facedir_to_right_map[facedir % 32]] +end + +-- Rotation + +local negative_x = minetest.hash_node_position({x = -1, y = 0, z = 0}) +local positive_x = minetest.hash_node_position({x = 1, y = 0, z = 0}) +local negative_y = minetest.hash_node_position({x = 0, y = -1, z = 0}) +local positive_y = minetest.hash_node_position({x = 0, y = 1, z = 0}) +local negative_z = minetest.hash_node_position({x = 0, y = 0, z = -1}) +local positive_z = minetest.hash_node_position({x = 0, y = 0, z = 1}) + +local facedir_rot = { + [negative_x] = {[0] = 4, 5, 6, 7, 22, 23, 20, 21, 0, 1, 2, 3, 13, 14, 15, 12, 19, 16, 17, 18, 10, 11, 8, 9}, -- 270 degrees + [positive_x] = {[0] = 8, 9, 10, 11, 0, 1, 2, 3, 22, 23, 20, 21, 15, 12, 13, 14, 17, 18, 19, 16, 6, 7, 4, 5}, -- 90 degrees + [negative_y] = {[0] = 3, 0, 1, 2, 19, 16, 17, 18, 15, 12, 13, 14, 7, 4, 5, 6, 11, 8, 9, 10, 21, 22, 23, 20}, -- 270 degrees + [positive_y] = {[0] = 1, 2, 3, 0, 13, 14, 15, 12, 17, 18, 19, 16, 9, 10, 11, 8, 5, 6, 7, 4, 23, 20, 21, 22}, -- 90 degrees + [negative_z] = {[0] = 16, 17, 18, 19, 5, 6, 7, 4, 11, 8, 9, 10, 0, 1, 2, 3, 20, 21, 22, 23, 12, 13, 14, 15}, -- 270 degrees + [positive_z] = {[0] = 12, 13, 14, 15, 7, 4, 5, 6, 9, 10, 11, 8, 20, 21, 22, 23, 0, 1, 2, 3, 16, 17, 18, 19}, -- 90 degrees +} + +local wallmounted_rot = { + [negative_x] = {[0] = 4, 5, 2, 3, 1, 0}, -- 270 degrees + [positive_x] = {[0] = 5, 4, 2, 3, 0, 1}, -- 90 degrees + [negative_y] = {[0] = 0, 1, 4, 5, 3, 2}, -- 270 degrees + [positive_y] = {[0] = 0, 1, 5, 4, 2, 3}, -- 90 degrees + [negative_z] = {[0] = 3, 2, 0, 1, 4, 5}, -- 270 degrees + [positive_z] = {[0] = 2, 3, 1, 0, 4, 5}, -- 90 degrees +} + +local rotate_facedir = function(axis_hash, facedir) + return facedir_rot[axis_hash][facedir] +end +local rotate_wallmounted = function(axis_hash, facedir) + return wallmounted_rot[axis_hash][facedir] +end + +--90 degrees CW about x-axis: (x, y, z) -> (x, -z, y) +--90 degrees CCW about x-axis: (x, y, z) -> (x, z, -y) +--90 degrees CW about y-axis: (x, y, z) -> (-z, y, x) +--90 degrees CCW about y-axis: (x, y, z) -> (z, y, -x) +--90 degrees CW about z-axis: (x, y, z) -> (y, -x, z) +--90 degrees CCW about z-axis: (x, y, z) -> (-y, x, z) +-- operates directly on the pos vector +-- Rotates it around origin +local rotate_pos = function(axis_hash, pos) + if axis_hash == negative_x and not (pos.y == 0 and pos.z == 0) then + local temp_z = pos.z + pos.z = pos.y + pos.y = -temp_z + elseif axis_hash == positive_x and not (pos.y == 0 and pos.z == 0) then + local temp_z = pos.z + pos.z = -pos.y + pos.y = temp_z + elseif axis_hash == negative_y and not (pos.x == 0 and pos.z == 0) then + local temp_x = pos.x + pos.x = -pos.z + pos.z = temp_x + elseif axis_hash == positive_y and not (pos.x == 0 and pos.z == 0) then + local temp_x = pos.x + pos.x = pos.z + pos.z = -temp_x + elseif axis_hash == negative_z and not (pos.x == 0 and pos.y == 0) then + local temp_x = pos.x + pos.x = -pos.y + pos.y = temp_x + elseif axis_hash == positive_z and not (pos.x == 0 and pos.y == 0) then + local temp_x = pos.x + pos.x = pos.y + pos.y = -temp_x + end + return pos +end + +digtron.cardinal_dirs = cardinal_dirs -- used by builder entities as well +digtron.cardinal_dirs_hash = cardinal_dirs_hash +digtron.facedir_to_dir_map = facedir_to_dir_map + +digtron.facedir_to_dir = facedir_to_dir +digtron.facedir_to_dir_hash = facedir_to_dir_hash +digtron.facedir_to_up = facedir_to_up +digtron.facedir_to_up_hash = facedir_to_up_hash +digtron.facedir_to_right = facedir_to_right +digtron.facedir_to_right_hash = facedir_to_right_hash + +digtron.rotate_pos = rotate_pos +digtron.rotate_wallmounted = rotate_wallmounted +digtron.rotate_facedir = rotate_facedir \ No newline at end of file diff --git a/init.lua b/init.lua index 5df8ef8..3415d18 100644 --- a/init.lua +++ b/init.lua @@ -28,6 +28,7 @@ dofile(modpath.."/class_fakeplayer.lua") digtron.fake_player = DigtronFakePlayer.create({x=0,y=0,z=0}, "fake_player") -- since we only need one fake player at a time and it doesn't retain useful state, create a global one and just update it as needed. dofile(modpath.."/util_item_place_node.lua") +dofile(modpath.."/geometry.lua") dofile(modpath.."/entities.lua") dofile(modpath.."/functions.lua") dofile(modpath.."/controller.lua") diff --git a/util_item_place_node.lua b/util_item_place_node.lua index ba6ff37..16cbb3b 100644 --- a/util_item_place_node.lua +++ b/util_item_place_node.lua @@ -18,16 +18,6 @@ --See the GNU Lesser General Public License for more details: --https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html --- Mapping from facedir value to index in facedir_to_dir. -digtron.facedir_to_dir_map = { - [0]=1, 2, 3, 4, - 5, 2, 6, 4, - 6, 2, 5, 4, - 1, 5, 3, 6, - 1, 6, 3, 5, - 1, 4, 3, 2, -} - local function has_prefix(str, prefix) return str:sub(1, string.len(prefix)) == prefix end