• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

Special Storage System (key as a string)

Lolis

Member
Joined
Mar 18, 2021
Messages
20
Reaction score
12
Location
Portugal
Helo guys :)
Just implemented a litle storage system where key is a string. This can be usefull in cases you want to have a visual view of data in you database and if you wanna get less confused while programming your lua scripts :p

The system is very litle tested if I find bugs I will update the post.

Any comments are wellcome


so to install:

create the new player_special_storage table:
SQL:
CREATE TABLE `player_special_storage` (
  `player_id` int(11) NOT NULL DEFAULT 0,
  `key` varchar(255) NOT NULL DEFAULT '0',
  `value` varchar(255) NOT NULL DEFAULT '0') -- value is atm as varchar but is used for ints only
 
ALTER TABLE `player_special_storage`
ADD PRIMARY KEY (`player_id`,`key`);
 
ALTER TABLE `player_special_storage`
ADD CONSTRAINT `player_special_storage_ibfk_1` FOREIGN KEY (`player_id`) REFERENCES `players` (`id`) ON DELETE CASCADE;

add this code to your iologindata.cpp at IOLoginData::loadPlayer(Player* player, DBResult_ptr result):
Lua:
//load special player storage
query.str(std::string());
query << "SELECT `key`, `value` FROM `player_special_storage` WHERE `player_id` = " << player->getGUID();
if ((result = db.storeQuery(query.str()))) {
    do {
        player->addPlayerSpecialStorageValue(result->getString("key"), result->getNumber<int32_t>("value"));
    } while (result->next());
}

add to you iologindata.cpp at IOLoginData::savePlayer(Player* player):
Lua:
    query.str(std::string());
    query << "DELETE FROM `player_special_storage` WHERE `player_id` = " << player->getGUID();
    if (!db.executeQuery(query.str())) {
        return false;
    }

    query.str(std::string());
    DBInsert playerSpecialStorageQuery("INSERT INTO `player_special_storage` (`player_id`, `key`, `value`) VALUES ");

    for (const auto& it : player->playerSpecialStorageMap) {
        query << player->getGUID() << ',' << db.escapeString(it.first) << ',' << it.second;

        if (!playerSpecialStorageQuery.addRow(query)) {
            return false;
        }
    }

    if (!playerSpecialStorageQuery.execute()) {
        return false;
    }

add this 2 new methods to play.cpp:
Lua:
void Player::addPlayerSpecialStorageValue(const std::string& key, const int32_t value)
{
    if (value == -1) {
        playerSpecialStorageMap.erase(key);
    }
    else {
        playerSpecialStorageMap[key] = value;
    }
}

bool Player::getPlayerSpecialStorageValue(const std::string key, int32_t& value) const
{
    auto it = playerSpecialStorageMap.find(key);
    if (it == playerSpecialStorageMap.end()) {
        value = -1;
        return false;
    }

    value = it->second;
    return true;
}

at player.h where you have your player storage(after std::map<uint32_t, std::string> storageStringMap; for example) system you should add the new map:
Lua:
std::map<std::string, int32_t> playerSpecialStorageMap;

also declair new methods at player.h like this:
Lua:
bool getPlayerSpecialStorageValue(const std::string key, int32_t& value) const;
void addPlayerSpecialStorageValue(const std::string& key, const int32_t value);

at luascript.h:
Lua:
static int luaPlayerGetPlayerSpecialStorageValue(lua_State* L);
static int luaPlayerSetPlayerSpecialStorageValue(lua_State* L);

at luascript.cpp:
Lua:
registerMethod("Player", "getPlayerSpecialStorageValue", LuaScriptInterface::luaPlayerGetPlayerSpecialStorageValue);
registerMethod("Player", "setPlayerSpecialStorageValue", LuaScriptInterface::luaPlayerSetPlayerSpecialStorageValue);

and also add at luascript.cpp:
Lua:
int LuaScriptInterface::luaPlayerGetPlayerSpecialStorageValue(lua_State* L)
{
    //player:getPlayerSpecialStorageValue(key)
    Player* player = getUserdata<Player>(L, 1);
    if (!player) {
        lua_pushnil(L);
        return 1;
    }

    std::string key = getString(L, 2);
    int32_t value;
    std::string strValue;
    if (player->getPlayerSpecialStorageValue(key, value)) {
        lua_pushnumber(L, value);
    }

    else {
        lua_pushnumber(L, -1);
    }
    return 1;
}

