• 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 Make it work in globalevents cleanning specific area

dervin13

Active Member
Joined
Apr 26, 2008
Messages
458
Solutions
1
Reaction score
28
I get this script in another place and trying to make it work in globalevent, but already chance to function onThink(interval) but not happens...

Can anyone help? It's to clean a specific area thanks

Code:
function cleanmap()
  local configClean = {
    Map = {
      LS = {x = 550, y = 441, z = 7},   -- LIMIT NORT WEST
      LI = {x = 720, y = 346, z = 7}, -- LIMIT SUL EAST
    },
  }
  local ItensIDS = {2148, 2152} -- IDS FOR REMOVE
  for x = configClean.Map.LS.x, configClean.Map.LI.x do
    for y = configClean.Map.LS.y, configClean.Map.LI.y do
      for z = 1, 6 do
        for lista = 1, #ItensIDS do
          local tile = Tile(x, y, z)
          if tile then
            local field = tile:getItemById(ItensIDS[lista])
            if field then
              field:remove()
            end
          end
        end
      end
    end
  end
end
 
Solution
Im getting this error
Lua Script Error: [GlobalEvent Interface]
data/globalevents/scripts/clean.lua:eek:nThink
data/globalevents/scripts/clean.lua:23: attempt to index local 'tile' (a n
umber value)

and with Evil Hero
Lua Script Error: [GlobalEvent Interface]
data/globalevents/scripts/clean.lua:eek:nThink
data/globalevents/scripts/clean.lua:24: attempt to get length of local 'ti
leItems' (a nil value)
Oops, I'm too used to Python. Use the way @Evil Hero showed, manual iteration is much faster.
Lua:
local area = {
    fromPos = Position(300, 300, 7),
    toPos = Position(400, 400, 7)
}

local tileCache = {}

local itemIds = {2148, 2152}

function onThink(interval)
    -- initialize tiles we need to clean, store...
Code:
LS = {x = 550, y = 441, z = 7},   -- LIMIT NORT WEST
LI = {x = 720, y = 346, z = 7}, -- LIMIT SUL EAST
3dZyUxB.png

18:40 You see hunting horn.
Position: [X: 200] [Y: 100] [Z: 6].
--------
18:40 You see a ferumbras doll.
Position: [X: 203] [Y: 103] [Z: 6].
---------------------------
The numbers to the south east should always be larger then the numbers to the north west.
Currently, your south east Y position is lower then the north west Y position..
So the script is going to be doing really really weird shit, or it's not going to work at all.
---
So, fix your positions, and your problem should be fixed.
 
3dZyUxB.png

18:40 You see hunting horn.
Position: [X: 200] [Y: 100] [Z: 6].
--------
18:40 You see a ferumbras doll.
Position: [X: 203] [Y: 103] [Z: 6].
---------------------------
The numbers to the south east should always be larger then the numbers to the north west.
Currently, your south east Y position is lower then the north west Y position..
So the script is going to be doing really really weird shit, or it's not going to work at all.
---
So, fix your positions, and your problem should be fixed.

I put function onThink(interval) at the topo and changed the positions then come this error

[Error - GlobalEvents::think] Failed to execute event: cleantemple
 
I put function onThink(interval) at the topo and changed the positions then come this error

[Error - GlobalEvents::think] Failed to execute event: cleantemple
Post the full current script?
 
Post the full current script?


Code:
function onThink(interval)
  local configClean = {
    Map = {
      LS = {x = 651, y = 541, z = 7},   -- LIMIT NORT WEST
      LI = {x = 670, y = 556, z = 7}, -- LIMIT SUL EAST
    },
  }
  local ItensIDS = {2148, 2152} -- IDS FOR REMOVE
  for x = configClean.Map.LS.x, configClean.Map.LI.x do
    for y = configClean.Map.LS.y, configClean.Map.LI.y do
      for z = 1, 6 do
        for lista = 1, #ItensIDS do
          local tile = Tile(x, y, z)
          if tile then
            local field = tile:getItemById(ItensIDS[lista])
            if field then
              field:remove()
            end
          end
        end
