• 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 Optimization this talkactions.

OTcreator

Well-Known Member
Joined
Feb 14, 2022
Messages
482
Solutions
1
Reaction score
53
Hello!
Possible to optimize this talkaction scripts?

LUA:
local function secondsToReadable(s)
    local hours   = math.floor(s / 3600)
    local minutes = math.floor(math.fmod(s, 3600)/60)
    local seconds = math.floor(math.fmod(s, 60))
    return (hours   > 0 and (hours   .. ' hours ')   or '') ..
           (minutes > 0 and (minutes .. ' minutes ') or '') ..
           (seconds > 0 and (seconds .. ' seconds ') or '')
end

local ImbuementTalk = TalkAction("!imbuements")

function ImbuementTalk.onSay(player, words, param, type)

    local cur_time = os.time()
    local strike_one = player:getStorageValue(12400)
    local strike_two = player:getStorageValue(12401)
    local strike_three = player:getStorageValue(12402)

    local void_one = player:getStorageValue(12403)
    local void_two = player:getStorageValue(12404)
    local void_three = player:getStorageValue(12405)

    local vamp_one = player:getStorageValue(12406)
    local vamp_two = player:getStorageValue(12407)
    local vamp_three = player:getStorageValue(12408)


    if strike_one > cur_time then
        player:sendChannelMessage("Imbuement Strike", "Time to end: " .. os.date('!%Hh %Mm %Ss', strike_one - cur_time) .. ".", TALKTYPE_CHANNEL_O, 15)
    elseif strike_two > cur_time then
        player:sendChannelMessage("Imbuement Strike", "Time to end: " .. os.date('!%Hh %Mm %Ss', strike_two - cur_time) .. ".", TALKTYPE_CHANNEL_O, 15)
    elseif strike_three > cur_time then
        player:sendChannelMessage("Imbuement Strike", "Time to end: " .. os.date('!%Hh %Mm %Ss', strike_three - cur_time) .. ".", TALKTYPE_CHANNEL_O, 15)
    end

    if void_one > cur_time then
        player:sendChannelMessage("Imbuement Void", "Time to end: " .. os.date('!%Hh %Mm %Ss', void_one - cur_time) .. ".", TALKTYPE_CHANNEL_O, 15)
    elseif void_two > cur_time then
        player:sendChannelMessage("Imbuement Void", "Time to end: " .. os.date('!%Hh %Mm %Ss', void_two - cur_time) .. ".", TALKTYPE_CHANNEL_O, 15)
    elseif void_three > cur_time then
        player:sendChannelMessage("Imbuement Void", "Time to end: " .. os.date('!%Hh %Mm %Ss', void_three - cur_time) .. ".", TALKTYPE_CHANNEL_O, 15)
    end
    
    if vamp_one > cur_time then
        player:sendChannelMessage("Imbuement Vampirism", "Time to end: " .. os.date('!%Hh %Mm %Ss', vamp_one - cur_time) .. ".", TALKTYPE_CHANNEL_O, 15)
    elseif vamp_two > cur_time then
        player:sendChannelMessage("Imbuement Vampirism", "Time to end: " .. os.date('!%Hh %Mm %Ss', vamp_two - cur_time) .. ".", TALKTYPE_CHANNEL_O, 15)
    elseif vamp_three > cur_time then
        player:sendChannelMessage("Imbuement Vampirism", "Time to end: " .. os.date('!%Hh %Mm %Ss', vamp_three - cur_time) .. ".", TALKTYPE_CHANNEL_O, 15)
    end
    return false
end

ImbuementTalk:register()
 
LUA:
local imbuements = {
    {name = "Strike", storages = {12400, 12401, 12402}},
    {name = "Void", storages = {12403, 12404, 12405}},
    {name = "Vampirism", storages = {12406, 12407, 12408}}
}

local function secondsToReadable(s)
    local hours   = math.floor(s / 3600)
    local minutes = math.floor(math.fmod(s, 3600) / 60)
    local seconds = math.floor(math.fmod(s, 60))
    return (hours > 0 and (hours .. ' hours ') or '') ..
        (minutes > 0 and (minutes .. ' minutes ') or '') ..
        (seconds > 0 and (seconds .. ' seconds ') or '')
end

local ImbuementTalk = TalkAction("!imbuements")

function ImbuementTalk.onSay(player, words, param, type)
    local cur_time = os.time()
    for _, imbuement in ipairs(imbuements) do
        for _, storage in ipairs(imbuement.storages) do
            local timeRemaining = player:getStorageValue(storage)
            if timeRemaining > cur_time then
                local timeToEnd = timeRemaining - cur_time
                local readableTime = secondsToReadable(timeToEnd)
                player:sendChannelMessage(
                    "Imbuement " .. imbuement.name,
                    "Time to end: " .. readableTime .. ".",
                    TALKTYPE_CHANNEL_O, 15
                )
                break
            end
        end
    end
  
    return false
