Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Digtron 2.0 digpocalypse #89

Draft
wants to merge 63 commits into
base: master
Choose a base branch
from
Draft
Changes from 1 commit
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
6a38e68
clean the slate! Old code will be brought back as it's needed.
FaceDeer Aug 17, 2019
4e2ac43
can now create detached inventory. May be very buggy yet.
FaceDeer Aug 18, 2019
90c2315
persisting inventory between runs
FaceDeer Aug 18, 2019
ff22918
can now reliably construct and deconstruct
FaceDeer Aug 18, 2019
27c9d82
a bit of naming work
FaceDeer Aug 18, 2019
9d52699
make constructed controllers pick-uppable
FaceDeer Aug 18, 2019
fda6aa9
a little more setup for placing constructed Digtrons
FaceDeer Aug 18, 2019
e88a3fa
basic ability to pick up and put down a complete digtron
FaceDeer Aug 19, 2019
4031ea0
tidy up aftermath of building a constructed digtron
FaceDeer Aug 19, 2019
e16035b
save bounding box relative to root.
FaceDeer Aug 19, 2019
1c732ae
change metadata naming standard, add some corrupted data checks
FaceDeer Aug 19, 2019
a9420ea
explosions automatically deconstruct Digtrons.
FaceDeer Aug 20, 2019
03c9a81
so... much... error checking...
FaceDeer Aug 20, 2019
2283cdb
hide digtron_id from clients, change "construct" to "assemble", vario…
FaceDeer Aug 20, 2019
f14b0a9
no need to expose caches globally
FaceDeer Aug 20, 2019
2928896
indicator entities for when Digtron can't be built
FaceDeer Aug 21, 2019
7f5cf4d
add a digger head model
FaceDeer Aug 21, 2019
5d7eea2
static digger variant for unassembled digtrons
FaceDeer Aug 22, 2019
c295999
digtron 2.0 can now move
FaceDeer Aug 23, 2019
80b9530
add a basic beginning to dig prediction
FaceDeer Aug 24, 2019
63ea131
remove origin displacement, not really needed
FaceDeer Aug 24, 2019
a0f47b5
no need to persist derived values. Cache digger targets.
FaceDeer Aug 25, 2019
a74cc14
add setting formspec to disassembled digger
FaceDeer Aug 25, 2019
cafb2ec
add config, add material cost to predict_dig
FaceDeer Aug 25, 2019
683b941
split inventory functions into a separate file, add predictive invent…
FaceDeer Aug 25, 2019
426cd4d
IT DIGS
FaceDeer Aug 25, 2019
b90e571
Executing all on-dig callbacks "properly" with a fake player
FaceDeer Aug 25, 2019
7b2b296
pull some code out into subroutines
FaceDeer Aug 25, 2019
1333748
further subroutine breakdown
FaceDeer Aug 25, 2019
beed475
begin reintroducing builder nodes
FaceDeer Aug 26, 2019
e0d0270
IT BUILDS
FaceDeer Aug 26, 2019
256ec95
bring back the hacked item place function
FaceDeer Aug 26, 2019
a410187
extrusion, and account for diggers/builders pointing at the same targ…
FaceDeer Aug 27, 2019
395a794
offset/periodicity implemented
FaceDeer Aug 27, 2019
861d9b2
messy formspec code, but can now translate Digtron around freely
FaceDeer Aug 27, 2019
e63f016
implement rotation. Broke builders in the process.
FaceDeer Aug 28, 2019
8ecc738
add can-build check to rotation
FaceDeer Aug 28, 2019
c35104e
Make control formspec a bit snugger, eliminate unnecessary disassembl…
FaceDeer Aug 28, 2019
df4c7f7
add a distinct rotation sound
FaceDeer Aug 28, 2019
70e1649
create separate unassembled controller, make builder "read" work.
FaceDeer Aug 31, 2019
7c08241
add sequencer tab. Digtron doesn't yet actually use the sequence set …
FaceDeer Aug 31, 2019
263aba9
fix/remove a few TODOs
FaceDeer Aug 31, 2019
b1cd43c
in theory, Digtron 2.0 can now recover from total metadata write-to-m…
FaceDeer Sep 1, 2019
0eb3d1f
add dual digger nodes, recipes
FaceDeer Sep 1, 2019
d743636
make dual diggers function dually
FaceDeer Sep 1, 2019
e717f09
stair digging is now possible, if a bit hacky.
FaceDeer Sep 2, 2019
1fa10d8
make soft diggers work
FaceDeer Sep 2, 2019
63a7f6a
implement duplicator
FaceDeer Sep 2, 2019
ce6f05c
digtrons can do hp damage now
FaceDeer Sep 3, 2019
a998fd9
tidy recipes
FaceDeer Sep 3, 2019
772bcdd
add paging to inventory tabs
FaceDeer Sep 3, 2019
ace967d
make sequencer data structure more robust
FaceDeer Sep 3, 2019
fe5979a
sequencer can now advance through the sequence. Still not actually ho…
FaceDeer Sep 8, 2019
8732366
command UI now lets multiple cycles be requested.
FaceDeer Sep 8, 2019
f83f5cb
remove need to pass formname around
FaceDeer Sep 8, 2019
61be57e
give builder items a little love
FaceDeer Sep 8, 2019
926f722
more loopable engine sound, supporting sequences better
FaceDeer Sep 8, 2019
8f70b98
fix a bug with building into freshly-dug spots
FaceDeer Sep 8, 2019
b568fff
fix bug in rotate, wasn't invalidating adjacent node cache
FaceDeer Sep 8, 2019
d79b226
rearrange context cache to play nice with players using multiple digt…
FaceDeer Sep 9, 2019
1e776de
update to client-side translation system
FaceDeer Feb 22, 2020
6745446
fix name preservation, add stop button
FaceDeer Feb 24, 2020
3c0fbca
make it possible to edit builders that are part of an assembled digtron
FaceDeer Mar 2, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Executing all on-dig callbacks "properly" with a fake player
FaceDeer committed Aug 25, 2019

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
commit b90e5713aa887a32fc041b2f8512fc9030328f34
145 changes: 145 additions & 0 deletions class_fakeplayer.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
-- The purpose of this class is to have something that can be passed into callbacks that
-- demand a "Player" object as a parameter and hopefully prevent the mods that have
-- registered with those callbacks from crashing on a nil dereference or bad function
-- call. This is not supposed to be a remotely functional thing, it's just supposed
-- to provide dummy methods and return values of the correct data type for anything that
-- might ignore the false "is_player()" return and go ahead and try to use this thing
-- anyway.