end
end
end
end
 
Code:
function onThink(interval)
  local configClean = {
    Map = {
      LS = {x = 651, y = 541, z = 7},   -- LIMIT NORT WEST
      LI = {x = 670, y = 556, z = 7}, -- LIMIT SUL EAST
    },
  }
  local ItensIDS = {2148, 2152} -- IDS FOR REMOVE
  for x = configClean.Map.LS.x, configClean.Map.LI.x do
    for y = configClean.Map.LS.y, configClean.Map.LI.y do
      for z = 1, 6 do
        for lista = 1, #ItensIDS do
          local tile = Tile(x, y, z)
          if tile then
            local field = tile:getItemById(ItensIDS[lista])
            if field then
              field:remove()
            end
          end
        end
end
end
end
end
Is there nothing above or near this error?
No lines indicating an issue?
 
It's working now thanks

Code:
function onThink(interval)
local area = {
      fromPos = {x = 300, y = 300, z = 7},   
      toPos = {x = 400, y = 400, z = 7}
  }
  local itemIds = {2148, 2152}
    for x = area.fromPos.x, area.toPos.x do
        for y = area.fromPos.y, area.toPos.y do
            for z = area.fromPos.z, area.toPos.z do
                local t = Tile(x, y, z)
                if t and t:getTopDownItem() then
                    for i = 255, 1, -1 do
                        for _ = 1, #itemIds do
                            if t:getTopDownItem():getId() == itemIds[_] then
                                t:getTopDownItem():remove()
                            end
    return true
                        end
                    end
                end
            end
        end
end
end
 
It's working now thanks

Code:
function onThink(interval)
local area = {
      fromPos = {x = 300, y = 300, z = 7},
      toPos = {x = 400, y = 400, z = 7}
  }
  local itemIds = {2148, 2152}
    for x = area.fromPos.x, area.toPos.x do
        for y = area.fromPos.y, area.toPos.y do
            for z = area.fromPos.z, area.toPos.z do
                local t = Tile(x, y, z)
                if t and t:getTopDownItem() then
                    for i = 255, 1, -1 do
                        for _ = 1, #itemIds do
                            if t:getTopDownItem():getId() == itemIds[_] then
                                t:getTopDownItem():remove()
                            end
    return true
                        end
                    end
                end
            end
        end
end
end
That return true is in a very bad spot.
It's going to clean like 1 square then stop.

I'd recommend finding a better method of locating items to remove.. because I feel like this script is going to lag severely.
even the 100 by 100 test area you have is 10,000 tiles.. and then you are looping through every tile 255 times..
10,000 * 255 = 2,550,000 checks.

With that many checks.. even if your server could somehow go through 50,000 checks per millisecond, your server is going to hang and be unable to do anything for 51 millseconds.
And trust me, your server cannot perform 50,000 checks per millisecond. That would be phenomenally fast.

In any case, here's where the return true should be located.
Lua:
local area = {
    fromPos = {x = 300, y = 300, z = 7}, 
    toPos = {x = 400, y = 400, z = 7}
}
local itemIds = {2148, 2152}

function onThink(interval)
    for x = area.fromPos.x, area.toPos.x do
        for y = area.fromPos.y, area.toPos.y do
            for z = area.fromPos.z, area.toPos.z do
                local t = Tile(x, y, z)
                if t and t:getTopDownItem() then
                    for i = 255, 1, -1 do
                        for _ = 1, #itemIds do
                            if t:getTopDownItem():getId() == itemIds[_] then
                                t:getTopDownItem():remove()
                            end
                        end
                    end
                end
            end
        end
    end
    return true
end
 
Last edited:
That return true is in a very bad spot.
It's going to clean like 1 square then stop.

I'd recommend finding a better method of locating items to remove.. because I feel like this script is going to lag severely.
even the 100 by 100 test area you have is 10,000 tiles.. and then you are looping through every tile 255 times..
10,000 * 255 = 2,550,000 checks.

