• 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!
  • If you're using Gesior 2012 or MyAAC, please review this thread for information about a serious security vulnerability and a fix.

OTClient Change shader onPositionChange(player, newPos, oldPos)

ralke

(҂ ͠❛ ෴ ͡❛)ᕤ
Joined
Dec 17, 2011
Messages
1,202
Solutions
27
Reaction score
671
Location
Santiago - Chile
GitHub
ralke23
Twitch
ralke23
Hi there! There's a script written by oen that shows a message in the window everytime the player changes an area. I wonder if the could be an extra option, that can be enabled or disabled inside the tables, that triggers a change of shader.

Here's the script and the line i'm talking about

This way, inside the table, allow to write types of enviroment (shaders), for example:
Lua:
  {
    from = {x = 1034, y = 1050, z = 6},
    to = {x = 1034, y = 1051, z = 6},
    name = "Orc Fortress"
    biome = "bloom"
  },

So if biome = "bloom" turn on MAP_SHADERS
Lua:
{
    name = 'Map - Bloom',
    frag = 'shaders/fragment/bloom.frag'
},

Reference:

As an extra, only if is possible, whenever you write "none" on name = or biome = it returns and does nothing.
Thanks in advance, Regards! :)
 

margoh

{{ user.title }}
Joined
Apr 1, 2013
Messages
799
Solutions
18
Reaction score
337
It is possible, you just need to use setMapShader(biome) if is in the area and if not set Default shader.
 

4mrcn

tibiaswap.com
Premium User
Joined
Oct 27, 2009
Messages
317
Solutions
11
Reaction score
195
just add it here, that's the part of logic responsible for notification so you can change the shader here as well.

Small tip: avoid having too many areas, otherwise your client will lag every onPositionChange (every step), the guy who wrote the script didn't expect people to add new areas, lol, I hope you didn't pay for it, and if you did - you should definitely bring this up, the issue is here:
 
Last edited:

4mrcn

tibiaswap.com
Premium User
Joined
Oct 27, 2009
Messages
317
Solutions
11
Reaction score
195
The guy is me, I made in in 15min and shared somewhere on OTLand. Lag might happen at around few thousands areas.
Looks like ralke is sitting on around thousand lines right now and I'm not sure if he is that far into development - the lag will happen each step, this is why I suggest that this approach is bad.
 
Last edited:

oen432

Legendary OT User
Joined
Oct 3, 2014
Messages
1,653
Solutions
54
Reaction score
1,779
Location
Poland
GitHub
Oen44
Looks like rake is sitting on around thousand lines right now and I'm not sure if he is that far into development - the lag will happen each step, this is why I suggest that this approach is bad.
At 300, he should be fine for a long time. But yeah, there are 100x better ways to handle this, however as I said, I made this in 15min and didn't bother optimizing for a freaking 32kx32k world with 10k areas.
 
Last edited:

4mrcn

tibiaswap.com
Premium User
Joined
Oct 27, 2009
Messages
317
Solutions
11
Reaction score
195
It's not about "optimizing", it's about choosing the right approach. O(n) on something that you will be extending this way is no go, case closed.
You could, for example, make a key from the position coordinates and have similar solution in O(1).

You should really learn about time complexity and data structures if you plan on becoming a programmer and landing an IT job someday.
 
Last edited:

oen432

Legendary OT User
Joined
Oct 3, 2014
Messages
1,653
Solutions
54
Reaction score
1,779
Location
Poland
GitHub
Oen44
It will be completely unplayable with 10k, so I'm not sure why you are overly exaggerating.
It's not about "optimizing", it's about choosing the right approach. O(n) on something that the user will be extending is no go, case closed.
You could, for example, make a key from the position coordinates and have a solution in O(1) that you can use with 1k areas or more.

You should really learn something about time complexity and data structures if you plan on becoming a programmer and landing an IT job someday.
Pathetic... Making it personal like you know me. If I were to make it professionally then ofc I would choose different approach, I wouldn't even consider making this in a module but server side using proper tree algorithm and handle area change there. But... I DON'T FUCKING CARE.
 
Last edited:

4mrcn

tibiaswap.com
Premium User
Joined
Oct 27, 2009
Messages
317
Solutions
11
Reaction score
195
Pathetic... Making it personal like you know me.
I know you mainly because I had to fix your paid modules too many times
If I were to make it professionally then ofc I would choose different approach, I wouldn't even consider making this in a module but server side using proper tree algorithm and handle area change there. But... I DON'T FUCKING CARE.
Anyway... back to making money.
I guess that was your goal ¯\(ツ)
 
Last edited:
OP
OP
ralke

ralke

(҂ ͠❛ ෴ ͡❛)ᕤ
Joined
Dec 17, 2011
Messages
1,202
Solutions
27
Reaction score
671
Location
Santiago - Chile
GitHub
ralke23
Twitch
ralke23
just add it here, that's the part of logic responsible for notification so you can change the shader here as well.

Small tip: avoid having too many areas, otherwise your client will lag every onPositionChange (every step), the guy who wrote the script didn't expect people to add new areas, lol