-- I'm trying to patch holes in bad mod programming, essentially. If a mod is so badly
-- programmed that it crashes anyway there's not a lot else I can do on my end of things.

DigtronFakePlayer = {}
DigtronFakePlayer.__index = DigtronFakePlayer

local function return_value(x)
return (function() return x end)
end

local function return_nil()
return nil
end

local function return_empty_string()
return ""
end

local function return_zero()
return 0
end

local function return_empty_table()
return {}
end

function DigtronFakePlayer.update(self, pos, player_name)
self.is_fake_player = ":digtron " .. player_name
self.get_pos = return_value(pos)
end

function DigtronFakePlayer.create(pos, player_name)
local self = {}
setmetatable(self, DigtronFakePlayer)

self.is_fake_player = ":digtron " .. player_name

-- ObjectRef
self.get_pos = return_value(pos)
self.set_pos = return_nil
self.move_to = return_nil
self.punch = return_nil
self.right_click = return_nil
self.get_hp = return_value(10)
self.set_hp = return_nil
self.get_inventory = return_nil -- returns an `InvRef`
self.get_wield_list = return_empty_string
self.get_wield_index = return_value(1)
self.get_wielded_item = return_value(ItemStack(nil))
self.set_wielded_item = return_value(false)
self.set_armor_groups = return_nil
self.get_armor_groups = return_empty_table
self.set_animation = return_nil
self.get_animation = return_nil -- a set of values, maybe important?
self.set_attach = return_nil
self.get_attach = return_nil
self.set_detach = return_nil
self.set_bone_position = return_nil
self.get_bone_position = return_nil
self.set_properties = return_nil
self.get_properties = return_empty_table

self.is_player = return_value(false)

self.get_nametag_attributes = return_empty_table
self.set_nametag_attributes = return_nil

