From 814ad39c0950fdc4a14d2169cf054ad90c263490 Mon Sep 17 00:00:00 2001 From: ancientmarinerdev Date: Mon, 7 Nov 2022 23:25:41 +0000 Subject: [PATCH 1/6] Villagers can now claim any type of bed. --- mods/ENTITIES/mobs_mc/villager.lua | 102 ++++++++++++++++++++++++----- 1 file changed, 87 insertions(+), 15 deletions(-) diff --git a/mods/ENTITIES/mobs_mc/villager.lua b/mods/ENTITIES/mobs_mc/villager.lua index 503a56be4..7afa1052c 100644 --- a/mods/ENTITIES/mobs_mc/villager.lua +++ b/mods/ENTITIES/mobs_mc/villager.lua @@ -648,6 +648,71 @@ function get_activity(tod) end +local function find_closest_bed (self) + local p = self.object:get_pos() + + --local nn = minetest.find_nodes_in_area(vector.offset(p,-48,-48,-48),vector.offset(p,48,48,48), spawnable_bed) + --if nn then + -- mcl_log("Red beds: " .. #nn) + --end + + local unclaimed_beds = {} + local nn2 = minetest.find_nodes_in_area(vector.offset(p,-48,-48,-48),vector.offset(p,48,48,48), {"group:bed"}) + if nn2 then + mcl_log("All bed parts: " .. #nn2) + + for a,b in pairs(nn2) do + mcl_log("b: " .. minetest.pos_to_string(b)) + + local bed_node = minetest.get_node(b) + local bed_meta = minetest.get_meta(b) + + local bed_name = bed_node.name + --mcl_log("bed_node name: " .. bed_name) + + local is_bed_bottom = string.find(bed_name,"_bottom") + local owned_by = bed_meta:get_string("villager") + + if owned_by and owned_by == self._id then + mcl_log("Weird. I own this, but don't know it.") + bed_meta:set_string("villager", nil) + end + + if is_bed_bottom and owned_by == "" then + table.insert(unclaimed_beds, b) + mcl_log("is an unowned bed bottom") + else + mcl_log("Not bottom or is claimed, remove. Owned: ".. owned_by) + end + end + end + + local distance_to_closest_block = nil + local closest_block = nil + + if unclaimed_beds then + mcl_log("All unclaimed bed bottoms: " .. #unclaimed_beds) + + for i,b in pairs(unclaimed_beds) do + mcl_log("b: " .. minetest.pos_to_string(b)) + local distance_to_block = vector.distance(p, b) + mcl_log("Distance to block ".. i .. ": ".. distance_to_block) + + if not distance_to_closest_block or distance_to_closest_block > distance_to_block then + mcl_log("This block is closer than the last.") + closest_block = b + distance_to_closest_block = distance_to_block + end + + local bed_node = minetest.get_node(b) + local bed_name = bed_node.name + mcl_log("bed_node name: " .. bed_name) + end + end + + return closest_block +end + local function find_closest_unclaimed_block (p, requested_block_types) local nn = minetest.find_nodes_in_area(vector.offset(p,-48,-48,-48),vector.offset(p,48,48,48), requested_block_types) @@ -681,7 +746,10 @@ local function check_bed (entity) end local n = minetest.get_node(b) - if n and n.name ~= "mcl_beds:bed_red_bottom" then + + local is_bed_bottom = string.find(n.name,"_bottom") + mcl_log("" .. tostring(is_bed_bottom)) + if n and not is_bed_bottom then mcl_log("Where did my bed go?!") entity._bed = nil --the stormtroopers have killed uncle owen return false @@ -749,28 +817,32 @@ local function take_bed (entity) local p = entity.object:get_pos() - local closest_block = find_closest_unclaimed_block (p, spawnable_bed) + --local closest_block = find_closest_unclaimed_block (p, spawnable_bed) + local closest_block = find_closest_bed (entity) if closest_block then - local m = minetest.get_meta(closest_block) mcl_log("Can we path to bed: "..minetest.pos_to_string(closest_block) ) - local gp = mcl_mobs:gopath(entity, closest_block,function(self) - if self then - self.order = SLEEP + local distance_to_block = vector.distance(p, closest_block) + mcl_log("Distance: " .. distance_to_block) + if distance_to_block < 2 then + if entity.order ~= SLEEP then mcl_log("Sleepy time" ) + entity.order = SLEEP + local m = minetest.get_meta(closest_block) + m:set_string("villager", entity._id) + entity._bed = closest_block else - mcl_log("Can't sleep, no self in the callback" ) + mcl_log("Set as sleep already..." ) end - end) - if gp then - mcl_log("Nice bed. I'll defintely take it as I can path") - m:set_string("villager", entity._id) - entity._bed = closest_block else - mcl_log("Awww. I can't find my bed.") + local gp = mcl_mobs:gopath(entity, closest_block,function(self) end) + if gp then + mcl_log("Nice bed. I'll defintely take it as I can path") + else + mcl_log("Awww. I can't find my bed.") + end end end - end local function has_golem(pos) @@ -1879,7 +1951,7 @@ mcl_mobs:register_mob("mobs_mc:villager", { end end if has_player then - minetest.log("verbose", "[mobs_mc] Player near villager found!") + --minetest.log("verbose", "[mobs_mc] Player near villager found!") stand_still(self) else --minetest.log("verbose", "[mobs_mc] No player near villager found!") From ff0fea8978cd7974fae9313e6ca6fc7a97ed6f77 Mon Sep 17 00:00:00 2001 From: ancientmarinerdev Date: Tue, 8 Nov 2022 22:27:10 +0000 Subject: [PATCH 2/6] Add default logger to make logging easier --- mods/CORE/mcl_util/init.lua | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/mods/CORE/mcl_util/init.lua b/mods/CORE/mcl_util/init.lua index 556b12855..83cc79d22 100644 --- a/mods/CORE/mcl_util/init.lua +++ b/mods/CORE/mcl_util/init.lua @@ -22,6 +22,19 @@ function table.update_nil(t, ...) return t end +local LOGGING_ON = minetest.settings:get_bool("mcl_logging_default",false) +local LOG_MODULE = "[MCL2]" +function mcl_util.mcl_log (message, module) + local selected_module = LOG_MODULE + if module then + selected_module = module + end + if LOGGING_ON and message then + minetest.log(selected_module .. " " .. message) + end +end + + function mcl_util.file_exists(name) if type(name) ~= "string" then return end local f = io.open(name) From e5c639c77946f746fd769ed2b274b91843fba306 Mon Sep 17 00:00:00 2001 From: ancientmarinerdev Date: Tue, 8 Nov 2022 22:54:16 +0000 Subject: [PATCH 3/6] Logging improvements --- mods/CORE/mcl_util/init.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mods/CORE/mcl_util/init.lua b/mods/CORE/mcl_util/init.lua index 83cc79d22..4684234e5 100644 --- a/mods/CORE/mcl_util/init.lua +++ b/mods/CORE/mcl_util/init.lua @@ -24,12 +24,12 @@ end local LOGGING_ON = minetest.settings:get_bool("mcl_logging_default",false) local LOG_MODULE = "[MCL2]" -function mcl_util.mcl_log (message, module) +function mcl_util.mcl_log (message, module, bypass_default_logger) local selected_module = LOG_MODULE if module then selected_module = module end - if LOGGING_ON and message then + if (bypass_default_logger or LOGGING_ON) and message then minetest.log(selected_module .. " " .. message) end end From 3e1a47544255303feeeede25cd796cca7e2457bb Mon Sep 17 00:00:00 2001 From: ancientmarinerdev Date: Tue, 8 Nov 2022 22:55:34 +0000 Subject: [PATCH 4/6] Logging improvements --- mods/ENTITIES/mcl_mobs/api.lua | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/mods/ENTITIES/mcl_mobs/api.lua b/mods/ENTITIES/mcl_mobs/api.lua index a21e16806..b306b0fd7 100644 --- a/mods/ENTITIES/mcl_mobs/api.lua +++ b/mods/ENTITIES/mcl_mobs/api.lua @@ -21,11 +21,9 @@ local S = minetest.get_translator("mcl_mobs") local mob_active_range = tonumber(minetest.settings:get("mcl_mob_active_range")) or 48 local LOGGING_ON = minetest.settings:get_bool("mcl_logging_mobs_villager",false) - -local LOG_MODULE = "[Mobs]" local function mcl_log (message) - if LOGGING_ON and message then - minetest.log(LOG_MODULE .. " " .. message) + if LOGGING_ON then + mcl_util.mcl_log (message, "[Mobs]", true) end end From 3000a378f354d7ed3c966452cb312bfa8427eb88 Mon Sep 17 00:00:00 2001 From: ancientmarinerdev Date: Tue, 8 Nov 2022 22:58:47 +0000 Subject: [PATCH 5/6] Villagers can claim any bed. Player can steal villager bed. Villager won't take player bed --- mods/ENTITIES/mobs_mc/villager.lua | 96 +++++++++++++++++++++++------- mods/ITEMS/mcl_beds/functions.lua | 39 +++++++++++- mods/PLAYER/mcl_spawn/init.lua | 39 ++++++++++++ 3 files changed, 150 insertions(+), 24 deletions(-) diff --git a/mods/ENTITIES/mobs_mc/villager.lua b/mods/ENTITIES/mobs_mc/villager.lua index 7afa1052c..53d249128 100644 --- a/mods/ENTITIES/mobs_mc/villager.lua +++ b/mods/ENTITIES/mobs_mc/villager.lua @@ -45,10 +45,9 @@ local PATHFINDING = "gowp" -- will be much easier. local LOGGING_ON = minetest.settings:get_bool("mcl_logging_mobs_villager",false) -local LOG_MODULE = "[Mobs - Villager]" local function mcl_log (message) - if LOGGING_ON and message then - minetest.log(LOG_MODULE .. " " .. message) + if LOGGING_ON then + mcl_util.mcl_log (message, "[Mobs - Villager]", true) end end @@ -578,9 +577,6 @@ end jobsites = populate_jobsites() -local spawnable_bed={} -table.insert(spawnable_bed, "mcl_beds:bed_red_bottom") - local function stand_still(self) self.walk_chance = 0 self.jump = false @@ -651,6 +647,8 @@ end local function find_closest_bed (self) local p = self.object:get_pos() + --local spawnable_bed={} + --table.insert(spawnable_bed, "mcl_beds:bed_red_bottom") --local nn = minetest.find_nodes_in_area(vector.offset(p,-48,-48,-48),vector.offset(p,48,48,48), spawnable_bed) --if nn then -- mcl_log("Red beds: " .. #nn) @@ -659,30 +657,52 @@ local function find_closest_bed (self) local unclaimed_beds = {} local nn2 = minetest.find_nodes_in_area(vector.offset(p,-48,-48,-48),vector.offset(p,48,48,48), {"group:bed"}) if nn2 then - mcl_log("All bed parts: " .. #nn2) + --mcl_log("All bed parts: " .. #nn2) for a,b in pairs(nn2) do mcl_log("b: " .. minetest.pos_to_string(b)) local bed_node = minetest.get_node(b) - local bed_meta = minetest.get_meta(b) - local bed_name = bed_node.name - --mcl_log("bed_node name: " .. bed_name) - local is_bed_bottom = string.find(bed_name,"_bottom") - local owned_by = bed_meta:get_string("villager") - if owned_by and owned_by == self._id then - mcl_log("Weird. I own this, but don't know it.") + local bed_meta = minetest.get_meta(b) + local owned_by = bed_meta:get_string("villager") + --mcl_log("Owned by villager: ".. tostring(owned_by)) + + if (owned_by and owned_by == self._id) then + mcl_log("Clear as already owned by me.") bed_meta:set_string("villager", nil) + owned_by = nil end - if is_bed_bottom and owned_by == "" then - table.insert(unclaimed_beds, b) - mcl_log("is an unowned bed bottom") + if is_bed_bottom then + local bed_top = mcl_beds.get_bed_top (b) + mcl_log("bed_top: " .. tostring(bed_top)) + + local bed_top_node = minetest.get_node(bed_top) + if bed_top_node then + mcl_log("There is a block here for bed top: ".. bed_top_node.name) + else + mcl_log("There is no block here for bed top") + end + + local bed_top_meta = minetest.get_meta(bed_top) + local owned_by_player = bed_top_meta:get_string("player") + if bed_top_meta then + mcl_log("Player: " .. tostring(owned_by_player)) + else + mcl_log("No bed top meta") + end + + if owned_by == "" and (not owned_by_player or owned_by_player == "") then + table.insert(unclaimed_beds, b) + mcl_log("is an unowned bed bottom") + else + + end else - mcl_log("Not bottom or is claimed, remove. Owned: ".. owned_by) + --mcl_log("bed_node name: " .. bed_name) end end end @@ -817,7 +837,6 @@ local function take_bed (entity) local p = entity.object:get_pos() - --local closest_block = find_closest_unclaimed_block (p, spawnable_bed) local closest_block = find_closest_bed (entity) if closest_block then @@ -1177,11 +1196,46 @@ local function go_to_town_bell(self) return nil end +local function validate_bed(self) + if not self or not self._bed then + return false + end + local n = mcl_vars.get_node(self._bed) + if not n then + self._bed = nil + return false + end + + local bed_valid = true + + local m = minetest.get_meta(self._bed) + local owned_by_player = m:get_string("player") + mcl_log("Player owner: " .. owned_by_player) + if owned_by_player ~= "" then + mcl_log("Player owns this. Villager won't take this.") + m:set_string("villager", nil) + self._bed = nil + bed_valid = false + return + end + + if m:get_string("villager") ~= self._id then + mcl_log("This bed is owned by another player. I'll unclaim.") + self._bed = nil + return false + else + mcl_log("Bed is valid") + return true + end + +end + local function do_activity (self) -- Maybe just check we're pathfinding first? - if not self._bed and self.state ~= PATHFINDING then - --mcl_log("Villager has no bed. Currently at location: "..minetest.pos_to_string(self.object:get_pos())) + if not validate_bed(self) and self.state ~= PATHFINDING then + if self.order == SLEEP then self.order = nil end + mcl_log("Villager has no bed. Currently at location: "..minetest.pos_to_string(self.object:get_pos())) take_bed (self) end diff --git a/mods/ITEMS/mcl_beds/functions.lua b/mods/ITEMS/mcl_beds/functions.lua index c745b5f0c..056da71dc 100644 --- a/mods/ITEMS/mcl_beds/functions.lua +++ b/mods/ITEMS/mcl_beds/functions.lua @@ -10,6 +10,10 @@ local explosions_mod = minetest.get_modpath("mcl_explosions") local spawn_mod = minetest.get_modpath("mcl_spawn") local worlds_mod = minetest.get_modpath("mcl_worlds") +local function mcl_log (message) + mcl_util.mcl_log (message, "[Beds]") +end + -- Helper functions local function get_look_yaw(pos) @@ -300,6 +304,37 @@ function mcl_beds.skip_night() minetest.set_timeofday(0.25) -- tod = 6000 end +function mcl_beds.get_bed_top (pos) + local node = minetest.get_node(pos) + local dir = minetest.facedir_to_dir(node.param2) + local bed_top_pos = vector.add(pos, dir) + local bed_top = minetest.get_node(bed_top_pos) + + if bed_top then + mcl_log("Has a bed top") + else + mcl_log("No bed top") + end + return bed_top_pos +end + +function mcl_beds.get_bed_bottom (pos) + local node = minetest.get_node(pos) + local dir = minetest.facedir_to_dir(node.param2) + mcl_log("Dir: " .. tostring(dir)) + local bed_bottom = vector.add(pos, -dir) + mcl_log("bed_bottom: " .. tostring(bed_bottom)) + + local bed_bottom_node = minetest.get_node(bed_bottom) + if bed_bottom_node then + mcl_log("Bed bottom node name:" .. bed_bottom_node.name) + else + mcl_log("Didn't get bed bottom") + end + + return bed_bottom +end + function mcl_beds.on_rightclick(pos, player, is_top) -- Anti-Inception: Don't allow to sleep while you're sleeping if player:get_meta():get_string("mcl_beds:sleeping") == "true" then @@ -329,9 +364,7 @@ function mcl_beds.on_rightclick(pos, player, is_top) if is_top then message = select(2, lay_down(player, ppos, pos)) else - local node = minetest.get_node(pos) - local dir = minetest.facedir_to_dir(node.param2) - local other = vector.add(pos, dir) + local other = mcl_beds.get_bed_top (pos) message = select(2, lay_down(player, ppos, other)) end if message then diff --git a/mods/PLAYER/mcl_spawn/init.lua b/mods/PLAYER/mcl_spawn/init.lua index 9022dfc25..c8746fdf0 100644 --- a/mods/PLAYER/mcl_spawn/init.lua +++ b/mods/PLAYER/mcl_spawn/init.lua @@ -4,6 +4,10 @@ local S = minetest.get_translator(minetest.get_current_modname()) local mg_name = minetest.get_mapgen_setting("mg_name") local storage = minetest.get_mod_storage() +local function mcl_log (message) + mcl_util.mcl_log (message, "[Spawn]") +end + -- Parameters ------------- @@ -429,6 +433,41 @@ function mcl_spawn.set_spawn_pos(player, pos, message) else local oldpos = minetest.string_to_pos(meta:get_string("mcl_beds:spawn")) meta:set_string("mcl_beds:spawn", minetest.pos_to_string(pos)) + + -- Set player ownership on bed + local bed_node = minetest.get_node(pos) + local bed_meta = minetest.get_meta(pos) + + local bed_bottom = mcl_beds.get_bed_bottom (pos) + local bed_bottom_meta = minetest.get_meta(bed_bottom) + + if bed_meta then + if bed_node then + mcl_log("Bed name: " .. bed_node.name) + end + + mcl_log("Setting bed meta: " .. player:get_player_name()) + bed_meta:set_string("player", player:get_player_name()) + + -- Pass in villager as arg. Shouldn't know about villagers + if bed_bottom_meta then + mcl_log("Removing villager from bed bottom meta") + bed_bottom_meta:set_string("villager", nil) + else + mcl_log("Cannot remove villager from bed bottom meta") + end + + + + local old_bed_meta = minetest.get_meta(oldpos) + if oldpos ~= pos and old_bed_meta then + mcl_log("Removing old bed meta") + old_bed_meta:set_string("player", "") + else + mcl_log("No old bed meta to remove or same as current") + end + end + if oldpos then -- We don't bother sending a message if the new spawn pos is basically the same spawn_changed = vector.distance(pos, oldpos) > 0.1 From 59808c51902d0c232d460ced3b63055e26f7cd96 Mon Sep 17 00:00:00 2001 From: ancientmarinerdev Date: Tue, 8 Nov 2022 23:42:44 +0000 Subject: [PATCH 6/6] Fix race condition where many villagers are fighting for same job --- mods/ENTITIES/mobs_mc/villager.lua | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/mods/ENTITIES/mobs_mc/villager.lua b/mods/ENTITIES/mobs_mc/villager.lua index 53d249128..7b7eafda5 100644 --- a/mods/ENTITIES/mobs_mc/villager.lua +++ b/mods/ENTITIES/mobs_mc/villager.lua @@ -843,14 +843,24 @@ local function take_bed (entity) mcl_log("Can we path to bed: "..minetest.pos_to_string(closest_block) ) local distance_to_block = vector.distance(p, closest_block) mcl_log("Distance: " .. distance_to_block) + if distance_to_block < 2 then + local m = minetest.get_meta(closest_block) + local owner = m:get_string("villager") + mcl_log("owner: ".. owner) + if owner and owner ~= "" and owner ~= entity._id then + mcl_log("Already taken") + if entity.order == "stand" then entity.order = nil end + return + end + if entity.order ~= SLEEP then mcl_log("Sleepy time" ) entity.order = SLEEP - local m = minetest.get_meta(closest_block) m:set_string("villager", entity._id) entity._bed = closest_block else + --entity.order = nil mcl_log("Set as sleep already..." ) end else @@ -861,6 +871,9 @@ local function take_bed (entity) mcl_log("Awww. I can't find my bed.") end end + else + mcl_log("Cannot find a bed to claim.") + if entity.order == "stand" then entity.order = nil end end end