Thanks for the advice! Never knew this could lag, I'll do the test with the changes and follow the advice :) Considering this, maybe i'll just use it for a few places. I'll reply back with the tests asap :)

By the way, could be this script a good option to change shader aswell?
It does the change with function toggleSound() not sure if there could be an additional function or if the shader can just get added right there

#offtopic
4mrcn said:
I hope you didn't pay for it, and if you did - you should definitely bring this up, the issue is here[/code]
Fortunately I have never had to pay for a tibia script. It will sound like I'm a leecher but the truth is I always thank for the help and I try to contribute and push intresting changes to the systems I ask for

@oen432 I've always appreciated your helps and systems a lot! Don't bother about writing a system with a professional approach, at least it helped and worked well 👍Anyways I personally think that doing it in a more "professional" way enriches the feedback more and we can all understand more as all this content remains on the web it is always useful for others.
 

4mrcn

tibiaswap.com
Premium User
Joined
Oct 27, 2009
Messages
317
Solutions
11
Reaction score
195
Thanks for the advice! Never knew this could lag, I'll do the test with the changes and follow the advice :) Considering this, maybe i'll just use it for a few places. I'll reply back with the tests asap :)
The issue is the fact that you would iterate over all areas each step - more areas = it takes longer to iterate through them, and it will happen every step.
It takes a few lines and most of your onPositionChange will be done in O(1)
 

oen432

Legendary OT User
Joined
Oct 3, 2014
Messages
1,653
Solutions
54
Reaction score
1,779
Location
Poland
GitHub
Oen44
The issue is the fact that you would iterate over all areas each step - more areas = it takes longer to iterate through them, and it will happen every step.
It takes a few lines and most of your onPositionChange will be done in O(1)
Memory leak.
 
OP
OP
ralke

ralke

(҂ ͠❛ ෴ ͡❛)ᕤ
Joined
Dec 17, 2011
Messages
1,202
Solutions
27
Reaction score
671
Location
Santiago - Chile
GitHub
ralke23
Twitch
ralke23
It is possible, you just need to use setMapShader(biome) if is in the area and if not set Default shader.
I tried to merge @4mrcn code with the game shader function, tried:
Lua:
local areas = {
  {
    from = {x = 1236, y = 880, z = 7},
    to = {x = 1246, y = 880, z = 7},
    name = "Mi'hen Temple"
    biome = "bloom"
  }
}

And
Lua:
function onPositionChange(player, newPos, oldPos)
  local area = smallAreas["Position(" .. newPos.x .. "," .. newPos.y .. "," .. newPos.z .. ")"]
  if not area then
    for _, v in ipairs(bigAreas) do
      if isInArea(newPos, v.from, v.to) then area = v break end
    end
  end

  if not area or currentArea == area.name then
    return
  end

  currentArea = area.name
  print(area.name)
  setMapShader(area.biome)
  nameLabel:setText("Entering " .. area.name)
  window:setWidth(nameLabel:getText():len() * 8)
  g_effects.fadeIn(window, 750)
  if fadeOutEvent then
    removeEvent(fadeOutEvent)
  end
  fadeOutEvent = scheduleEvent(fadeOut, 1000)
end

I really don't think that setMapShader(area.biome) is working, it's my fault since I don't know much .lua
Without changes, the code from @4mrcn worked well, this are the logs I have after changing