--LuaEntitySAO
self.set_velocity = return_nil
self.get_velocity = return_value({x=0,y=0,z=0})
self.set_acceleration = return_nil
self.get_acceleration = return_value({x=0,y=0,z=0})
self.set_yaw = return_nil
self.get_yaw = return_zero
self.set_texture_mod = return_nil
self.get_texture_mod = return_nil -- maybe important?
self.set_sprite = return_nil
--self.get_entity_name` (**Deprecated**: Will be removed in a future version)
self.get_luaentity = return_nil

-- Player object

self.get_player_name = return_empty_string
self.get_player_velocity = return_nil
self.get_look_dir = return_value({x=0,y=1,z=0})
self.get_look_horizontal = return_zero
self.set_look_horizontal = return_nil
self.get_look_vertical = return_zero
self.set_look_vertical = return_nil

--self.get_look_pitch`: pitch in radians - Deprecated as broken. Use `get_look_vertical`
--self.get_look_yaw`: yaw in radians - Deprecated as broken. Use `get_look_horizontal`
--self.set_look_pitch(radians)`: sets look pitch - Deprecated. Use `set_look_vertical`.
--self.set_look_yaw(radians)`: sets look yaw - Deprecated. Use `set_look_horizontal`.
self.get_breath = return_value(10)
self.set_breath = return_nil
self.get_attribute = return_nil
self.set_attribute = return_nil

self.set_inventory_formspec = return_nil
self.get_inventory_formspec = return_empty_string
self.get_player_control = return_value({jump=false, right=false, left=false, LMB=false, RMB=false, sneak=false, aux1=false, down=false, up=false} )
self.get_player_control_bits = return_zero

self.set_physics_override = return_nil
self.get_physics_override = return_value({speed = 1, jump = 1, gravity = 1, sneak = true, sneak_glitch = false, new_move = true,})


self.hud_add = return_nil
self.hud_remove = return_nil
self.hud_change = return_nil
self.hud_get = return_nil -- possibly important return value?
self.hud_set_flags = return_nil
self.hud_get_flags = return_value({ hotbar=true, healthbar=true, crosshair=true, wielditem=true, breathbar=true, minimap=true })
self.hud_set_hotbar_itemcount = return_nil
self.hud_get_hotbar_itemcount = return_zero
self.hud_set_hotbar_image = return_nil
self.hud_get_hotbar_image = return_empty_string
self.hud_set_hotbar_selected_image = return_nil
self.hud_get_hotbar_selected_image = return_empty_string
self.set_sky = return_nil
self.get_sky = return_empty_table -- may need members on this table

self.set_clouds = return_nil
self.get_clouds = return_value({density = 0, color = "#fff0f0e5", ambient = "#000000", height = 120, thickness = 16, speed = {x=0, y=-2}})

self.override_day_night_ratio = return_nil
self.get_day_night_ratio = return_nil

self.set_local_animation = return_nil
self.get_local_animation = return_empty_table

self.set_eye_offset = return_nil
self.get_eye_offset = return_value({x=0,y=0,z=0},{x=0,y=0,z=0})

return self
end
81 changes: 67 additions & 14 deletions functions.lua
Original file line number Diff line number Diff line change
@@ -30,8 +30,7 @@ local create_new_id = function()
while mod_meta:get_string(digtron_id..":layout") ~= "" do
digtron_id = "digtron" .. tostring(math.random(1, 2^21))
end
local inv = minetest.create_detached_inventory(digtron_id, detached_inventory_callbacks)
return digtron_id, inv
return digtron_id
end

-- Deletes a Digtron record. Note: just throws everything away, this is not digtron.disassemble.
@@ -273,7 +272,8 @@ digtron.assemble = function(root_pos, player_name)
-- use this info, but it's small and IMO not worth the complexity.
get_all_digtron_nodes(root_pos, digtron_nodes, digtron_adjacent, player_name)

local digtron_id, digtron_inv = create_new_id(root_pos)
local digtron_id = create_new_id(root_pos)
local digtron_inv = retrieve_inventory(digtron_id)

local layout = {}

@@ -536,7 +536,7 @@ digtron.is_buildable_to = function(digtron_id, root_pos, player_name, ignore_nod
if not (
(node_def and node_def.buildable_to)
or ignore_hashes[node_hash]) or
minetest.is_protected(target_pos, player_name)
minetest.is_protected(node_pos, player_name)
then
if return_immediately_on_failure then
return false -- no need to test further, don't return node positions
@@ -656,27 +656,80 @@ local predict_dig = function(digtron_id, player_name)
return leftovers, dug_positions, cost
end

-- Removes nodes and records node info so on-dig callbacks can be called later
local get_and_remove_nodes = function(nodes_to_dig)
local ret = {}
for _, pos in ipairs(nodes_to_dig) do
local record = {}
record.pos = pos
record.node = minetest.get_node(pos)
record.meta = minetest.get_meta(pos)
minetest.remove_node(pos)
table.insert(ret, record)
end
return ret
end

digtron.execute_cycle = function(digtron_id, player_name)
local leftovers, nodes_to_dig, cost = predict_dig(digtron_id, player_name)
local root_pos = retrieve_pos(digtron_id)
local root_node = minetest.get_node(root_pos)
local new_pos = vector.add(root_pos, cardinal_dirs[facedir_to_dir_index(root_node.param2)])
local buildable_to, succeeded, failed = digtron.is_buildable_to(digtron_id, new_pos, player_name, nodes_to_dig, return_immediately_on_failure)
local old_root_pos = retrieve_pos(digtron_id)
local root_node = minetest.get_node(old_root_pos)
local new_root_pos = vector.add(old_root_pos, cardinal_dirs[facedir_to_dir_index(root_node.param2)])
local buildable_to, succeeded, failed = digtron.is_buildable_to(digtron_id, new_root_pos, player_name, nodes_to_dig)

if buildable_to then
digtron.fake_player:update(old_root_pos, player_name)
local removed = digtron.remove_from_world(digtron_id, player_name)
minetest.bulk_set_node(nodes_to_dig, {name="air"})
digtron.build_to_world(digtron_id, new_pos, player_name)
minetest.sound_play("digtron_construction", {gain = 0.5, pos=new_pos})

local nodes_dug = get_and_remove_nodes(nodes_to_dig)

local nodes_dug_count = #nodes_to_dig
if nodes_dug_count > 0 then
local pluralized = "node"
if nodes_dug_count > 1 then
pluralized = "nodes"
end
minetest.log("action", nodes_dug_count .. " " .. pluralized .. " dug by "
.. digtron_id .. " near ".. minetest.pos_to_string(new_root_pos)
.. " operated by by " .. player_name)
end

digtron.build_to_world(digtron_id, new_root_pos, player_name)
minetest.sound_play("digtron_construction", {gain = 0.5, pos=new_root_pos})

-- 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
for _, dug_pos in ipairs(nodes_to_dig) do
-- TODO: other on-dug callbacks
minetest.check_for_falling(dug_pos)

-- Execute various on-dig callbacks for the nodes that Digtron dug
-- Must be called after digtron.build_to_world because it triggers falling nodes
for _, dug_data in ipairs(nodes_dug) do
local old_pos = dug_data.pos
local old_node = dug_data.node
local old_name = old_node.name

for _, callback in ipairs(minetest.registered_on_dignodes) do
-- Copy pos and node because callback can modify them
local pos_copy = {x=old_pos.x, y=old_pos.y, z=old_pos.z}
local oldnode_copy = {name=old_name, param1=old_node.param1, param2=old_node.param2}
callback(pos_copy, oldnode_copy, digtron.fake_player)
end

local old_def = minetest.registered_nodes[old_name]
if old_def ~= nil then
local old_after_dig = old_def.after_dig_node
if old_after_dig ~= nil then
old_after_dig(old_pos, old_node, dug_data.meta, digtron.fake_player)
end
end
end

commit_predictive_inventory(digtron_id)
else
clear_predictive_inventory(digtron_id)
digtron.show_buildable_nodes({}, failed)
minetest.sound_play("digtron_squeal", {gain = 0.5, pos=new_pos})
end
4 changes: 4 additions & 0 deletions init.lua
Original file line number Diff line number Diff line change
@@ -5,6 +5,10 @@ digtron.mod_meta = minetest.get_mod_storage()

local modpath = minetest.get_modpath(minetest.get_current_modname())


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.."/config.lua")
dofile(modpath.."/entities.lua")
dofile(modpath.."/functions.lua")
2 changes: 1 addition & 1 deletion inventories.lua
Original file line number Diff line number Diff line change
@@ -137,7 +137,7 @@ local clear_predictive_inventory = function(digtron_id)
minetest.remove_detached_inventory("digtron_predictive_"..digtron_id)
predictive_inventory[digtron_id] = nil

if not next(predictive_inventory) then
if next(predictive_inventory) ~= nil then
minetest.log("warning", "[Digtron] multiple predictive inventories were in existence, this shouldn't be happening. File an issue with Digtron programmers.")
end
end