• 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!

Lua How to save changes made in game?

Joined
Jul 18, 2014
Messages
193
Solutions
2
Reaction score
15
Hi! I got a question, how to save some changes made in game? If I create some wall and I reset the server, i want the wall still there.
I know that the map is possible modify it by RME, but i dont know if this is possible.
Im thinking in some lua script, when I create something with an specific command (different of /i) anything that i create will be saved and with another command or with a globalscript load those things.
It's for TFS 1.2.

Thanks^^
 
Hi! I got a question, how to save some changes made in game? If I create some wall and I reset the server, i want the wall still there.
I know that the map is possible modify it by RME, but i dont know if this is possible.
Im thinking in some lua script, when I create something with an specific command (different of /i) anything that i create will be saved and with another command or with a globalscript load those things.
It's for TFS 1.2.

Thanks^^
You could create a new table in the database and store it there, its the same thing as using a script to generate tiles, although it could be quite the load on the server if it is extensive or done too quickly.

This method is how 3d games store their objects in the world, they use coordinates and the object type to determine its location.
This is why if you run a private wow server and move something in the world it effects all players not just the person moving it, as well as when they reboot the server the items are in the new location.

An Example
Burning Crusades database was about 250 mbs in size many years ago, in case you are concerned of how much is too extensive, of course it also depends on the server used, can tfs handle a huge database?.. idk
 
You could create a new table in the database and store it there, its the same thing as using a script to generate tiles, although it could be quite the load on the server if it is extensive or done too quickly.

This method is how 3d games store their objects in the world, they use coordinates and the object type to determine its location.
This is why if you run a private wow server and move something in the world it effects all players not just the person moving it, as well as when they reboot the server the items are in the new location.

An Example
Burning Crusades database was about 250 mbs in size many years ago, in case you are concerned of how much is too extensive, of course it also depends on the server used, can tfs handle a huge database?.. idk

Can you give me an example of how can i create that new table?
 
Can you give me an example of how can i create that new table?
Here it is:

Save this to some lib file you can create a new one or put it in any existing one.
Code:
function Tile:removeFromMap()
    local items = self:getItems()
    table.insert(items, self:getGround())
    for i = 1, #items do
        items[i]:remove()
    end
end

function Tile:save()
    if self:getGround() then
        local pos = self:getPosition()
        db.query("DELETE FROM `tile_save` WHERE `posx` = " .. pos.x .. " AND `posy` = " .. pos.y .. " AND `posz` = " .. pos.z .. ";")
        local buffer = {"INSERT INTO `tile_save` (`itemid`, `count`, `posx`, `posy`, `posz`, `stackpos`) VALUES "}
        local items = {self:getGround()}
        local itab = self:getItems()
        for i = #itab, 1, -1 do
            table.insert(items, itab[i])
        end
        for i = 1, #items do
            local item = items[i]
            if i ~= 1 then
                table.insert(buffer, ",")
            end
            table.insert(buffer, string.format("(%d, %d, %d, %d, %d, %d)", item:getId(), item:getCount(), pos.x, pos.y, pos.z, i-1))
        end
        table.insert(buffer, ";")
        db.query(table.concat(buffer))
    end
end

function Tile:removeSave()
   local pos = self:getPosition()
   db.query("DELETE FROM `tile_save` WHERE `posx` = " .. pos.x .. " AND `posy` = " .. pos.y .. " AND `posz` = " .. pos.z .. ";")
end

function loadSavedTiles()
    db.asyncStoreQuery("SELECT * FROM `tile_save` ORDER BY `stackpos` ASC;",
    function(query)
        if query then
            local ret = {}
            repeat
                local itemid, count, posx, posy, posz, stackpos = result.getDataInt(query, "itemid"), result.getDataInt(query, "count"), result.getDataInt(query, "posx"), result.getDataInt(query, "posy"), result.getDataInt(query, "posz"), result.getDataInt(query, "stackpos")
                if itemid and posx and posy and posz then
                    local tile = Tile(posx, posy, posz)
                    if tile then
                        if stackpos == 0 then
                            tile:removeFromMap()
                        end
                        Game.createItem(itemid, count, {x=posx, y=posy, z=posz, stackpos=stackpos})
                    end
                end
            until not result.next(query)
        end
    end)
end

Then you just have to create some talkaction to use it:

Code:
function onSay(player, words, param)
    local tile = Tile(player:getPosition())
    if param == "save" then
        tile:save()
    elseif param == "load" then
        loadSavedTiles()
    elseif param == "unsave" then
        tile:removeSave()
    else
        player:sendTextMessage(MESSAGE_STATUS_SMALL, "You can either save the tile or load all tiles")
    end
    return false
end
In this talkaction when you use !command save it will save the tile you're stepping but when you use !command load it will reload ALL saved tiles.

Edit: Added !command unsave to remove the saved items from the db of the current tile.

And you can add this to the onStartUp to load all tiles when you open the server:
Code:
loadSavedTiles()

SQL Schema to create the "tile_save" table in the db:

Code:
CREATE TABLE `tile_save` (
  `itemid` int(11) NOT NULL,
  `count` int(11) NOT NULL,
  `posx` int(11) NOT NULL,
  `posy` int(11) NOT NULL,
  `posz` int(11) NOT NULL,
  `stackpos` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

OBS: This wont save any item attribute, its just a simple code to save the itemid and count of items in the tile and their pos/stackpos. So don't save tiles if you want to keep their attributes, like actionid, text, etc... cause it will delete it once you load the tiles.

Cheers.
 
Last edited:
Here it is:

Save this to some lib file you can create a new one or put it in any existing one.
Code:
function Tile:removeFromMap()
    local items = self:getItems()
    table.insert(items, self:getGround())
    for i = 1, #items do
        items[i]:remove()
    end
end

function Tile:save()
    if self:getGround() then
        local pos = self:getPosition()
        db.query("DELETE FROM `tile_save` WHERE `posx` = " .. pos.x .. " AND `posy` = " .. pos.y .. " AND `posz` = " .. pos.z .. ";")
        local buffer = {"INSERT INTO `tile_save` (`itemid`, `count`, `posx`, `posy`, `posz`, `stackpos`) VALUES "}
        local items = {self:getGround()}
        local itab = self:getItems()
        for i = #itab, 1, -1 do
            table.insert(items, itab[i])
        end
        for i = 1, #items do
            local item = items[i]
            if i ~= 1 then
                table.insert(buffer, ",")
            end
            table.insert(buffer, string.format("(%d, %d, %d, %d, %d, %d)", item:getId(), item:getCount(), pos.x, pos.y, pos.z, i-1))
        end
        table.insert(buffer, ";")
        db.query(table.concat(buffer))
    end
end

function Tile:removeSave()
   local pos = self:getPosition()
   db.query("DELETE FROM `tile_save` WHERE `posx` = " .. pos.x .. " AND `posy` = " .. pos.y .. " AND `posz` = " .. pos.z .. ";")
end

function loadSavedTiles()
    db.asyncStoreQuery("SELECT * FROM `tile_save` ORDER BY `stackpos` ASC;",
    function(query)
        if query then
            local ret = {}
            repeat
                local itemid, count, posx, posy, posz, stackpos = result.getDataInt(query, "itemid"), result.getDataInt(query, "count"), result.getDataInt(query, "posx"), result.getDataInt(query, "posy"), result.getDataInt(query, "posz"), result.getDataInt(query, "stackpos")
                if itemid and posx and posy and posz then
                    local tile = Tile(posx, posy, posz)
                    if tile then
                        if stackpos == 0 then
                            tile:removeFromMap()
                        end
                        Game.createItem(itemid, count, {x=posx, y=posy, z=posz, stackpos=stackpos})
                    end
                end
            until not result.next(query)
        end
    end)
end

Then you just have to create some talkaction to use it:

Code:
function onSay(player, words, param)
    local tile = Tile(player:getPosition())
    if param == "save" then
        tile:save()
    elseif param == "load" then
        loadSavedTiles()
    elseif param == "unsave" then
        tile:removeSave()
    else
        player:sendTextMessage(MESSAGE_STATUS_SMALL, "You can either save the tile or load all tiles")
    end
    return false
end
In this talkaction when you use !command save it will save the tile you're stepping but when you use !command load it will reload ALL saved tiles.

Edit: Added !command unsave to remove the saved items from the db of the current tile.

And you can add this to the onStartUp to load all tiles when you open the server:
Code:
loadSavedTiles()

SQL Schema to create the "tile_save" table in the db:

Code:
CREATE TABLE `tile_save` (
  `itemid` int(11) NOT NULL,
  `count` int(11) NOT NULL,
  `posx` int(11) NOT NULL,
  `posy` int(11) NOT NULL,
  `posz` int(11) NOT NULL,
  `stackpos` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

OBS: This wont save any item attribute, its just a simple code to save the itemid and count of items in the tile and their pos/stackpos. So don't save tiles if you want to keep their attributes, like actionid, text, etc... cause it will delete it once you load the tiles.

Cheers.
Excellent. Was looking for something similiar to. Thanks :)
 
Here it is:

Save this to some lib file you can create a new one or put it in any existing one.
Code:
function Tile:removeFromMap()
    local items = self:getItems()
    table.insert(items, self:getGround())
    for i = 1, #items do
        items[i]:remove()
    end
end

function Tile:save()
    if self:getGround() then
        local pos = self:getPosition()
        db.query("DELETE FROM `tile_save` WHERE `posx` = " .. pos.x .. " AND `posy` = " .. pos.y .. " AND `posz` = " .. pos.z .. ";")
        local buffer = {"INSERT INTO `tile_save` (`itemid`, `count`, `posx`, `posy`, `posz`, `stackpos`) VALUES "}
        local items = {self:getGround()}
        local itab = self:getItems()
        for i = #itab, 1, -1 do
            table.insert(items, itab[i])
        end
        for i = 1, #items do
            local item = items[i]
            if i ~= 1 then
                table.insert(buffer, ",")
            end
            table.insert(buffer, string.format("(%d, %d, %d, %d, %d, %d)", item:getId(), item:getCount(), pos.x, pos.y, pos.z, i-1))
        end
        table.insert(buffer, ";")
        db.query(table.concat(buffer))
    end
end

function Tile:removeSave()
   local pos = self:getPosition()
   db.query("DELETE FROM `tile_save` WHERE `posx` = " .. pos.x .. " AND `posy` = " .. pos.y .. " AND `posz` = " .. pos.z .. ";")
end

function loadSavedTiles()
    db.asyncStoreQuery("SELECT * FROM `tile_save` ORDER BY `stackpos` ASC;",
    function(query)
        if query then
            local ret = {}
            repeat
                local itemid, count, posx, posy, posz, stackpos = result.getDataInt(query, "itemid"), result.getDataInt(query, "count"), result.getDataInt(query, "posx"), result.getDataInt(query, "posy"), result.getDataInt(query, "posz"), result.getDataInt(query, "stackpos")
                if itemid and posx and posy and posz then
                    local tile = Tile(posx, posy, posz)
                    if tile then
                        if stackpos == 0 then
                            tile:removeFromMap()
                        end
                        Game.createItem(itemid, count, {x=posx, y=posy, z=posz, stackpos=stackpos})
                    end
                end
            until not result.next(query)
        end
    end)
end

Then you just have to create some talkaction to use it:

Code:
function onSay(player, words, param)
    local tile = Tile(player:getPosition())
    if param == "save" then
        tile:save()
    elseif param == "load" then
        loadSavedTiles()
    elseif param == "unsave" then
        tile:removeSave()
    else
        player:sendTextMessage(MESSAGE_STATUS_SMALL, "You can either save the tile or load all tiles")
    end
    return false
end
In this talkaction when you use !command save it will save the tile you're stepping but when you use !command load it will reload ALL saved tiles.

Edit: Added !command unsave to remove the saved items from the db of the current tile.

And you can add this to the onStartUp to load all tiles when you open the server:
Code:
loadSavedTiles()

SQL Schema to create the "tile_save" table in the db:

Code:
CREATE TABLE `tile_save` (
  `itemid` int(11) NOT NULL,
  `count` int(11) NOT NULL,
  `posx` int(11) NOT NULL,
  `posy` int(11) NOT NULL,
  `posz` int(11) NOT NULL,
  `stackpos` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

OBS: This wont save any item attribute, its just a simple code to save the itemid and count of items in the tile and their pos/stackpos. So don't save tiles if you want to keep their attributes, like actionid, text, etc... cause it will delete it once you load the tiles.

Cheers.

Awesome work^^ This gave me an idea, thanks :)
 
Last edited:
Back
Top