bank_accounts/functions.lua
2025-08-22 02:10:35 +02:00

147 lines
5.9 KiB
Lua

-- functions.lua (Corrected for Deadlock issue during interest calculation)
local world_path = minetest.get_worldpath()
local file_path = world_path .. "/accounts"
function normalize_and_tonumber(str)
if not str then return nil end
str = str:gsub(",", ".")
return tonumber(str)
end
local function read_accounts_file()
local f = io.open(file_path, "r")
if not f then return { balance = {}, pin = {}, credit = {}, history = {} } end
local data = f:read("*a")
f:close()
if data == "" or data == nil then return { balance = {}, pin = {}, credit = {}, history = {} } end
return minetest.deserialize(data) or { balance = {}, pin = {}, credit = {}, history = {} }
end
-- CORRECTED: The save function now accepts an optional parameter to bypass the lock.
local function save_accounts_file(data, bypass_lock)
-- If the interest script is running AND the lock bypass is NOT active, block the save.
if not bypass_lock and bank_accounts and bank_accounts.is_calculating_interest then
minetest.log("warning", "[bank_accounts] Save operation blocked: Daily interest calculation is in progress.")
return false -- Signal failure
end
local f, err = io.open(file_path, "w")
if not f then
minetest.log("error", "[bank_accounts] Could not open accounts file for writing: " .. tostring(err))
return false
end
f:write(minetest.serialize(data))
f:close()
return true
end
local function log_transaction(data, player_name, account_type, amount, new_total, trans_type, purpose, other_party)
if not data.history then data.history = {} end
if not data.history[player_name] then data.history[player_name] = {} end
local transaction = { timestamp = os.time(), type = trans_type or "unknown", account = account_type, amount = amount, new_total = new_total, purpose = purpose or "", other = other_party or "" }
table.insert(data.history[player_name], 1, transaction)
while #data.history[player_name] > 200 do
table.remove(data.history[player_name])
end
end
-- On first run, bypass lock to create file safely.
do
local f = io.open(file_path, "r")
if not f then
save_accounts_file({ balance = {}, pin = {}, credit = {}, history = {} }, true)
else
f:close()
end
end
--- API ---
function bank_accounts.get_account_data(player_name)
if not player_name then
return read_accounts_file()
end
local data = read_accounts_file()
if not data.history then data.history = {} end
return {
balance = data.balance[player_name] or 0,
pin = data.pin[player_name] or "0000",
credit = data.credit[player_name] or 0,
history = data.history[player_name] or {},
}
end
function bank_accounts.get_all_data()
return read_accounts_file()
end
-- CORRECTED: save_all now calls the internal save function with the bypass parameter.
function bank_accounts.save_all(data)
return save_accounts_file(data, true)
end
function bank_accounts.get_balance(player_name) local data = read_accounts_file(); return data.balance[player_name] or 0 end
function bank_accounts.get_credit(player_name) local data = read_accounts_file(); return data.credit[player_name] or 0 end
function bank_accounts.get_pin(player_name) local data = read_accounts_file(); return data.pin[player_name] or "0000" end
function bank_accounts.add_balance(player_name, amount, trans_type, purpose, other_party)
local data = read_accounts_file()
local current_balance = data.balance[player_name] or 0
local new_balance = current_balance + tonumber(amount)
data.balance[player_name] = new_balance
log_transaction(data, player_name, "balance", amount, new_balance, trans_type, purpose, other_party)
return save_accounts_file(data)
end
function bank_accounts.set_balance(player_name, amount, trans_type, purpose, other_party)
local data = read_accounts_file()
local current_balance = data.balance[player_name] or 0
local new_balance = tonumber(amount)
local diff = new_balance - current_balance
data.balance[player_name] = new_balance
log_transaction(data, player_name, "balance", diff, new_balance, trans_type or "admin_set", purpose, other_party)
return save_accounts_file(data)
end
function bank_accounts.add_credit(player_name, amount, trans_type, purpose, other_party)
local data = read_accounts_file()
local current_credit = data.credit[player_name] or 0
local new_credit = current_credit + tonumber(amount)
data.credit[player_name] = new_credit
log_transaction(data, player_name, "credit", amount, new_credit, trans_type, purpose, other_party)
return save_accounts_file(data)
end
function bank_accounts.set_credit(player_name, amount, trans_type, purpose, other_party)
local data = read_accounts_file()
local current_credit = data.credit[player_name] or 0
local new_credit = tonumber(amount)
local diff = new_credit - current_credit
data.credit[player_name] = new_credit
log_transaction(data, player_name, "credit", diff, new_credit, trans_type or "admin_set_credit", purpose, other_party)
return save_accounts_file(data)
end
function bank_accounts.set_pin(player_name, pin)
local data = read_accounts_file()
data.pin[player_name] = tostring(pin)
return save_accounts_file(data)
end
function bank_accounts.player_has_account(player_name)
local data = read_accounts_file()
return data.balance[player_name] ~= nil
end
function bank_accounts.create_account(player_name)
if bank_accounts.player_has_account(player_name) then return false end
local data = read_accounts_file()
data.balance[player_name] = 0
data.pin[player_name] = "0000"
data.credit[player_name] = 0
if not data.history then data.history = {} end
data.history[player_name] = {}
log_transaction(data, player_name, "system", 0, 0, "Account Created", "Initial account setup")
return save_accounts_file(data)
end