forked from your-land-mirror/yl_speak_up
		
	
		
			
				
	
	
		
			235 lines
		
	
	
		
			7.9 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			235 lines
		
	
	
		
			7.9 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
| -- handle logging
 | |
| 
 | |
| 
 | |
| -- log changes done by players or admins to NPCs
 | |
| yl_speak_up.log_change = function(pname, n_id, text, log_level)
 | |
| 	-- make sure all variables are defined
 | |
| 	if(not(pname)) then
 | |
| 		pname = "- unkown player -"
 | |
| 	end
 | |
| 	if(not(n_id)) then
 | |
| 		n_id = "- unknown NPC -"
 | |
| 	end
 | |
| 	if(not(text)) then
 | |
| 		text = "- no text given -"
 | |
| 	end
 | |
| 	if(not(log_level)) then
 | |
| 		log_level = "info"
 | |
| 	end
 | |
| 	-- we don't want newlines in the texts
 | |
| 	text = string.gsub(text, "\n", "\\n")
 | |
| 
 | |
| 	-- log in debug.txt
 | |
| 	local log_text = "<"..tostring(n_id).."> ["..tostring(pname).."]: "..text
 | |
| 	minetest.log(log_level, "[MOD] yl_speak_up "..log_text)
 | |
| 
 | |
| 	-- log in a file for each npc so that it can be shown when needed
 | |
| 	-- date needs to be inserted manually (minetest.log does it automaticly);
 | |
| 	-- each file logs just one npc, so n_id is not important
 | |
| 	log_text = tostring(os.date("%Y-%m-%d %H:%M:%S ")..tostring(pname).." "..text.."\n")
 | |
| 	n_id = tostring(n_id)
 | |
| 	if(n_id and n_id ~= "" and n_id ~= "n_" and n_id ~= "- unkown NPC -") then
 | |
| 		-- actually append to the logfile
 | |
| 		local file, err = io.open(yl_speak_up.worldpath..yl_speak_up.log_path..DIR_DELIM..
 | |
| 					"log_"..tostring(n_id)..".txt", "a")
 | |
| 		if err then
 | |
| 			minetest.log("error", "[MOD] yl_speak_up Error saving NPC logfile: "..minetest.serialize(err))
 | |
| 			return
 | |
| 		end
 | |
| 		file:write(log_text)
 | |
| 		file:close()
 | |
| 	end
 | |
| 
 | |
| 	-- log into a general all-npc-file as well
 | |
| 	local file, err = io.open(yl_speak_up.worldpath..yl_speak_up.log_path..DIR_DELIM..
 | |
| 					"log_ALL.txt", "a")
 | |
| 	if err then
 | |
| 		minetest.log("error","[MOD] yl_speak_up Error saving NPC logfile: "..minetest.serialize(err))
 | |
| 		return
 | |
| 	end
 | |
| 	file:write(tostring(n_id).." "..log_text)
 | |
| 	file:close()
 | |
| end
 | |
| 
 | |
| 
 | |
| -- this is used by yl_speak_up.eval_and_execute_function(..) in fs_edit_general.lua
 | |
| yl_speak_up.log_with_position = function(pname, n_id, text, log_level)
 | |
| 	if(not(pname) or not(yl_speak_up.speak_to[pname])) then
 | |
| 		yl_speak_up.log_change(pname, n_id,
 | |
| 			"error: -npc not found- "..tostring(text))
 | |
| 		return
 | |
| 	end
 | |
| 	local obj = yl_speak_up.speak_to[pname].obj
 | |
| 	local n_id = yl_speak_up.speak_to[pname].n_id
 | |
| 	local pos_str = "-unknown-"
 | |
| 	if obj:get_luaentity() and tonumber(npc) then
 | |
| 		pos_str = minetest.pos_to_string(obj:get_pos(),0)
 | |
| 	end
 | |
| 	yl_speak_up.log_change(pname, n_id,
 | |
| 		"NPC at position "..pos_str.." "..tostring(text), log_level)
 | |
| end
 | |
| 
 | |
| 
 | |
| yl_speak_up.input_show_log = function(player, formname, fields)
 | |
| 	local pname = player:get_player_name()
 | |
| 	local n_id = yl_speak_up.speak_to[pname].n_id
 | |
| 	if(not(yl_speak_up.may_edit_npc(player, n_id))) then
 | |