end

ImbuementTalk:register()
 
LUA:
local imbuements = {
    {name = "Strike", storages = {12400, 12401, 12402}},
    {name = "Void", storages = {12403, 12404, 12405}},
    {name = "Vampirism", storages = {12406, 12407, 12408}}
}

local function secondsToReadable(s)
    local hours   = math.floor(s / 3600)
    local minutes = math.floor(math.fmod(s, 3600) / 60)
    local seconds = math.floor(math.fmod(s, 60))
    return (hours > 0 and (hours .. ' hours ') or '') ..
        (minutes > 0 and (minutes .. ' minutes ') or '') ..
        (seconds > 0 and (seconds .. ' seconds ') or '')
end

local ImbuementTalk = TalkAction("!imbuements")

function ImbuementTalk.onSay(player, words, param, type)
    local cur_time = os.time()
    for _, imbuement in ipairs(imbuements) do
        for _, storage in ipairs(imbuement.storages) do
            local timeRemaining = player:getStorageValue(storage)
            if timeRemaining > cur_time then
                local timeToEnd = timeRemaining - cur_time
                local readableTime = secondsToReadable(timeToEnd)
                player:sendChannelMessage(
                    "Imbuement " .. imbuement.name,
                    "Time to end: " .. readableTime .. ".",
                    TALKTYPE_CHANNEL_O, 15
                )
                break
            end
        end
    end
 
    return false
end

ImbuementTalk:register()
I try optimized, but I have problems with functions: for_ , iPairs etc.
I don't understand this...

Thank you very much.
 
I try optimized, but I have problems with functions: for_ , iPairs etc.
I don't understand this...

Thank you very much.
Alright, here's the same thing with for loops.

LUA:
local imbuements = {
    {name = "Strike", storages = {12400, 12401, 12402}},
    {name = "Void", storages = {12403, 12404, 12405}},
    {name = "Vampirism", storages = {12406, 12407, 12408}}
}

local function secondsToReadable(s)
    local hours   = math.floor(s / 3600)
    local minutes = math.floor(math.fmod(s, 3600) / 60)
    local seconds = math.floor(math.fmod(s, 60))
    return (hours > 0 and (hours .. ' hours ') or '') ..
        (minutes > 0 and (minutes .. ' minutes ') or '') ..
        (seconds > 0 and (seconds .. ' seconds ') or '')
end

local ImbuementTalk = TalkAction("!imbuements")

function ImbuementTalk.onSay(player, words, param, type)
    local cur_time = os.time()
    for i = 1, #imbuements do
        local imbuement = imbuements[i]
        for j = 1, #imbuement.storages do
            local storage = imbuement.storages[j]
            local timeRemaining = player:getStorageValue(storage)
            if timeRemaining > cur_time then
                local timeToEnd = timeRemaining - cur_time
                local readableTime = secondsToReadable(timeToEnd)
                player:sendChannelMessage(
                    "Imbuement " .. imbuement.name,
                    "Time to end: " .. readableTime .. ".",
                    TALKTYPE_CHANNEL_O, 15
                )
                break
            end
        end
    end
    return false
end

ImbuementTalk:register()
 
Alright, here's the same thing with for loops.

LUA:
local imbuements = {
    {name = "Strike", storages = {12400, 12401, 12402}},
    {name = "Void", storages = {12403, 12404, 12405}},
    {name = "Vampirism", storages = {12406, 12407, 12408}}
}

local function secondsToReadable(s)
    local hours   = math.floor(s / 3600)
    local minutes = math.floor(math.fmod(s, 3600) / 60)
    local seconds = math.floor(math.fmod(s, 60))
    return (hours > 0 and (hours .. ' hours ') or '') ..
        (minutes > 0 and (minutes .. ' minutes ') or '') ..
        (seconds > 0 and (seconds .. ' seconds ') or '')
end

local ImbuementTalk = TalkAction("!imbuements")

function ImbuementTalk.onSay(player, words, param, type)
    local cur_time = os.time()
    for i = 1, #imbuements do
        local imbuement = imbuements[i]
        for j = 1, #imbuement.storages do
            local storage = imbuement.storages[j]
            local timeRemaining = player:getStorageValue(storage)
            if timeRemaining > cur_time then
                local timeToEnd = timeRemaining - cur_time
                local readableTime = secondsToReadable(timeToEnd)
                player:sendChannelMessage(
                    "Imbuement " .. imbuement.name,
                    "Time to end: " .. readableTime .. ".",
                    TALKTYPE_CHANNEL_O, 15
                )
                break
            end
        end
    end
    return false