With that many checks.. even if your server could somehow go through 50,000 checks per millisecond, your server is going to hang and be unable to do anything for 51 millseconds.
And trust me, your server cannot perform 50,000 checks per millisecond. That would be phenomenally fast.

In any case, here's where the return true should be located.
Lua:
local area = {
    fromPos = {x = 300, y = 300, z = 7},
    toPos = {x = 400, y = 400, z = 7}
}
local itemIds = {2148, 2152}

function onThink(interval)
    for x = area.fromPos.x, area.toPos.x do
        for y = area.fromPos.y, area.toPos.y do
            for z = area.fromPos.z, area.toPos.z do
                local t = Tile(x, y, z)
                if t and t:getTopDownItem() then
                    for i = 255, 1, -1 do
                        for _ = 1, #itemIds do
                            if t:getTopDownItem():getId() == itemIds[_] then
                                t:getTopDownItem():remove()
                            end
                        end
                    end
                end
            end
        end
    end
    return true
end
Cleaner & faster:
Lua:
local area = {
    fromPos = Position(300, 300, 7),
    toPos = Position(400, 400, 7)
}

local tileCache = {}

local itemIds = {2148, 2152}

function onThink(interval)
    -- initialize tiles we need to clean, store all tiles in a cache to avoid reconstructing them in the future
    if #tileCache == 0 then
        for x = area.fromPos.x, area.toPos.x do
            for y = area.fromPos.y, area.toPos.y do
                for z = area.fromPos.z, area.toPos.z do
                    tileCache[#tileCache+1] = Tile(x, y, z)
                end
            end
        end
    end
    -- clean based off of cache, pairs iterates faster than ipairs
    for tile in pairs(tileCache) do
        for _, item in pairs(tile:getItems()) do
            if table.contains(itemIds, item:getId()) then
                item:remove()
            end
        end
    end
    return true
end
 
Lua:
    -- clean based off of cache, pairs iterates faster than ipairs
    for tile in pairs(tileCache) do
        for _, item in pairs(tile:getItems()) do
            if table.contains(itemIds, item:getId()) then
                item:remove()
            end
        end
    end
    return true
end
actually this is even faster than pairs
Lua:
for i = 1, #tileCache do
    local tileItems = tileCache[i]:getItems()
    for items = 1, #tileItems do
        local item = tileItems[items]    
        if table.contains(itemIds, item:getId()) then
            item:remove()
        end
    end
end
test with 1million loops
yours => 2.747075
mine => 1.945673

It's ofcourse not significant which loop method you use for smaller loops anyway
 
actually this is even faster than pairs
Lua:
for i = 1, #tileCache do
    local tileItems = tileCache[i]:getItems()
    for items = 1, #tileItems do
        local item = tileItems[items]   
        if table.contains(itemIds, item:getId()) then
            item:remove()
        end
    end
end
test with 1million loops
yours => 2.747075
mine => 1.945673

It's ofcourse not significant which loop method you use for smaller loops anyway
Forgot that manual iteration is way faster, very nice.
 
Cleaner & faster:
Lua:
local area = {
    fromPos = Position(300, 300, 7),
    toPos = Position(400, 400, 7)
}

local tileCache = {}

local itemIds = {2148, 2152}

function onThink(interval)
    -- initialize tiles we need to clean, store all tiles in a cache to avoid reconstructing them in the future
    if #tileCache == 0 then
        for x = area.fromPos.x, area.toPos.x do
            for y = area.fromPos.y, area.toPos.y do
                for z = area.fromPos.z, area.toPos.z do
                    tileCache[#tileCache+1] = Tile(x, y, z)
                end
            end
        end
    end
    -- clean based off of cache, pairs iterates faster than ipairs
    for tile in pairs(tileCache) do
        for _, item in pairs(tile:getItems()) do
            if table.contains(itemIds, item:getId()) then
                item:remove()
            end
        end
    end
    return true
end

Im getting this error
Lua Script Error: [GlobalEvent Interface]
data/globalevents/scripts/clean.lua:eek:nThink
data/globalevents/scripts/clean.lua:23: attempt to index local 'tile' (a n
umber value)

and with Evil Hero
Lua Script Error: [GlobalEvent Interface]
data/globalevents/scripts/clean.lua:eek:nThink
data/globalevents/scripts/clean.lua:24: attempt to get length of local 'ti
leItems' (a nil value)
 
Im getting this error
Lua Script Error: [GlobalEvent Interface]
data/globalevents/scripts/clean.lua:eek:nThink
data/globalevents/scripts/clean.lua:23: attempt to index local 'tile' (a n
umber value)

and with Evil Hero
Lua Script Error: [GlobalEvent Interface]
data/globalevents/scripts/clean.lua:eek:nThink
data/globalevents/scripts/clean.lua:24: attempt to get length of local 'ti
leItems' (a nil value)
Oops, I'm too used to Python. Use the way @Evil Hero showed, manual iteration is much faster.
Lua:
local area = {
    fromPos = Position(300, 300, 7),
    toPos = Position(400, 400, 7)
}

local tileCache = {}

local itemIds = {2148, 2152}

function onThink(interval)
    -- initialize tiles we need to clean, store all tiles in a cache to avoid reconstructing them in the future
    if #tileCache == 0 then
        for x = area.fromPos.x, area.toPos.x do
            for y = area.fromPos.y, area.toPos.y do
                for z = area.fromPos.z, area.toPos.z do
                    tileCache[#tileCache+1] = Tile(x, y, z)
                end
            end
        end
    end
    -- clean based off of cache
    for i = 1, #tileCache do
        local items = tileCache[i]:getItems()
        for index = 1, #items do
            local item = items[index]
            if table.contains(itemIds, item:getId()) then
                item:remove()
            end
        end
    end
    return true
end
 
Solution
Oops, I'm too used to Python. Use the way @Evil Hero showed, manual iteration is much faster.
Lua:
local area = {
    fromPos = Position(300, 300, 7),
    toPos = Position(400, 400, 7)
}

local tileCache = {}

local itemIds = {2148, 2152}

function onThink(interval)
    -- initialize tiles we need to clean, store all tiles in a cache to avoid reconstructing them in the future
    if #tileCache == 0 then
        for x = area.fromPos.x, area.toPos.x do
            for y = area.fromPos.y, area.toPos.y do
                for z = area.fromPos.z, area.toPos.z do
                    tileCache[#tileCache+1] = Tile(x, y, z)
                end
            end
        end
    end
    -- clean based off of cache
    for i = 1, #tileCache do
        local items = tileCache[i]:getItems()
        for index = 1, #items do
            local item = items[index]
            if table.contains(itemIds, item:getId()) then
                item:remove()
            end
        end
    end
    return true
end

It's working, but if there's an water placed in the area I get this error
data/globalevents/scripts/clean.lua:24: attempt to get length of local 'ti
leItems' (a nil value)

It's possible to solve or is better to remove this water?
 
Why do you still have a variable named tileItems?
This should make sure an items table exists before iterating over it.
Lua:
local area = {
    fromPos = Position(300, 300, 7),
    toPos = Position(400, 400, 7)
}

local tileCache = {}

local itemIds = {2148, 2152}

function onThink(interval)
    -- initialize tiles we need to clean, store all tiles in a cache to avoid reconstructing them in the future
    if #tileCache == 0 then
        for x = area.fromPos.x, area.toPos.x do
            for y = area.fromPos.y, area.toPos.y do
                for z = area.fromPos.z, area.toPos.z do
                    tileCache[#tileCache+1] = Tile(x, y, z)
                end
            end
        end
    end
    -- clean based off of cache
    for i = 1, #tileCache do
        local items = tileCache[i]:getItems()
        if items and next(items) then
            for index = 1, #items do
                local item = items[index]
                if table.contains(itemIds, item:getId()) then
                    item:remove()
                end
            end
        end
    end
    return true
end
 
Back
Top