| 		return
 | |
| 	end
 | |
| 	if(fields.show_trade_log) then
 | |
| 		yl_speak_up.show_fs(player, "show_log", {log_type = "trade"})
 | |
| 	elseif(fields.show_full_log) then
 | |
| 		yl_speak_up.show_fs(player, "show_log", {log_type = "full"})
 | |
| 	elseif(fields.back_to_trade) then
 | |
| 		yl_speak_up.show_fs(player, "trade_list")
 | |
| 	elseif(fields.back_to_talk) then
 | |
| 		yl_speak_up.show_fs(player, "talk")
 | |
| 	end
 | |
| 	return
 | |
| end
 | |
| 
 | |
| 
 | |
| -- helper function for get_fs_show_log
 | |
| --   text: list of string
 | |
| yl_speak_up.show_log_add_line = function(text, last_day, last_who, last_line, same_lines, entry_type, log_type)
 | |
| 	local line = {}
 | |
| 	-- split the line up so that it can actually be read
 | |
| 	local multiline = minetest.wrap_text(last_line, 75, true)
 | |
| 	for i, p in ipairs(multiline) do
 | |
| 		if(i == 1) then
 | |
| 			table.insert(line, '#AAAAAA')
 | |
| 			table.insert(line, minetest.formspec_escape(last_day))
 | |
| 			table.insert(line, '#FFFF00')
 | |
| 			table.insert(line, minetest.formspec_escape(last_who))
 | |
| 			table.insert(line, '#AAAAAA')
 | |
| 			if(same_lines > 1) then
 | |
| 				table.insert(line, tostring(same_lines).."x")
 | |
| 			else
 | |
| 				table.insert(line, "")
 | |
| 			end
 | |
| 		else
 | |
| 			-- do not repeat all the other entries - we just continue text
 | |
| 			table.insert(line, '#AAAAAA,,#FFFF00,,#AAAAAA,')
 | |
| 		end
 | |
| 		if(entry_type and entry_type == "bought") then
 | |
| 			--table.insert(line, '#FF0000') -- red
 | |
| 			--table.insert(line, '#00FF00') -- green
 | |
| 			--table.insert(line, '#0000FF') -- blue
 | |
| 			--table.insert(line, '#FFFF00') -- yellow
 | |
| 			--table.insert(line, '#00FFFF') -- cyan
 | |
| 			--table.insert(line, '#FF00FF') -- magenta
 | |
| 			table.insert(line, '#00FF00') -- green
 | |
| 		elseif(entry_type and entry_type == "takes") then
 | |
| 			table.insert(line, '#FF6600') -- orange
 | |
| 		elseif(entry_type and entry_type == "adds") then
 | |
| 			table.insert(line, '#FFCC00') -- orange
 | |
| 		elseif(entry_type and (entry_type == "buy_if_less" or entry_type == "sell_if_more")) then
 | |
| 			table.insert(line, '#00FFFF') -- cyan
 | |
| 		elseif(entry_type and entry_type == "Trade:") then
 | |
| 			table.insert(line, '#00BBFF') -- darker cyan
 | |
| 		elseif(log_type and log_type == 'trade') then
 | |
| 			-- don't show this line if only trade lines are beeing asked for
 | |
| 			return
 | |
| 		elseif(entry_type and entry_type == "error:") then
 | |
| 			table.insert(line, '#FF4444') -- bright red
 | |
| 		else
 | |
| 			table.insert(line, '#FFFFFF')
 | |
| 		end
 | |
| 		table.insert(line, minetest.formspec_escape(p))
 | |
| 	end
 | |
| 	table.insert(text, table.concat(line, ','))
 | |
| end
 | |
| 
 | |
| 
 | |
| -- allow to toggle between trade entries and full log
 | |
| yl_speak_up.get_fs_show_log = function(player, log_type)
 | |
| 	local pname = player:get_player_name()
 | |
| 	local n_id = yl_speak_up.speak_to[pname].n_id
 | |
| 	local dialog = yl_speak_up.speak_to[pname].dialog
 | |
| 	if(not(yl_speak_up.may_edit_npc(player, n_id))) then
 | |
| 		return "size[5,1]label[0,0;Error: You do not own this NPC.]"
 | |
| 	end
 | |
| 
 | |
| 	local log_type_desc = "Full"
 | |
