Browse Source

Deduplicate player action logging, silence fake player actions (#2941)

nixnoxus 1 year ago
parent
commit
0c2ee1e41d

+ 30 - 0
game_api.txt

@@ -1115,3 +1115,33 @@ This function registers a shapeless recipe that takes `ingredient`
 and `result` as input and outputs `result`.
 
 The metadata of the input `result` is copied to the output `result`.
+
+
+Log API
+-------
+
+Logs action of the player with a node at a certain position.
+By default only actions of real players are logged.
+Actions of non-players (usually machines) are logged only when
+setting `log_non_player_actions` is enabled.
+A player is considered non-player if `player:is_player()` returns
+`false` or `player.is_fake_player` is truthy. The use of
+`is_fake_player` is an unofficial standard between mods.
+These non-players are marked by the content of `is_fake_player`
+(if it is a string) or a "*" in brackets after the player name in
+the log.
+
+`default.log_player_action(player, ...)`
+
+ * `player`        The player who performed the action
+ * `message_parts` Any mumber of message parts describing the action
+                   in 3rd person singular present tense. It can also
+                   contain a `pos` which is logged as "(X,Y,Z)"
+
+`default.set_inventory_action_loggers(def, name)`
+
+ * sets the callbacks `on_metadata_inventory_move`,
+   `on_metadata_inventory_put` and `on_metadata_inventory_take`
+   that log corresponding actions
+ * `def`     See [Node definition]
+ * `name`    Description of the node in the log message

+ 3 - 0
minetest.conf.example

@@ -75,3 +75,6 @@ default:torch 99,default:cobble 99
 # Enable cloud and shadow intensity variation by the 'weather' mod.
 # Non-functional in V6 or Singlenode mapgens.
 #enable_weather = true
+
+# If enabled, non-player actions are logged
+#log_non_player_actions = false

+ 1 - 15
mods/default/chests.lua

@@ -222,21 +222,7 @@ function default.chest.register_chest(prefixed_name, d)
 		end
 	end
 
-	def.on_metadata_inventory_move = function(pos, from_list, from_index,
-			to_list, to_index, count, player)
-		minetest.log("action", player:get_player_name() ..
-			" moves stuff in chest at " .. minetest.pos_to_string(pos))
-	end
-	def.on_metadata_inventory_put = function(pos, listname, index, stack, player)
-		minetest.log("action", player:get_player_name() ..
-			" moves " .. stack:get_name() ..
-			" to chest at " .. minetest.pos_to_string(pos))
-	end
-	def.on_metadata_inventory_take = function(pos, listname, index, stack, player)
-		minetest.log("action", player:get_player_name() ..
-			" takes " .. stack:get_name() ..
-			" from chest at " .. minetest.pos_to_string(pos))
-	end
+	default.set_inventory_action_loggers(def, "chest")
 
 	local def_opened = table.copy(def)
 	local def_closed = table.copy(def)

+ 41 - 0
mods/default/functions.lua

@@ -715,6 +715,47 @@ function default.register_craft_metadata_copy(ingredient, result)
 	end)
 end
 
+--
+-- Log API / helpers
+--
+
+local log_non_player_actions = minetest.settings:get_bool("log_non_player_actions", false)
+
+local is_pos = function(v)
+	return type(v) == "table" and
+		type(v.x) == "number" and type(v.y) == "number" and type(v.z) == "number"
+end
+
+function default.log_player_action(player, ...)
+	local msg = player:get_player_name()
+	if player.is_fake_player or not player:is_player() then
+		if not log_non_player_actions then
+			return
+		end
+		msg = msg .. "(" .. (type(player.is_fake_player) == "string"
+			and player.is_fake_player or "*") .. ")"
+	end
+	for _, v in ipairs({...}) do
+		-- translate pos
+		local part = is_pos(v) and minetest.pos_to_string(v) or v
+		-- no leading spaces before punctuation marks
+		msg = msg .. (string.match(part, "^[;,.]") and "" or " ") .. part
+	end
+	minetest.log("action",  msg)
+end
+
+function default.set_inventory_action_loggers(def, name)
+	def.on_metadata_inventory_move = function(pos, from_list, from_index,
+			to_list, to_index, count, player)
+		default.log_player_action(player, "moves stuff in", name, "at", pos)
+	end
+	def.on_metadata_inventory_put = function(pos, listname, index, stack, player)
+		default.log_player_action(player, "moves", stack:get_name(), "to", name, "at", pos)
+	end
+	def.on_metadata_inventory_take = function(pos, listname, index, stack, player)
+		default.log_player_action(player, "takes", stack:get_name(), "from", name, "at", pos)
+	end
+end
 
 --
 -- NOTICE: This method is not an official part of the API yet.