int LuaScriptInterface::luaPlayerSetPlayerSpecialStorageValue(lua_State* L)
{
    //player:setPlayerSpecialStorageValue(key, value)
    std::string key = getString(L, 2);
    Player* player = getUserdata<Player>(L, 1);

    if (player) {
        player->addPlayerSpecialStorageValue(key, getNumber<int32_t>(L, 3));

        pushBoolean(L, true);
    }
    else {
        lua_pushnil(L);
    }
    return 1;
}


and thats it, hope it is usefull for someone
 
Thanks for the advise, was just following what was already made and replicated it.

Btw can you explain the diference? Did a small research on both and what I saw was that .clear() was faster but cloudn't understand 100% why
 
Thansk for the advise, was just following what was already make to just replicated it.

Btw can you explain the diference? Did a small research on both and what I saw was that .clear() was faster but cloudn't understand 100% why
Eh, nvm, forgot TFS is using ostringstream to build query. Leave it as it is.
 
I'm sorry for the ignorance but as I don't speak the same language you think I lacked a little understanding on my part.

is this system like a second way of storing storage?
or is it a new way of storing values in strings?
 
I'm sorry for the ignorance but as I don't speak the same language you think I lacked a little understanding on my part.

is this system like a second way of storing storage?
or is it a new way of storing values in strings?
Instead of setStorage(1234, 1) you can do setStorage("quest", 1) which is pointless imo. Not only it slows down players loading time but also uses more memory.
There is a great file to help manage storages - data/lib/core/storages.lua, use PlayerStorageKeys to add more, keeping track of which are used.

Instead of player:setStorageValue(12345, 1) you can do
Lua:
PlayerStorageKeys = {
  exampleQuest = 12345,
  statsLevel = 12346, -- reserved 12346 - 12350 (5)
  fooBar = 12351
}
And then use player:setStorageValue(PlayerStorageKeys.exampleQuest, 1)
 
Last edited:
Instead of setStorage(1234, 1) you can do setStorage("quest", 1) which is pointless imo. Not only it slows down players loading time but also uses more memory.
There is a great file to help manage storages - data/lib/core/storages.lua, use PlayerStorageKeys to add more, keeping track of which are used.

Instead of player:setStorageValue(12345, 1) you can do
Lua:
PlayerStorageKeys = {
  exampleQuest = 12345,
  statsLevel = 12346, -- reserved 12346 - 12350 (5)
  fooBar = 12351
}
And then use player:setStorageValue(PlayerStorageKeys.exampleQuest, 1)

do u have to create the file and add manually the storages? I don't have that file (using TFS 1.3)

1616501020058.png
 
do u have to create the file and add manually the storages? I don't have that file (using TFS 1.3)

View attachment 56732
Definitely part of 1.3
 
Definitely part of 1.3
But this file checks all data for setStorages or you add storages there manually to keep track of them and just use variables in data scripts?
 
@domvinicius it is what @oen432 said. About the utility or not, this was published because a friend requested me this so I just published what I did, I agree that it might slow down the player's load and will use more memory but its up to people to decide if they want to copy this or not. And tbh I dont think that this will cause any problem.

What Oen said is the right practive to follow imo.

Just added it here in case someone find it usefull, and might add ideias for other functionalities. :p
 
@domvinicius it is what @oen432 said. About the utility or not, this was published because a friend requested me this so I just published what I did, I agree that it might slow down the player's load and will use more memory but its up to people to decide if they want to copy this or not. And tbh I dont think that this will cause any problem.

What Oen said is the right practive to follow imo.

Just added it here in case someone find it usefull, and might add ideias for other functionalities. :p
I understand, a beautiful idea .... I will test and think of ideas for him, anything posted here to contribute
 
If you making an project from zero (from scratch) you can always save storages in Lib folder in data and do things like Oen said or something like:
STORAGE_FIRST_QUEST = 1
keyword thats represent storagavalue (name) = storage value (number)
.. etc.
As I want to say.. it's better to hold storages in one file because it's easier to organize and search for unused/used ones.

Anyway this feature is good for newcomers! Great release buddy!
 
Last edited:
Back
Top