| 	local log_type_switch = "show_trade_log;Show trade log"
 | |
| 	local back_link = "back_to_talk;Back to talk"
 | |
| 	if(log_type == "trade") then
 | |
| 		log_type_desc = "Trade"
 | |
| 		log_type_switch = "show_full_log;Show full log"
 | |
| 		back_link = "back_to_trade;Back to trade"
 | |
| 	end
 | |
| 	local file, err = io.open(yl_speak_up.worldpath..yl_speak_up.log_path..DIR_DELIM..
 | |
| 					"log_"..tostring(n_id)..".txt", "r")
 | |
| 	local formspec = {'size[18,12]'..
 | |
| 			'button[0.5,11.1;17,0.8;',
 | |
| 				back_link,
 | |
| 				']'..
 | |
| 			'label[4.5,0.5;'..log_type_desc..' Log of ',
 | |
| 				minetest.formspec_escape(tostring(dialog.n_npc)..
 | |
| 							" [ID: "..tostring(n_id).."]"),
 | |
| 				']',
 | |
| 			'button[0.5,0.1;3,0.8;',
 | |
| 				log_type_switch,
 | |
| 				']',
 | |
| 			'tablecolumns[' ..
 | |
| 				'color;text,align=left;'..	-- the date
 | |
| 				'color;text,align=center;'..	-- name of the player
 | |
| 				'color;text,align=right;'..	-- how many times the entry was repeated
 | |
| 				'color;text,align=left]'..	-- actual log file entry
 | |
| 			'table[0.1,1.0;17.8,9.8;show_log_of_npc;'..
 | |
| 				'#FFFFFF,Date,#FFFFFF,Player,#FFFFFF,,#FFFFFF,',
 | |
| 			}
 | |
| 	-- without the time information, some entries (in particular when someone buys from a shpo)
 | |
| 	-- may be the same. Those entries are combined into one when viewing the log.
 | |
| 	local text = {}
 | |
| 	local last_line = ""
 | |
| 	local last_day = ""
 | |
| 	local last_who = ""
 | |
| 	local same_lines = 0
 | |
| 	local count = 0
 | |
| 	if(err) then
 | |
| 		-- we don't want to get too much into detail here for players
 | |
| 		return "size[5,1]label[0,0;Error reading NPC logfile.]"
 | |
| 	else
 | |
| 		local last_entry_type = ""
 | |
| 		for line in file:lines() do
 | |
| 			local parts = string.split(line, " ")
 | |
| 			-- suppress the time information as that would be too detailled;
 | |
| 			-- it is still logged so that admins can check
 | |
| 			local this_line = table.concat(parts, " ", 4)
 | |
| 			if(this_line == last_line and parts[1] == last_day
 | |
| 			  and #parts > 3 and parts[3] == last_who) then
 | |
| 				-- just count the line
 | |
| 				same_lines = same_lines + 1
 | |
| 			else
 | |
| 				yl_speak_up.show_log_add_line(text, last_day, last_who, last_line, same_lines,
 | |
| 					last_entry_type, log_type)
 | |
| 				-- store information about the next line
 | |
| 				same_lines = 0
 | |
| 				last_line = this_line
 | |
| 				last_day = parts[1]
 | |
| 				last_who = parts[3]
 | |
| 				last_entry_type = parts[4]
 | |
| 			end
 | |
| 			count = count + 1
 | |
| 		end
 | |
| 		-- cover the last line
 | |
| 		yl_speak_up.show_log_add_line(text, last_day, last_who, last_line, same_lines, last_entry_type, log_type)
 | |
| 		file:close()
 | |
| 
 | |
| 		-- reverse the order so that new entries are on top (newer entries are more intresting)
 | |
| 		local reverse_text = {}
 | |
| 		for part = #text, 1, -1 do
 | |
| 			table.insert(reverse_text, text[part])
 | |
| 		end
 | |
| 		table.insert(formspec, minetest.formspec_escape('Log entry, newest first, '..
 | |
| 					tostring(#text)..' entries:')..",")
 | |
| 		table.insert(formspec, table.concat(reverse_text, ','))
 | |
| 	end
 | |
| 
 | |
| 	-- selected row
 | |
| 	table.insert(formspec, ";1]")
 | |
| 	return table.concat(formspec, '')
 | |
| end
 | |
| 
 |