+ 9 - 23
mods/default/nodes.lua

@@ -2057,10 +2057,9 @@ local function coral_on_place(itemstack, placer, pointed_thing)
 
 	if minetest.is_protected(pos_under, player_name) or
 			minetest.is_protected(pos_above, player_name) then
-		minetest.log("action", player_name
-			.. " tried to place " .. itemstack:get_name()
-			.. " at protected position "
-			.. minetest.pos_to_string(pos_under))
+		default.log_player_action(placer,
+			"tried to place", itemstack:get_name(),
+			"at protected position", pos_under)
 		minetest.record_protection_violation(pos_under, player_name)
 		return itemstack
 	end
@@ -2525,7 +2524,7 @@ local function update_bookshelf(pos)
 	end
 end
 
-minetest.register_node("default:bookshelf", {
+local default_bookshelf_def = {
 	description = S("Bookshelf"),
 	tiles = {"default_wood.png", "default_wood.png", "default_wood.png",
 		"default_wood.png", "default_bookshelf.png", "default_bookshelf.png"},
@@ -2550,21 +2549,6 @@ minetest.register_node("default:bookshelf", {
 		end
 		return 0
 	end,
-	on_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
-		minetest.log("action", player:get_player_name() ..
-			" moves stuff in bookshelf at " .. minetest.pos_to_string(pos))
-		update_bookshelf(pos)
-	end,
-	on_metadata_inventory_put = function(pos, listname, index, stack, player)
-		minetest.log("action", player:get_player_name() ..
-			" puts stuff to bookshelf at " .. minetest.pos_to_string(pos))
-		update_bookshelf(pos)
-	end,
-	on_metadata_inventory_take = function(pos, listname, index, stack, player)
-		minetest.log("action", player:get_player_name() ..
-			" takes stuff from bookshelf at " .. minetest.pos_to_string(pos))
-		update_bookshelf(pos)
-	end,
 	on_blast = function(pos)
 		local drops = {}
 		default.get_inventory_drops(pos, "books", drops)
@@ -2572,7 +2556,9 @@ minetest.register_node("default:bookshelf", {
 		minetest.remove_node(pos)
 		return drops
 	end,
-})
+}
+default.set_inventory_action_loggers(default_bookshelf_def, "bookshelf")
+minetest.register_node("default:bookshelf", default_bookshelf_def)
 
 local function register_sign(material, desc, def)
 	minetest.register_node("default:sign_wall_" .. material, {
@@ -2615,8 +2601,8 @@ local function register_sign(material, desc, def)
 				minetest.chat_send_player(player_name, S("Text too long"))
 				return
 			end
-			minetest.log("action", player_name .. " wrote \"" .. text ..
-				"\" to the sign at " .. minetest.pos_to_string(pos))
+			default.log_player_action(sender, "wrote \"" .. text ..
+				"\" to the sign at", pos)
 			local meta = minetest.get_meta(pos)
 			meta:set_string("text", text)
 

+ 1 - 2
mods/default/trees.lua

@@ -572,8 +572,7 @@ function default.sapling_on_place(itemstack, placer, pointed_thing,
 		return itemstack
 	end
 
-	minetest.log("action", player_name .. " places node "
-			.. sapling_name .. " at " .. minetest.pos_to_string(pos))
+	default.log_player_action(placer, "places node", sapling_name, "at", pos)
 
 	local take_item = not minetest.is_creative_enabled(player_name)
 	local newnode = {name = sapling_name}

+ 1 - 2
mods/farming/api.lua

@@ -178,8 +178,7 @@ farming.place_seed = function(itemstack, placer, pointed_thing, plantname)
 	end
 
 	-- add the node and remove 1 item from the itemstack
-	minetest.log("action", player_name .. " places node " .. plantname .. " at " ..
-		minetest.pos_to_string(pt.above))
+	default.log_player_action(placer, "places node", plantname, "at", pt.above)
 	minetest.add_node(pt.above, {name = plantname, param2 = 1})
 	tick(pt.above)
 	if not minetest.is_creative_enabled(player_name) then

+ 2 - 6
mods/tnt/init.lua

@@ -465,9 +465,7 @@ minetest.register_node("tnt:gunpowder", {
 	on_punch = function(pos, node, puncher)
 		if puncher:get_wielded_item():get_name() == "default:torch" then
 			minetest.set_node(pos, {name = "tnt:gunpowder_burning"})
-			minetest.log("action", puncher:get_player_name() ..
-				" ignites tnt:gunpowder at " ..
-				minetest.pos_to_string(pos))
+			default.log_player_action(puncher, "ignites tnt:gunpowder at", pos)
 		end
 	end,
 	on_blast = function(pos, intensity)
@@ -635,9 +633,7 @@ function tnt.register_tnt(def)
 				if puncher:get_wielded_item():get_name() == "default:torch" then
 					minetest.swap_node(pos, {name = name .. "_burning"})
 					minetest.registered_nodes[name .. "_burning"].on_construct(pos)
-					minetest.log("action", puncher:get_player_name() ..
-						" ignites " .. node.name .. " at " ..
-						minetest.pos_to_string(pos))
+					default.log_player_action(puncher, "ignites", node.name, "at", pos)
 				end
 			end,
 			on_blast = function(pos, intensity)

+ 4 - 17
mods/vessels/init.lua

@@ -49,7 +49,7 @@ local function update_vessels_shelf(pos)
 	end
 end
 
-minetest.register_node("vessels:shelf", {
+local vessels_shelf_def = {
 	description = S("Vessels Shelf"),
 	tiles = {"default_wood.png", "default_wood.png", "default_wood.png",
 		"default_wood.png", "vessels_shelf.png", "vessels_shelf.png"},
@@ -74,21 +74,6 @@ minetest.register_node("vessels:shelf", {
 		end
 		return 0
 	end,
-	on_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
-		minetest.log("action", player:get_player_name() ..
-			   " moves stuff in vessels shelf at ".. minetest.pos_to_string(pos))
-		update_vessels_shelf(pos)
-	end,
-	on_metadata_inventory_put = function(pos, listname, index, stack, player)
-		minetest.log("action", player:get_player_name() ..
-			   " moves stuff to vessels shelf at ".. minetest.pos_to_string(pos))
-		update_vessels_shelf(pos)
-	end,
-	on_metadata_inventory_take = function(pos, listname, index, stack, player)
-		minetest.log("action", player:get_player_name() ..
-			   " takes stuff from vessels shelf at ".. minetest.pos_to_string(pos))
-		update_vessels_shelf(pos)
-	end,
 	on_blast = function(pos)
 		local drops = {}
 		default.get_inventory_drops(pos, "vessels", drops)
@@ -96,7 +81,9 @@ minetest.register_node("vessels:shelf", {
 		minetest.remove_node(pos)
 		return drops
 	end,
-})
+}
+default.set_inventory_action_loggers(vessels_shelf_def, "vessels shelf")
+minetest.register_node("vessels:shelf", vessels_shelf_def)
 
 minetest.register_craft({
 	output = "vessels:shelf",

+ 3 - 0
settingtypes.txt

@@ -75,3 +75,6 @@ river_source_sounds (River source node sounds) bool false
 #    Enable cloud and shadow intensity variation by the 'weather' mod.
 #    Non-functional in V6 or Singlenode mapgens.
 enable_weather (Enable weather) bool true
+
+#    If enabled, non-player actions are logged
+log_non_player_actions (Log non-player action) bool false