re-enable order logging using custom lua serialization code
This commit is contained in:
parent
101dc3b796
commit
e0d373dd5d
@ -255,17 +255,16 @@ local get_info_formspec = function(market, account)
|
||||
"size[10,10]",
|
||||
"tabheader[0,0;tabs;"..market.def.description..",Your Inventory,Market Orders;1;false;true]",
|
||||
"textarea[0.5,0.5;9.5,1.5;;Description:;"..market.def.long_description.."]",
|
||||
-- TODO: logging temporarily disabled, it was causing minetest.serialize to generate invalid output for some reason
|
||||
--"textarea[0.5,2.5;9.5,6;;Your Recent Purchases and Sales:;",
|
||||
"textarea[0.5,2.5;9.5,6;;Your Recent Purchases and Sales:;",
|
||||
}
|
||||
-- if next(account.log) then
|
||||
-- for _, log_entry in ipairs(account.log) do
|
||||
-- formspec[#formspec+1] = log_to_string(market, log_entry) .. "\n"
|
||||
-- end
|
||||
-- else
|
||||
-- formspec[#formspec+1] = "No logged activites in this market yet"
|
||||
-- end
|
||||
-- formspec[#formspec+1] = "]"
|
||||
if next(account.log) then
|
||||
for _, log_entry in ipairs(account.log) do
|
||||
formspec[#formspec+1] = log_to_string(market, log_entry) .. "\n"
|
||||
end
|
||||
else
|
||||
formspec[#formspec+1] = "No logged activites in this market yet"
|
||||
end
|
||||
formspec[#formspec+1] = "]"
|
||||
|
||||
return table.concat(formspec)
|
||||
end
|
||||
|
56
market.lua
56
market.lua
@ -77,21 +77,23 @@ local get_account = function(market, player_name)
|
||||
return account
|
||||
end
|
||||
|
||||
-- Caution: the data structures produced by sale logging caused me to discover
|
||||
-- issue https://github.com/minetest/minetest/issues/8719 with minetest.serialize()
|
||||
-- I'm working around it by using the code in persistence.lua instead
|
||||
local log_sale = function(item, quantity, price, purchaser, seller)
|
||||
-- TODO: disabled temporarily, the log code should work in theory but in practice minetest.serialize was generating invalid output for some reason.
|
||||
-- local log_entry = {item=item, quantity=quantity, price=price, purchaser=purchaser, seller=seller, timestamp = minetest.get_gametime()}
|
||||
-- local purchaser_log = purchaser.log
|
||||
-- local seller_log = seller.log
|
||||
-- table.insert(purchaser_log, log_entry)
|
||||
-- if #purchaser_log > log_length_limit then
|
||||
-- table.remove(purchaser_log, 1)
|
||||
-- end
|
||||
-- if (purchaser ~= seller) then
|
||||
-- table.insert(seller_log, log_entry)
|
||||
-- if #seller_log > log_length_limit then
|
||||
-- table.remove(seller_log, 1)
|
||||
-- end
|
||||
-- end
|
||||
local log_entry = {item=item, quantity=quantity, price=price, purchaser=purchaser, seller=seller, timestamp = minetest.get_gametime()}
|
||||
local purchaser_log = purchaser.log
|
||||
local seller_log = seller.log
|
||||
table.insert(purchaser_log, log_entry)
|
||||
if #purchaser_log > log_length_limit then
|
||||
table.remove(purchaser_log, 1)
|
||||
end
|
||||
if (purchaser ~= seller) then
|
||||
table.insert(seller_log, log_entry)
|
||||
if #seller_log > log_length_limit then
|
||||
table.remove(seller_log, 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local remove_orders_by_account = function(orders, account)
|
||||
@ -379,29 +381,23 @@ local buy = function(self, player_name, item, quantity, price)
|
||||
return add_buy(self, get_account(self, player_name), item, price, quantity)
|
||||
end
|
||||
|
||||
-- Using this instead of minetest.serialize because of https://github.com/minetest/minetest/issues/8719
|
||||
local MP = minetest.get_modpath(minetest.get_current_modname())
|
||||
local persistence_store, persistence_load = dofile(MP.."/persistence.lua")
|
||||
|
||||
local load_market_data = function(marketname)
|
||||
local path = minetest.get_worldpath()
|
||||
local filename = path .. "\\market_"..marketname..".lua"
|
||||
local file = loadfile(filename) -- returns nil if the file doesn't exist
|
||||
if file then
|
||||
return file()
|
||||
else
|
||||
return nil
|
||||
end
|
||||
return persistence_load(filename)
|
||||
end
|
||||
|
||||
local save_market_data = function(market)
|
||||
local path = minetest.get_worldpath()
|
||||
local filename = path .. "\\market_"..market.name..".lua"
|
||||
local file, err = io.open(filename, "w")
|
||||
if err ~= nil then
|
||||
minetest.log("error", "[commoditymarket] Could not save market to \"" .. filename .. "\"")
|
||||
return false
|
||||
end
|
||||
local data = {}
|
||||
data.player_accounts = market.player_accounts
|
||||
data.orders_for_items = market.orders_for_items
|
||||
file:write(minetest.serialize(data))
|
||||
persistence_store(filename, data)
|
||||
return true
|
||||
end
|
||||
|
||||
@ -483,8 +479,14 @@ commoditymarket.register_market = function(market_name, market_def)
|
||||
return 0
|
||||
end,
|
||||
allow_put = function(inv, listname, index, stack, player)
|
||||
-- Currency items are always allowed
|
||||
local item = stack:get_name()
|
||||
|
||||
-- reject unknown items
|
||||
if minetest.registered_items[item] == nil then
|
||||
return 0
|
||||
end
|
||||
|
||||
-- Currency items are always allowed
|
||||
if new_market.def.currency[item] then
|
||||
return stack:get_count()
|
||||
end
|
||||
|
200
persistence.lua
Normal file
200
persistence.lua
Normal file
@ -0,0 +1,200 @@
|
||||
-- Internal persistence library
|
||||
|
||||
--[[ Provides ]]
|
||||
-- persistence.store(path, ...): Stores arbitrary items to the file at the given path
|
||||
-- persistence.load(path): Loads files that were previously stored with store and returns them
|
||||
|
||||
--[[ Limitations ]]
|
||||
-- Does not export userdata, threads or most function values
|
||||
-- Function export is not portable
|
||||
|
||||
--[[ License: MIT (see bottom) ]]
|
||||
|
||||
-- Private methods
|
||||
local write, writeIndent, writers, refCount;
|
||||
|
||||
-- write thing (dispatcher)
|
||||
write = function (file, item, level, objRefNames)
|
||||
writers[type(item)](file, item, level, objRefNames);
|
||||
end;
|
||||
|
||||
-- write indent
|
||||
writeIndent = function (file, level)
|
||||
for i = 1, level do
|
||||
file:write("\t");
|
||||
end;
|
||||
end;
|
||||
|
||||
-- recursively count references
|
||||
refCount = function (objRefCount, item)
|
||||
-- only count reference types (tables)
|
||||
if type(item) == "table" then
|
||||
-- Increase ref count
|
||||
if objRefCount[item] then
|
||||
objRefCount[item] = objRefCount[item] + 1;
|
||||
else
|
||||
objRefCount[item] = 1;
|
||||
-- If first encounter, traverse
|
||||
for k, v in pairs(item) do
|
||||
refCount(objRefCount, k);
|
||||
refCount(objRefCount, v);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
-- Format items for the purpose of restoring
|
||||
writers = {
|
||||
["nil"] = function (file, item)
|
||||
file:write("nil");
|
||||
end;
|
||||
["number"] = function (file, item)
|
||||
file:write(tostring(item));
|
||||
end;
|
||||
["string"] = function (file, item)
|
||||
file:write(string.format("%q", item));
|
||||
end;
|
||||
["boolean"] = function (file, item)
|
||||
if item then
|
||||
file:write("true");
|
||||
else
|
||||
file:write("false");
|
||||
end
|
||||
end;
|
||||
["table"] = function (file, item, level, objRefNames)
|
||||
local refIdx = objRefNames[item];
|
||||
if refIdx then
|
||||
-- Table with multiple references
|
||||
file:write("multiRefObjects["..refIdx.."]");
|
||||
else
|
||||
-- Single use table
|
||||
file:write("{\n");
|
||||
for k, v in pairs(item) do
|
||||
writeIndent(file, level+1);
|
||||
file:write("[");
|
||||
write(file, k, level+1, objRefNames);
|
||||
file:write("] = ");
|
||||
write(file, v, level+1, objRefNames);
|
||||
file:write(";\n");
|
||||
end
|
||||
writeIndent(file, level);
|
||||
file:write("}");
|
||||
end;
|
||||
end;
|
||||
["function"] = function (file, item)
|
||||
-- Does only work for "normal" functions, not those
|
||||
-- with upvalues or c functions
|
||||
local dInfo = debug.getinfo(item, "uS");
|
||||
if dInfo.nups > 0 then
|
||||
file:write("nil --[[functions with upvalue not supported]]");
|
||||
elseif dInfo.what ~= "Lua" then
|
||||
file:write("nil --[[non-lua function not supported]]");
|
||||
else
|
||||
local r, s = pcall(string.dump,item);
|
||||
if r then
|
||||
file:write(string.format("loadstring(%q)", s));
|
||||
else
|
||||
file:write("nil --[[function could not be dumped]]");
|
||||
end
|
||||
end
|
||||
end;
|
||||
["thread"] = function (file, item)
|
||||
file:write("nil --[[thread]]\n");
|
||||
end;
|
||||
["userdata"] = function (file, item)
|
||||
file:write("nil --[[userdata]]\n");
|
||||
end;
|
||||
}
|
||||
|
||||
return function (path, ...)
|
||||
local file, e;
|
||||
if type(path) == "string" then
|
||||
-- Path, open a file
|
||||
file, e = io.open(path, "w");
|
||||
if not file then
|
||||
return error(e);
|
||||
end
|
||||
else
|
||||
-- Just treat it as file
|
||||
file = path;
|
||||
end
|
||||
local n = select("#", ...);
|
||||
-- Count references
|
||||
local objRefCount = {}; -- Stores reference that will be exported
|
||||
for i = 1, n do
|
||||
refCount(objRefCount, (select(i,...)));
|
||||
end;
|
||||
-- Export Objects with more than one ref and assign name
|
||||
-- First, create empty tables for each
|
||||
local objRefNames = {};
|
||||
local objRefIdx = 0;
|
||||
file:write("-- Persistent Data\n");
|
||||
file:write("local multiRefObjects = {\n");
|
||||
for obj, count in pairs(objRefCount) do
|
||||
if count > 1 then
|
||||
objRefIdx = objRefIdx + 1;
|
||||
objRefNames[obj] = objRefIdx;
|
||||
file:write("{};"); -- table objRefIdx
|
||||
end;
|
||||
end;
|
||||
file:write("\n} -- multiRefObjects\n");
|
||||
-- Then fill them (this requires all empty multiRefObjects to exist)
|
||||
for obj, idx in pairs(objRefNames) do
|
||||
for k, v in pairs(obj) do
|
||||
file:write("multiRefObjects["..idx.."][");
|
||||
write(file, k, 0, objRefNames);
|
||||
file:write("] = ");
|
||||
write(file, v, 0, objRefNames);
|
||||
file:write(";\n");
|
||||
end;
|
||||
end;
|
||||
-- Create the remaining objects
|
||||
for i = 1, n do
|
||||
file:write("local ".."obj"..i.." = ");
|
||||
write(file, (select(i,...)), 0, objRefNames);
|
||||
file:write("\n");
|
||||
end
|
||||
-- Return them
|
||||
if n > 0 then
|
||||
file:write("return obj1");
|
||||
for i = 2, n do
|
||||
file:write(" ,obj"..i);
|
||||
end;
|
||||
file:write("\n");
|
||||
else
|
||||
file:write("return\n");
|
||||
end;
|
||||
file:close();
|
||||
end, function (path)
|
||||
local f, e = loadfile(path);
|
||||
if f then
|
||||
return f();
|
||||
else
|
||||
return nil, e;
|
||||
end;
|
||||
end
|
||||
|
||||
--[[
|
||||
Copyright (c) 2010 Gerhard Roethlin
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
]]
|
Loading…
x
Reference in New Issue
Block a user