end

ImbuementTalk:register()
Its funny cause he asked for optimization and you just added nested loop. It is not better than his original code (performance wise).
It is shorter and easier to configure, but that's it.
 
Its funny cause he asked for optimization and you just added nested loop. It is not better than his original code (performance wise).
It is shorter and easier to configure, but that's it.
We all know what he wanted. Lol
So I gave him what he wanted instead of what his words portrayed.

-- Edit

But for clarity.. I think this is about as optimized as I can make it, while still keeping it kinda readable.
LUA:
local function formatTimeLeft(time_left)
    local hours = time_left // 3600
    local minutes = (time_left % 3600) // 60
    local seconds = time_left % 60
    return hours .. "h " .. minutes .. "m " .. seconds .. "s"
end

local ImbuementTalk = TalkAction("!imbuements")

function ImbuementTalk.onSay(player, words, param, type)
    local cur_time = os.time()

    local strike_one = player:getStorageValue(12400)
    local strike_two = player:getStorageValue(12401)
    local strike_three = player:getStorageValue(12402)
   
    local void_one = player:getStorageValue(12403)
    local void_two = player:getStorageValue(12404)
    local void_three = player:getStorageValue(12405)
   
    local vamp_one = player:getStorageValue(12406)
    local vamp_two = player:getStorageValue(12407)
    local vamp_three = player:getStorageValue(12408)

    local time_left
    local time_str

    -- Imbuement Strike
    time_left = strike_one > cur_time and strike_one - cur_time or strike_two > cur_time and strike_two - cur_time or strike_three > cur_time and strike_three - cur_time
    if time_left then
        time_str = formatTimeLeft(time_left)
        player:sendChannelMessage("Imbuement Strike", "Time to end: " .. time_str .. ".", TALKTYPE_CHANNEL_O, 15)
    end

    -- Imbuement Void
    time_left = void_one > cur_time and void_one - cur_time or void_two > cur_time and void_two - cur_time or void_three > cur_time and void_three - cur_time
    if time_left then
        time_str = formatTimeLeft(time_left)
        player:sendChannelMessage("Imbuement Void", "Time to end: " .. time_str .. ".", TALKTYPE_CHANNEL_O, 15)
    end

    -- Imbuement Vampirism
    time_left = vamp_one > cur_time and vamp_one - cur_time or vamp_two > cur_time and vamp_two - cur_time or vamp_three > cur_time and vamp_three - cur_time
    if time_left then
        time_str = formatTimeLeft(time_left)
        player:sendChannelMessage("Imbuement Vampirism", "Time to end: " .. time_str .. ".", TALKTYPE_CHANNEL_O, 15)
    end

    return false
end

ImbuementTalk:register()
 
Last edited:
Its funny cause he asked for optimization and you just added nested loop. It is not better than his original code (performance wise).
It is shorter and easier to configure, but that's it.
While I understand what you meant, there's several types of optimizations in computer science.
You can optimize for readability, for space, for time complexity, for parallelism, for data transformation, for data writting, for data reading, for functionalism (functional programming) and, (sight), even for evolution and maintenance.

The code is definetely optimized since it's shorter, more readable, allow for easier maintenance and is actually faster than the previous one. It's not a significant difference to the point of changing the Big O multiplier, but it's definetely faster by avoiding multiple calls of os.date.

I know it's not that important in this scenario where you're only iterating in 3 elements, but a cool trick is to actually cache the methods you're going to use:

date_f = os.date
for i = 1, 43462572 do
date_f(parameters)
end

(Here you have a benchmark for comparison: BenchAcessTables (https://replit.com/@andersonfaaria/BenchAcessTables))

This might sound counterintuive as you're using more memory to allocate the variable but for a big loop the gains are quite expressive.
When you're acessing the os.date you're actually doing 2 calls, one to open the library of os and another to get the method "date".
By caching this "path" directly to the function you're actually reducing to 1 single call and should get about twice as fast performance.
 
Last edited:
I know it's not that important in this scenario where you're only iterating in 3 elements, but a cool trick is to actually cache the methods you're going to use:

date_f = os.date
for i = 1, 43462572 do
date_f(parameters)
end
Yup, this is no that common but very useful, I'm using this method in my Passive Tree where a lot of calculations are made and this speeds up executing (not by a lot but there is a difference).
LUA:
local t_insert = table.insert
local m_pi = math.pi
local m_sin = math.sin
local m_cos = math.cos
local m_tan = math.tan
local m_atan2 = math.atan2
local m_sqrt = math.sqrt
local m_max = math.max

Hey Karen, no wonder everyone hates you.
Awesome.
 

Similar threads

Back
Top