Lua:
ERROR: Unable to load module 'game_areas': LUA ERROR: /game_areas/areas.lua:6: '}' expected (to close '{' at line 2) near 'biome'
stack traceback:
    [builtin#142]: at 0x7ff6960be310
    [C]: in function 'autoLoadModules'
    /init.lua:43: in main chunk

Maybe this is really simple and I just don't see it, could be window:setMapShader(area.biome) a better trigger?

Now I have this error :p
Lua:
ERROR: Lua exception: /game_areas/areas.lua:97: attempt to call global 'setMapShader' (a nil value)
stack traceback:
    [C]: in function 'setMapShader'
    /game_areas/areas.lua:97: in function </game_areas/areas.lua:81>
ERROR: protected lua call failed: LUA ERROR:
/game_areas/areas.lua:97: attempt to call global 'setMapShader' (a nil value)
stack traceback:
    [C]: in function 'setMapShader'
    /game_areas/areas.lua:97: in function </game_areas/areas.lua:81>

The code is here, what should I change?
Lua:
local areas = {
  {
    from = {x = 1236, y = 880, z = 7},
    to = {x = 1246, y = 880, z = 7},
    biome = "bloom"
  }
}

local window = nil
local nameLabel = nil
local fadeOutEvent = nil
local currentArea = ""

local smallAreas = {}
local bigAreas = {}

local function cacheArea(area)
  local width = area.to.x - area.from.x + 1
  local height = area.to.y - area.from.y + 1
  local depth = area.to.z - area.from.z + 1
  if width * height * depth > 1000 then
    return table.insert(bigAreas, area)
  end

  for x = area.from.x, area.to.x do
    for y = area.from.y, area.to.y do
      for z = area.from.z, area.to.z do
        -- we cannot guarantee its the same position table
        smallAreas["Position(" .. x .. "," .. y .. "," .. z .. ")"] = area
      end
    end
  end
end

function init()
  for _, area in ipairs(areas) do
    cacheArea(area)
  end
 
  connect(
    g_game,
    {
      onGameStart = create,
      onGameEnd = destroy
    }
  )

  if g_game.isOnline() then
    create()
  end
end

function create()
  --window = g_ui.loadUI("areas", modules.game_interface.getMapPanel())
  --window:setOpacity(0)
  --nameLabel = window:getChildById("name")

  connect(LocalPlayer, {onPositionChange = onPositionChange})
end

local function isInArea(position, fromPos, toPos)
  local x = position.x
  local y = position.y
  local z = position.z
  if z ~= fromPos.z and z ~= toPos.z then
    return false
  end

  if x >= fromPos.x and x <= toPos.x and y >= fromPos.y and y <= toPos.y then
    return true
  end

  return false
end

local function fadeOut()
  g_effects.fadeOut(window, 750)
  fadeOutEvent = nil
end

function onPositionChange(player, newPos, oldPos)
  local area = smallAreas["Position(" .. newPos.x .. "," .. newPos.y .. "," .. newPos.z .. ")"]
  if not area then
    for _, v in ipairs(bigAreas) do
      if isInArea(newPos, v.from, v.to) then area = v break end
    end
  end

  if not area or currentArea == area.name then
    return
  end

  currentArea = area.name
  print(area.name)
  --nameLabel:setText("Entering " .. area.name)
  --window:setWidth(nameLabel:getText():len() * 8)
  setMapShader(area.biome)
  --g_effects.fadeIn(window, 750)
  --if fadeOutEvent then
  --  removeEvent(fadeOutEvent)
  --end
  --fadeOutEvent = scheduleEvent(fadeOut, 1000)
end

function terminate()
  smallAreas = {}
  bigAreas = {}
  disconnect(
    g_game,
    {
      onGameStart = create,
      onGameEnd = destroy
    }
  )
  if window then
    destroy()
  end
end

function destroy()
  disconnect(LocalPlayer, {onPositionChange = onPositionChange})

  if window then
    window:destroy()
    window = nil
  end

  nameLabel = nil
  fadeOutEvent = nil
  currentArea = ""
end

Regards!
 
Last edited:

margoh

{{ user.title }}
Joined
Apr 1, 2013
Messages
799
Solutions
18
Reaction score
337
To be honest, I don't know as I haven't played with shaders. Maybe it is case sensitive, or you need to register and setup shaders like in shaders.lua.
 

4mrcn

tibiaswap.com
Premium User
Joined
Oct 27, 2009
Messages
317
Solutions
11
Reaction score
195
You need to call it on the map panel widget
Lua:
local map = modules.game_interface.getMapPanel()
map:setMapShader(g_shaders.getShader(area.biome))
 
OP
OP
ralke

ralke

(҂ ͠❛ ෴ ͡❛)ᕤ
Joined
Dec 17, 2011
Messages
1,202
Solutions
27
Reaction score
671
Location
Santiago - Chile
GitHub
ralke23
Twitch
ralke23
You need to call it on the map panel widget
Lua:
local map = modules.game_interface.getMapPanel()
map:setMapShader(g_shaders.getShader(area.biome))

I replaced setMapShader(area.biome) for that on line 97, it doesn't show any logs, so I think the syntaxis is correct, but, it doesn't trigger any shader. This is the area I triggered to test.

Lua:
local areas = {
  {
    from = {x = 1232, y = 912, z = 7},
    to = {x = 1241, y = 918, z = 7},
    biome = "bloom"
  }
}

Also used the entrance only
Lua:
local areas = {
  {
    from = {x = 1235, y = 911, z = 7},
    to = {x = 1238, y = 911, z = 7},
    biome = "bloom"
  }
}

1664398462343.png

For onPositionChange used

Lua:
function onPositionChange(player, newPos, oldPos)
  local area = smallAreas["Position(" .. newPos.x .. "," .. newPos.y .. "," .. newPos.z .. ")"]
  if not area then
    for _, v in ipairs(bigAreas) do
      if isInArea(newPos, v.from, v.to) then area = v break end
    end
  end

  if not area or currentArea == area.name then
    return
  end

  currentArea = area.name
  print(area.name)
  --nameLabel:setText("Entering " .. area.name)
  --window:setWidth(nameLabel:getText():len() * 8)
  local map = modules.game_interface.getMapPanel()
  map:setMapShader(g_shaders.getShader(area.biome))
  --g_effects.fadeIn(window, 750)
  --if fadeOutEvent then
  --  removeEvent(fadeOutEvent)
  --end
  --fadeOutEvent = scheduleEvent(fadeOut, 1000)
end

Where should I print to see if the system works? At least to know if the shader change is not working, or if the coordinates are not correctly set.
Btw thanks a lot for your help @4mrcn @margoh, I think i'm missing really minor stuff, but I would really like to make this work 100% :D

Regards!
 
Last edited:
Top