Last active
September 29, 2019 14:52
-
-
Save Znote/0317d3667447ad0f5473221e116eea7f to your computer and use it in GitHub Desktop.
[TFS 1.3] [Revscriptsys] setStorageValue and getStorageValue with string support for both keys and values prototype
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- /data/scripts/player_storagevalue.lua | |
-- TODO: Deprecate reserved_storage_min, reserved_storage_max, reserved_high, reserved_table | |
-- They are uneccesary, there is no point in trying to force player_storage usage unless it directly benefits us. | |
local function dump(o) | |
if type(o) == 'table' then | |
local s = '{ ' | |
for k,v in pairs(o) do | |
if type(k) ~= 'number' then k = '"'..k..'"' end | |
s = s .. '['..k..'] = ' .. dump(v) .. ',' | |
end | |
return s .. '} ' | |
else | |
return tostring(o) | |
end | |
end | |
local function int_foreach(t) -- seqipairs | |
local _t = {} | |
for i = 1, table.maxn(t) do | |
local val = t[i] | |
if val then | |
_t[#_t+1] = {key = i, value = val} | |
end | |
end | |
local i = 0 | |
return function() | |
i = i + 1 | |
local val = _t[i] | |
if val then | |
return val.key, val.value | |
end | |
return nil | |
end | |
end | |
-- Declare, load and maintain a local table of all storage values and keys | |
classic_storage = {} | |
storage_string_keys = {} | |
storage_string_values = {} | |
player_storage_string = {} | |
-- 4000 reserved storage value range for player_storages | |
-- Used when creating an integer value reference from a string key | |
reserved_storage_min = 21000 | |
reserved_storage_max = 24999 | |
reserved_high = reserved_storage_min | |
reserved_table = {} | |
-- storage value collition detection in the reserved storage value range | |
-- Do a startup check warning if any collition detected | |
--[[ | |
SELECT | |
`is`.`player_id`, | |
`is`.`key`, | |
`ss`.`value_key` | |
FROM `player_storage` AS `is` | |
LEFT JOIN `player_storage_string` AS `ss` | |
ON `is`.`player_id` = `ss`.`player_id` | |
AND `is`.`key` = `ss`.`value_key` | |
AND `ss`.`type` = 0 | |
WHERE | |
`is`.`key` >= reserved_storage_min | |
AND `is`.`key` <= reserved_storage_max | |
AND `ss`.`value_key` IS NULL | |
]] | |
-- | |
storage_log_queries = { | |
player_storage = {}, -- {t=2, p=player_id, d="query row data"} | |
player_storage_string = {}, | |
--storage_string_keys = {}, | |
--storage_string_values = {}, | |
rows = { | |
player_storage = 0, | |
player_storage_string = 0, | |
storage_string_keys = 0, | |
storage_string_values = 0 | |
} | |
} | |
function dumpStorage() | |
print(" ") | |
print("=======================") | |
print("= DUMP znote_storages =") | |
print("=======================") | |
print("== classic storage ============") | |
print(dump(classic_storage)) | |
print(" ") | |
print("== storage_string_keys ============") | |
print(dump(storage_string_keys)) | |
print(" ") | |
print("== storage_string_values ============") | |
print(dump(storage_string_values)) | |
print(" ") | |
print("== player storage string ============") | |
print(dump(player_storage_string)) | |
print(" ") | |
print("== QUERY LOG ============") | |
print(dump(storage_log_queries)) | |
print(" ") | |
return true | |
end | |
-- Toggle this via talkaction /debug_storage | |
storage_console_debug = true | |
local function printd(s) | |
if storage_console_debug then | |
print(s) | |
end | |
end | |
local talk_debugStorage = TalkAction("/debug_storage") | |
function talk_debugStorage.onSay(player, words, param) | |
if storage_console_debug then | |
storage_console_debug = false | |
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "Disabled debug messages from console.") | |
else | |
storage_console_debug = true | |
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "Enabled debug messages from console.") | |
end | |
return true | |
end | |
talk_debugStorage:separator(" ") | |
talk_debugStorage:register() | |
-- +55 database.cpp | |
-- DBResult_ptr result = storeQuery("SHOW VARIABLES LIKE 'max_allowed_packet'"); | |
-- Figure out how many rows can be inserted in one query | |
-- without exceeding server mysql max_allowed_packet configuration | |
-- hook into globalevent closeserver and saveserver and shutdown to execute log queries | |
local global_loadPlayerStorage = GlobalEvent("global_loadPlayerStorage") | |
function global_loadPlayerStorage.onStartup() | |
printd(" ") | |
printd("============================") | |
printd("= global_loadPlayerStorage =") | |
printd("============================") | |
-- Load all storage values from SQL server and store it internally | |
local resultId = db.storeQuery("SELECT `player_id`, `key`, `value` FROM `player_storage` ORDER BY `player_id` ASC, `key` ASC") | |
if resultId ~= false then | |
-- Declare SQL row parser | |
local lastPlayer = false | |
local storage = {} | |
local rows = 0 | |
repeat | |
-- Load the player id from SQL | |
local currentPlayer = result.getDataInt(resultId, "player_id") | |
-- If lastPlayer is declared but not initialized, give it the current player id. | |
if lastPlayer == false then | |
lastPlayer = currentPlayer | |
end | |
-- If lastPlayer is not currentPlayer, | |
-- import local storage into classic_storage, and prepare it for currentPlayer | |
if lastPlayer ~= currentPlayer then | |
classic_storage[lastPlayer] = storage | |
storage = {} | |
lastPlayer = currentPlayer | |
end | |
-- populate local storage | |
storage[result.getDataInt(resultId, "key")] = result.getDataInt(resultId, "value") | |
rows = rows + 1 | |
until not result.next(resultId) | |
result.free(resultId) | |
classic_storage[lastPlayer] = storage | |
printd("Loaded: " .. rows .. " player storage values from database to classic_storage.") | |
else | |
printd("Loaded: 0 player storage values from database to classic_storage.") | |
end | |
printd("== classic storage (untouched player_storage structure / integer keys and values) ============") | |
printd(dump(classic_storage)) | |
printd(" ") | |
resultId = db.storeQuery("SELECT `string`, `key` FROM `storage_string_keys`") | |
if resultId ~= false then | |
local rows = 0 | |
repeat -- populate storage_string_keys | |
storage_string_keys[result.getDataString(resultId, "string")] = result.getDataInt(resultId, "key") | |
rows = rows + 1 | |
until not result.next(resultId) | |
result.free(resultId) | |
printd("Loaded: " .. rows .. " string keys from database storage_string_keys.") | |
else | |
printd("Loaded: 0 string keys from database storage_string_keys.") | |
end | |
printd("== storage_string_keys (unique player-independent string <-> id reference table) ============") | |
printd(dump(storage_string_keys)) | |
printd(" ") | |
resultId = db.storeQuery("SELECT `key`, `string` FROM `storage_string_values`") | |
if resultId ~= false then | |
local rows = 0 | |
repeat -- populate storage_string_values | |
storage_string_values[result.getDataInt(resultId, "key")] = result.getDataString(resultId, "string") | |
rows = rows + 1 | |
until not result.next(resultId) | |
result.free(resultId) | |
printd("Loaded: " .. rows .. " string keys from database storage_string_values.") | |
else | |
printd("Loaded: 0 string values from database storage_string_values.") | |
end | |
printd("== storage_string_values (unique player-independent string <-> id reference table) ============") | |
printd(dump(storage_string_values)) | |
printd(" ") | |
-- Load all storage values from SQL server and store it internally | |
resultId = db.storeQuery("SELECT `player_id`, `key_key`, `value_key`, `type` FROM `player_storage_string` ORDER BY `player_id` ASC, `key_key` ASC") | |
if resultId ~= false then | |
local lastPlayer = false | |
local storage = {} | |
local rows = 0 | |
repeat | |
-- Load the player id from SQL | |
local currentPlayer = result.getDataInt(resultId, "player_id") | |
-- If lastPlayer is declared but not initialized, give it the current player id. | |
if lastPlayer == false then | |
lastPlayer = currentPlayer | |
end | |
-- If lastPlayer is not currentPlayer, | |
-- import local storage into player_storage_string, and prepare it for currentPlayer | |
if lastPlayer ~= currentPlayer then | |
player_storage_string[lastPlayer] = storage | |
storage = {} | |
lastPlayer = currentPlayer | |
end | |
-- extract key and types | |
local key_key = result.getDataInt(resultId, "key_key") | |
local rowdata = { | |
v=result.getDataInt(resultId, "value_key"), | |
t=result.getDataInt(resultId, "type") | |
} | |
-- Populate the reserved_table with used key_key -> value_key association | |
if rowdata.t == 0 and reserved_table[key_key] == nil then | |
reserved_table[key_key] = rowdata.v | |
if rowdata.v > reserved_high then | |
reserved_high = rowdata.v | |
end | |
end | |
-- populate local storage | |
storage[key_key] = rowdata | |
rows = rows + 1 | |
until not result.next(resultId) | |
result.free(resultId) | |
player_storage_string[lastPlayer] = storage | |
printd("Loaded: " .. rows .. " player storage values from database to player_storage_string.") | |
else | |
printd("Loaded: 0 player storage values from database to player_storage_string.") | |
end | |
printd("== player storage string (player string ID key <-> value reference table) ============") | |
printd(dump(player_storage_string)) | |
printd(" ") | |
end | |
--result.getDataInt(resultId, "rank_id") | |
--db.escapeString(result.getDataString(resultId, "guild_nick")) | |
global_loadPlayerStorage:register() | |
local global_savePlayerStorage = GlobalEvent("global_savePlayerStorage") | |
function global_savePlayerStorage.onShutdown() | |
printd(" ") | |
printd("== SHUTDOWN INITIATED - SAVING player storagevalues ==") | |
--dumpStorage() | |
printd(dump(storage_log_queries['player_storage'])) | |
local SQL_rows = {} | |
local count = 0 | |
for _, row in pairs(storage_log_queries['player_storage']) do | |
table.insert(SQL_rows, "("..row[1]..","..row[2]..","..row[3]..")") | |
count = count + 1 | |
end | |
storage_log_queries['player_storage'] = {} | |
storage_log_queries['rows']['player_storage'] = 0 | |
local SQL_query = "INSERT INTO `player_storage` (`player_id`,`key`,`value`) VALUES "..table.concat(SQL_rows,',').." ON DUPLICATE KEY UPDATE `value`=VALUES(`value`);" | |
if count > 0 then db.query(SQL_query) end | |
--[[ | |
INSERT INTO `player_storage` (`player_id`,`key`,`value`) VALUES | |
(2,1337,500), | |
(13,1337,325) | |
ON DUPLICATE KEY UPDATE `value`=VALUES(`value`); | |
]] | |
SQL_rows = {} | |
count = 0 | |
for _, row in pairs(storage_log_queries['player_storage_string']) do | |
table.insert(SQL_rows, "("..row[1]..","..row[2]..","..row[3]..","..row[4]..")") | |
count = count + 1 | |
end | |
storage_log_queries['player_storage_string'] = {} | |
storage_log_queries['rows']['player_storage_string'] = 0 | |
SQL_query = "INSERT INTO `player_storage_string` (`player_id`,`key_key`,`value_key`,`type`) VALUES "..table.concat(SQL_rows,',').." ON DUPLICATE KEY UPDATE `value_key`=VALUES(`value_key`), `type`=VALUES(`type`);" | |
if count > 0 then db.query(SQL_query) end | |
--[[ | |
INSERT INTO `player_storage_string` (`player_id`,`key_key`,`value_key`,`type`) VALUES | |
(2,4,7,1), | |
(2,8,16,1) | |
ON DUPLICATE KEY UPDATE `value_key`=VALUES(`value_key`), `key_type`=VALUES(`key_type`); | |
]] | |
return true | |
end | |
global_savePlayerStorage:register() | |
Player.oldGetStorageValue = Player.getStorageValue | |
Player.oldSetStorageValue = Player.setStorageValue | |
function Player.getStorageValue(self, key) | |
local ret = nil | |
local pid = self:getGuid() | |
-- player:getStorageValue(1337) | |
if type(key) == 'number' then | |
if classic_storage[pid] ~= nil then | |
ret = classic_storage[pid][key] | |
end | |
end | |
if ret == nil then | |
-- player:getStorageValue("Arena_bestplayer") | |
key = string.lower(''..key) | |
-- -- storage_string_keys ("Znote") = {key = 13} | |
if storage_string_keys[key] ~= nil then | |
-- param key is string, so lets find the int representation of the string | |
local int_key = storage_string_keys[key] | |
-- does player have any string storage keys? | |
if player_storage_string[pid] ~= nil then | |
-- does player have this specific string key? | |
if player_storage_string[pid][int_key] ~= nil then | |
-- does this string key reference an int or string value? | |
if player_storage_string[pid][int_key].t == 0 then | |
-- int value | |
if classic_storage[pid] ~= nil then | |
ret = classic_storage[pid][player_storage_string[pid][int_key].v] | |
end | |
elseif player_storage_string[pid][int_key].t == 1 then | |
-- string value | |
ret = storage_string_values[player_storage_string[pid][int_key].v] | |
end | |
end | |
end | |
end | |
end | |
if ret == nil then ret = -1 end | |
printd(pid..":getStorageValue(".. key ..") = "..ret) | |
return ret | |
end | |
function Player.setStorageValue(self, key, value) | |
local ret = false | |
local pid = self:getGuid() | |
-- if both key and value are integers, we can use the old classic storage system | |
if type(key) == 'number' and type(value) == 'number' then | |
local key_int = math.floor(key) -- Dont allow floats or double numbers | |
local value_int = math.floor(value) -- Dont allow floats or double numbers | |
if key_int ~= key or value_int ~= value then | |
printd("Warning: setStorageValue parameters converted to whole number.\nsetStorageValue("..key..","..value..") changed to setStorageValue("..key_int..","..value_int..")") | |
end | |
-- Does player exist in storage list? | |
if classic_storage[pid] ~= nil then | |
-- Does this player already have this storage key? | |
if classic_storage[pid][key_int] ~= nil then | |
-- Is the stored value different from new value? | |
if classic_storage[pid][key_int] ~= value_int then | |
-- update | |
classic_storage[pid][key_int] = value_int | |
table.insert(storage_log_queries.player_storage, {pid, key_int, value_int}) | |
storage_log_queries.rows.player_storage = storage_log_queries.rows.player_storage + 1 | |
-- TMP: classic_storage is being truncated and populated in C++ | |
self:oldSetStorageValue(key_int,value_int) | |
end | |
else | |
-- insert | |
classic_storage[pid][key_int] = value_int | |
table.insert(storage_log_queries.player_storage, {pid, key_int, value_int}) | |
storage_log_queries.rows.player_storage = storage_log_queries.rows.player_storage + 1 | |
-- TMP: classic_storage is being truncated and populated in C++ | |
self:oldSetStorageValue(key_int,value_int) | |
end | |
else | |
-- Create and insert | |
classic_storage[pid] = {[key_int]=value_int} | |
table.insert(storage_log_queries.player_storage, {pid, key, value_int}) | |
storage_log_queries.rows.player_storage = storage_log_queries.rows.player_storage + 1 | |
-- TMP: classic_storage is being truncated and populated in C++ | |
self:oldSetStorageValue(key,value_int) | |
end | |
ret = true | |
else -- key and/or value is a string | |
if not tonumber(key) then key = string.lower(key) end | |
local key_str = ''..key | |
local key_key = false | |
local new_value_key = false | |
-- If this string key doesn't exist, create it. | |
if storage_string_keys[key_str] == nil then | |
-- We can do live SQL query here since its not player specific | |
-- We also kinda want to do a live query, so we can retrieve the AUTO_INCREMENT key value | |
-- instead of an unreliable guess | |
db.query("INSERT INTO `storage_string_keys` (`string`) VALUES (".. db.escapeString(key_str) ..");") | |
resultId = db.storeQuery("SELECT `key` FROM `storage_string_keys` WHERE `string` = ".. db.escapeString(key_str) ..";") | |
if resultId ~= false then | |
key_key = result.getDataInt(resultId, "key") | |
storage_string_keys[key_str] = key_key | |
else | |
printd("Error: setStorageValue: Failed to store string and load key. \nTable: storage_string_keys. \nString: " .. db.escapeString(key_str)) | |
end | |
else | |
key_key = storage_string_keys[key_str] | |
end | |
-- If this value is a string and doesn't exist, create it. | |
if type(value) == 'string' then | |
-- Do we already have a value key for this string? | |
for i, s in int_foreach(storage_string_values) do | |
if s == value then | |
new_value_key = i | |
break | |
end | |
end | |
if not new_value_key then | |
-- We can do live SQL query here since its not player specific | |
-- We also kinda want to do a live query, so we can retrieve the AUTO_INCREMENT key value | |
-- instead of an unreliable guess | |
db.query("INSERT INTO `storage_string_values` (`string`) VALUES (".. db.escapeString(value) ..");") | |
resultId = db.storeQuery("SELECT `key` FROM `storage_string_values` WHERE `string` = ".. db.escapeString(value) ..";") | |
if resultId ~= false then | |
new_value_key = result.getDataInt(resultId, "key") | |
storage_string_values[new_value_key] = value | |
else | |
printd("Error: setStorageValue: Failed to store string and load key. \nTable: storage_string_values. \nString: " .. db.escapeString(value)) | |
end | |
end | |
end | |
-- create pid | |
if player_storage_string[pid] == nil then | |
player_storage_string[pid] = {} | |
end | |
if player_storage_string[pid][key_key] ~= nil then | |
local old_value_key = player_storage_string[pid][key_key].v | |
local key_type = player_storage_string[pid][key_key].t | |
if key_type == 1 then | |
-- Value is string | |
-- Is stored value different from current value? | |
--if storage_string_values[old_value_key] ~= value then | |
if old_value_key ~= new_value_key then | |
if type(value) == 'number' then | |
printd("Error: value of string key is suppose to be a string. \nkey: " .. key_str .. "\nValue: "..storage_string_values[old_value_key].."\nNew value: "..value) | |
elseif type(value) == 'string' then | |
-- update | |
player_storage_string[pid][key_key].v = new_value_key | |
table.insert(storage_log_queries.player_storage_string, {pid, key_key, new_value_key, key_type}) | |
storage_log_queries.rows.player_storage_string = storage_log_queries.rows.player_storage_string + 1 | |
ret = true | |
else | |
printd("Error: Unrecognized value type: " .. type(value)) | |
end | |
end | |
else | |
-- value is integer | |
-- Is stored value different from current value? | |
if classic_storage[pid][old_value_key] ~= value then | |
if type(value) == 'string' then | |
printd("Error: value of string key is suppose to be an integer. \nkey: " .. key_str .. "\nValue: "..classic_storage[pid][old_value_key].."\nNew value: "..value) | |
elseif type(value) == 'number' then | |
-- update | |
local value_int = math.floor(value) -- Dont allow floats or double numbers | |
if value_int ~= value then | |
printd("Warning: setStorageValue value parameter converted to whole number.\nsetStorageValue('"..key.."',"..value..") changed to setStorageValue('"..key.."',"..value_int..")") | |
end | |
classic_storage[pid][old_value_key] = value_int | |
table.insert(storage_log_queries.player_storage, {pid, old_value_key, value_int}) | |
storage_log_queries.rows.player_storage = storage_log_queries.rows.player_storage + 1 | |
ret = true | |
-- TMP: classic_storage is being truncated and populated in C++ | |
self:oldSetStorageValue(old_value_key,value_int) | |
else | |
printd("Error: Unrecognized value type: " .. type(value)) | |
end | |
end | |
end | |
else | |
-- insert (depending on type) | |
if type(value) == 'string' then | |
-- update | |
player_storage_string[pid][key_key] = { | |
v=new_value_key, | |
t=1 | |
} | |
table.insert(storage_log_queries.player_storage_string, {pid, key_key, new_value_key, 1}) | |
storage_log_queries.rows.player_storage_string = storage_log_queries.rows.player_storage_string + 1 | |
ret = true | |
elseif type(value) == 'number' then | |
local value_int = math.floor(value) -- Dont allow floats or double numbers | |
if value_int ~= value then | |
printd("Warning: setStorageValue parameters converted to whole number.\nsetStorageValue("..key_key..","..value..") changed to setStorageValue("..key_key..","..value_int..")") | |
end | |
-- Does anyone else has a classic_storage key for this? | |
if reserved_table[key_key] ~= nil then | |
-- yes: re-use that one | |
player_storage_string[pid][key_key] = { | |
v=reserved_table[key_key], | |
t=0 | |
} | |
table.insert(storage_log_queries.player_storage_string, {pid, key_key, reserved_table[key_key], 0}) | |
storage_log_queries.rows.player_storage_string = storage_log_queries.rows.player_storage_string + 1 | |
-- update or insert classic_storage | |
if classic_storage[pid] == nil then | |
classic_storage[pid] = {[reserved_table[key_key]]=value_int} | |
else | |
classic_storage[pid][reserved_table[key_key]] = value_int | |
end | |
table.insert(storage_log_queries.player_storage, {pid, reserved_table[key_key], value_int}) | |
storage_log_queries.rows.player_storage = storage_log_queries.rows.player_storage + 1 | |
ret = true | |
-- TMP: classic_storage is being truncated and populated in C++ | |
self:oldSetStorageValue(reserved_table[key_key],value_int) | |
else | |
-- no: create a new one | |
-- generate a new key | |
res_key = reserved_high + 1 | |
-- Ensure this generated key doesn't conflict with any existing keys | |
for _, i_res_key in ipairs(reserved_table) do | |
if i_res_key >= res_key then | |
printd("Warning: setStorageValue("..key_key..","..value_int..") - Auto allocated res_key ["..res_key.."] already in use. Trying to use: ["..(i_res_key + 1).."] instead.") | |
res_key = i_res_key + 1 | |
end | |
end | |
-- see if allocated res_key is available and within reserved_range | |
if res_key <= reserved_storage_max then | |
player_storage_string[pid][key_key] = { | |
v=res_key, | |
t=0 | |
} | |
table.insert(storage_log_queries.player_storage_string, {pid, key_key, res_key, 0}) | |
storage_log_queries.rows.player_storage_string = storage_log_queries.rows.player_storage_string + 1 | |
-- update or insert classic_storage | |
if classic_storage[pid] == nil then | |
classic_storage[pid] = {[res_key]=value_int} | |
else | |
classic_storage[pid][res_key] = value_int | |
end | |
table.insert(storage_log_queries.player_storage, {pid, res_key, value_int}) | |
storage_log_queries.rows.player_storage = storage_log_queries.rows.player_storage + 1 | |
reserved_table[res_key] = value_int | |
ret = true | |
-- TMP: classic_storage is being truncated and populated in C++ | |
self:oldSetStorageValue(res_key,value_int) | |
else | |
printd("Error: reserved_high: " .. res_key .. " exceeds reserved_storage_max: " .. reserved_storage_max .. "\nOperation cancelled: setStorageValue("..key_key..","..value_int..")") | |
end | |
end | |
else | |
printd("Error: Unrecognized value type: " .. type(value)) | |
end | |
end | |
end | |
local ret_str = ret and '[true]' or '[false]' | |
printd(pid..":setStorageValue(".. key ..",".. value ..") = "..ret_str) | |
return ret | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CREATE TABLE IF NOT EXISTS `storage_string_keys` ( | |
`string` varchar(255) NOT NULL, | |
`key` int(10) unsigned NOT NULL AUTO_INCREMENT, | |
PRIMARY KEY (`string`), | |
UNIQUE KEY `key` (`key`) | |
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8; | |
CREATE TABLE IF NOT EXISTS `storage_string_values` ( | |
`key` int(10) unsigned NOT NULL AUTO_INCREMENT, | |
`string` varchar(255) NOT NULL, | |
PRIMARY KEY (`key`), | |
UNIQUE KEY `string` (`string`) | |
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8; | |
CREATE TABLE IF NOT EXISTS `player_storage_string` ( | |
`player_id` int(11) NOT NULL DEFAULT '0', | |
`key_key` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'Table: storage_string_values', | |
`value_key` int(10) unsigned NOT NULL COMMENT 'Key reference in (player_storage) or (storage_string_values) based on type', | |
`type` tinyint(1) NOT NULL DEFAULT '0' COMMENT '0 = int (player_storage), 1 = string (storage_string_values)', | |
PRIMARY KEY (`player_id`,`key_key`), | |
FOREIGN KEY (`player_id`) REFERENCES `players`(`id`) ON DELETE CASCADE, | |
FOREIGN KEY (`key_key`) REFERENCES `storage_string_keys`(`key`) | |
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local function dump(o) | |
if type(o) == 'table' then | |
local s = '{ ' | |
for k,v in pairs(o) do | |
if type(k) ~= 'number' then k = '"'..k..'"' end | |
s = s .. '['..k..'] = ' .. dump(v) .. ',' | |
end | |
return s .. '} ' | |
else | |
return tostring(o) | |
end | |
end | |
local talk_dumpStorage = TalkAction("/dumpstorage") | |
function talk_dumpStorage.onSay(player, words, param) | |
dumpStorage() | |
return true | |
end | |
talk_dumpStorage:separator(" ") | |
talk_dumpStorage:register() | |
local getStorage = TalkAction("/getstorage") | |
function getStorage.onSay(player, words, param) | |
local key = tonumber(param) | |
local print_key = nil | |
local print_pid = player:getGuid() | |
if not key then | |
key = string.lower(param) | |
print_key = db.escapeString(key) | |
else | |
print_key = key | |
end | |
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, " ") | |
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, " "..print_pid..":getStorageValue("..print_key .."): "..dump(player:getStorageValue(key))) | |
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "OLD "..print_pid..":getStorageValue("..print_key .."): "..dump(player:oldGetStorageValue(key))) | |
return true | |
end | |
getStorage:separator(" ") | |
getStorage:register() | |
local setStorage = TalkAction("/setstorage") | |
function setStorage.onSay(player, words, param) | |
local parts = param:split(',') | |
local input = { | |
key=parts[1], | |
value=parts[2] | |
} | |
local key = tonumber(input.key) | |
local value = tonumber(input.value) | |
local print_key = nil | |
local print_value = nil | |
local print_pid = player:getGuid() | |
if not key then | |
key = string.lower(input.key) | |
print_key = db.escapeString(key) | |
else | |
print_key = key | |
end | |
if not value then | |
value = input.value | |
print_value = db.escapeString(value) | |
else | |
print_value = value | |
end | |
player:setStorageValue(key,value) | |
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, " ") | |
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, ""..print_pid..":setStorageValue("..print_key ..", ".. print_value..")") | |
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "=== "..print_pid..":getStorageValue("..print_key .."): "..dump(player:getStorageValue(key))) | |
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "OLD "..print_pid..":getStorageValue("..print_key .."): "..dump(player:oldGetStorageValue(key))) | |
return true | |
end | |
setStorage:separator(" ") | |
setStorage:register() | |
--[[ some tests I used this talkaction for | |
2:setStorageValue('hello', 'world') | |
=== 2:getStorageValue('hello'): world | |
OLD 2:getStorageValue('hello'): -1 | |
2:setStorageValue(1337, 7331) | |
=== 2:getStorageValue(1337): 7331 | |
OLD 2:getStorageValue(1337): 7331 | |
2:setStorageValue(7331, 'this@is.LEET') | |
=== 2:getStorageValue(7331): this@is.LEET | |
OLD 2:getStorageValue(7331): -1 | |
2:setStorageValue(7331, 1337) | |
=== 2:getStorageValue(7331): 1337 | |
OLD 2:getStorageValue(7331): 1337 | |
2:setStorageValue('woo', 'HOO!') | |
=== 2:getStorageValue('woo'): HOO! | |
OLD 2:getStorageValue('woo'): -1 | |
2:setStorageValue('autoloot', 1) | |
=== 2:getStorageValue('autoloot'): 1 | |
OLD 2:getStorageValue('autoloot'): -1 | |
]] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment