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

Save characters without freezing script

onewave1

Member
Joined
May 26, 2021
Messages
90
Reaction score
15
I'm looking for scripts like in thread.
is it possible to create a script that saves characters every xmin without freezing?
Otservbr
TFS1.3
 
goes to data/scripts folder

Code:
local noLagSave = GlobalEvent("noLagSave")
local timeBetweenSaves = 1 * 60 * 60 * 1000 -- in milliseconds
local delayBetweenSaves = 100

function delayedSave(cid)
    local p = Player(cid)
    if p then
        p:save()
    end
end

function noLagSave.onThink(interval, lastExecution)
    local players = Game.getPlayers()
    local delay = 0

    for _, player in ipairs(players) do
        delay = delay + delayBetweenSaves
        addEvent(delayedSave, delay, player:getId())
    end
end

noLagSave:interval(timeBetweenSaves)
noLagSave:register()

if still lagging, increase delay between saves to save the players slower

note: if someone has A LOT of items, like 10k or more, the save of that player may lag anyway (engine limitation)
 
note: if someone has A LOT of items, like 10k or more, the save of that player may lag anyway (engine limitation)
shouldn't TFS' lua interface support doing that in a separete thread? something like game:dispatchAsyncTask? I'm really asking. Haven't touched TFS for years now.
 
shouldn't TFS' lua interface support doing that in a separete thread? something like game:dispatchAsyncTask? I'm really asking. Haven't touched TFS for years now.

The problem is that the saves are all put next to each other in the queue of tasks. Saving players one by one with delays allows server to answer to other tasks as well (such as players moving, spells casting, item moving, etc), thus taking longer to save everyone, but reducing the time in which server is unresponsive.

In normal loop, the server is blocked until it finishes.
 
shouldn't TFS' lua interface support doing that in a separete thread? something like game:dispatchAsyncTask? I'm really asking. Haven't touched TFS for years now.
If you save player in separate thread (with some random delay), he may relog in meantime and clone items. There must be added cache or 'login blocking' for time of items saving,
In normal loop, the server is blocked until it finishes.
There is 6 years old issue on github:

I released there test version of:
1. multithread saving + caching player items in RAM (they must be cached to make multithread work)
2. binary save of items/depots
With my implementation server 'freez time' is just time to copy Item objects in RAM. They are serialized (to SQL format) and send to database in second thread.

Some people used it on their servers for months. There were some item rollback reports - which can duplicate items or remove items from game. As it was super rare and they were not much experienced. We could not find out, if it was problem with 'item cache' or their depots were bigger than default MySQL InnoDB maximum row size (which makes it not save on logout).

Anyway, changing items/depotitems from 'relational' to 'binary' make save of player 30-50 times faster. If saving 10k items depot takes 50 ms on your server, you can make it save in 1-2 ms.
 
Last edited:
steps to reproduce?

players also save on logout
maybe gesior got a point, if while saving players items got saved with log off, and in meanwhile its items being saved, i expect the already saved items from globalevents to be duplicated with the logout, not sure how the save function works
 
maybe gesior got a point, if while saving players items got saved with log off, and in meanwhile its items being saved, i expect the already saved items from globalevents to be duplicated with the logout, not sure how the save function works
I still don't get how that could cause duplication a way other than crashing the server. Logout saves the player too and we can skip the player saving if he's offline.

if you want absolute control over item duplication, you'd have to generate serial codes and remove the duplicates through db queries, but such solution isn't necessary when the server save itself is coded well
 
I still don't get how that could cause duplication a way other than crashing the server. Logout saves the player too and we can skip the player saving if he's offline.

if you want absolute control over item duplication, you'd have to generate serial codes and remove the duplicates through db queries, but such solution isn't necessary when the server save itself is coded well
OTS is like single thread application. 2 things cannot execute in same time. Your script executes 'save' = nobody can login in same time. Player logout cointains code that save player, that's why it gives lag in game, when player has a lot of items. He logouts, it saves for 0.2 sec and nobody can do anything in same time (can't walk, use spell, monsters do not move).
That gives lag on save, but also makes programming much easier.

How to clone items with 'delayed save' (asynchronous):
1. Logout - it saves items with delay, so they may save in same milisecond or 0.5 sec later, if there are other items to save in same time
2. Login - if it did not save yet, it will load old items from database, from previous save
So you need some cache for items - to do not load them from database on login - or block possiblity to login, if there are items waiting for save.
 
Oh, you were speaking about the async you coded. Thought you're referring to the script I posted, sorry. That makes sense now.

I'd solve that problem another way. I'd limit player depot to 10k items, player equipment to another 10k items, mailbox to 10k items and moveable items placed on house tiles to 8 (the client doesn't display more anyway). Items in house containers could also be limited to some number.

The player trying to mail the guy with full inbox would get his parcel throw attempt blocked with some cancel message that the other guy's inbox is full.
The items that HAVE to be sent (like boss rewards or house items returning to depot) could be stored in some player_pendingitems sql table.

If there are items in that table, the player would see a notification when logging in and when there are free slots in his inbox, the items would be moved there.

Also to prevent spam, a daily/weekly limit to parcel/letter actions per account/ip could be added.

This all would prevent each player from having more than 30k items loaded with them on relog.
 
Oh, estabas hablando sobre el asíncrono que codificaste. Pensé que te referías al guión que publiqué, lo siento. Eso tiene sentido ahora.

Resolvería ese problema de otra manera. Limitaría el depósito del jugador a 10k elementos, el equipo del jugador a otros 10k elementos, el buzón a 10k elementos y los elementos móviles colocados en mosaicos de casas a 8 (el cliente no muestra más de todos modos). Los artículos en los contenedores de la casa también podrían limitarse a una cierta cantidad.

El jugador que intentara enviarle un correo al tipo con la bandeja de entrada llena vería bloqueado su intento de lanzamiento de paquete con algún mensaje de cancelación que indica que la bandeja de entrada del otro tipo está llena.
Los artículos que DEBEN enviarse (como recompensas de jefes o artículos de la casa que regresan al depósito) podrían almacenarse en alguna tabla sql player_pendingitems.

Si hay elementos en esa tabla, el jugador verá una notificación al iniciar sesión y cuando haya espacios libres en su bandeja de entrada, los elementos se moverán allí.

También para evitar el spam, se podría agregar un límite diario/semanal de acciones de paquetes/cartas por cuenta/ip.

Todo esto evitaría que cada jugador tenga más de 30k elementos cargados con ellos al volver a iniciar sesión.
hello I have the same problem on my server, in Depot/Imbox after page 10 they start to duplicate the items.
 
Back
Top