Jump to content

Detect player dimension change


Mini-Me

Recommended Posts

Hi fellow scripters,

basing on the dimension a player is in I want to use the in MTA 1.3 new functions removeWorldModel and restoreWorldModel, and automatically do that when an other resource changes the player's dimension. Is there an event that gets triggered when a player(/element) changes the dimension? I tried the following code, but if I get it right then that only works with custom data attributes (those ones that are not posX, dimension, etc., for example added with "setElementData ( thePlayer, "tempdata.originalnick", sPlayerNickname )") and it doesn't work:

addEventHandler ( "onClientElementDataChange", getRootElement(), 
function ( dataName, oldValue ) 
    if getElementType ( source ) == "player" and dataName == "dimension" then 
        outputChatBox ( getPlayerName(source).."'s new dimension is "..getElementData (source, "dimension").." and was " .. oldValue .. "!" ) 
    end 
end ) 

Is there an other easy way or will I have to write me a loop that constantly check's an element's dimension to then trigger a custom event?

Thanks for your answers already,

Mini-Me

Link to comment

This?

Client

If you use element data.But idk why you need use element data instead of setElementInterior.

addEvent( "onClientPlayerChangeDimension",true ) 
  
addEventHandler( "onClientPlayerChangeDimension",root, 
    function( new,old ) 
        outputChatBox ( getPlayerName( source ).."'s new dimension is "..tostring( new ).." and was " ..tostring( old ).. "!" ) 
    end 
) 
     
addEventHandler ( "onClientElementDataChange", root, 
    function ( dataName, oldValue ) 
        if getElementType ( source ) == "player" and dataName == "dimension" then 
            triggerEvent( "onClientPlayerChangeDimension",source,getElementData ( source, "dimension" ),oldValue ) 
        end 
    end  
) 
  

Edited by Guest
Link to comment

Dimension change event. Put this script in the resource(s) that handle dimension changes:

_setElementDimension = setElementDimension 
function setElementDimension(player, dimension) 
  local bool = _setElementDimension(player, dimension) 
  if bool then   --this is used to check if the function actually worked before launching our custom event 
     triggerEvent('onPlayerDimensionChange', player, dimension) 
  end 
end 
  
addEvent('onPlayerDimensionChange', true) 
addEventHandler('onPlayerDimensionChange', root, 
function(dimension) 
   outputChatBox(getPlayerName(source).. "'s dimension was changed to: "..dimension) 
end 
) 
  

serverside ^

Link to comment

@Kenix:

That wont work. Like I said, when the "dimension" attribute of an element changes, the event "onClientElementDataChange" is NOT triggered.

@BinSlayer1:

I guess that's my only option then (apart from the loop I mentioned above). I actually wanted to keep resources separate so that if I were to use a foreign resource I don't have to keep changing the scripts when I download an update, but in this special case the other resource is actually mine as well.

Oh, and thank you for the quick answers.

Link to comment
@Kenix:

That wont work. Like I said, when the "dimension" attribute of an element changes, the event "onClientElementDataChange" is NOT triggered.

@BinSlayer1:

I guess that's my only option then (apart from the loop I mentioned above). I actually wanted to keep resources separate so that if I were to use a foreign resource I don't have to keep changing the scripts when I download an update, but in this special case the other resource is actually mine as well.

Oh, and thank you for the quick answers.

If you REALLY REALLY don't wanna put that code in all resources.. then put it in 1 resource and export setElementDimension

and use it like this

exports.nameOfResource:setElementDimension(player, 0)

Link to comment

@Kenix:

For a test I created a new resource. It only contains your code, plus this:

addCommandHandler("dimension", function(commandName, arg1) 
    arg1 = tonumber(arg1) 
    if (arg1 ~= nil) then 
        setElementDimension(getLocalPlayer(), arg1) 
    else 
        outputChatBox("You need to provide a number as argument!") 
    end 
end) 

If I now ingame use the command, my dimension is changed, however I do not get the message from your event handler. Also, there is no error output (that would show up with /debugscript 3).

@BinSlayer1:

That's not the point, it is that I wouldn't want to change the resource at all. Imagine I download a resource from the webpage here. I'd have to edit it each time when there is an update to it. But as there is no other way really, I'll have to use it.

Link to comment

why dont you use a "loop" then? easiest way to detect, isn't it?

-- or 1 in case it fails, but probably wont happen 
local dim = getElementDimension(getLocalPlayer()) or 1 
  
addEvent("onClientPlayerDimensionChange", true) 
addEventHandler("onClientPlayerDimensionChange", getRootElement(), 
function(dimension) 
    outputChatBox("Dimension changed to: "..dimension) 
end) 
  
addEventHandler("onClientRender", getRootElement(), 
function() 
    local _dim = getElementDimension(getLocalPlayer()) 
    if(_dim ~= dim)then 
        dim = _dim 
        triggerEvent("onClientPlayerDimensionChange", getLocalPlayer(), _dim) 
    end 
end) 

Link to comment

@BinSlayer1:

That's not the point, it is that I wouldn't want to change the resource at all. Imagine I download a resource from the webpage here. I'd have to edit it each time when there is an update to it. But as there is no other way really, I'll have to use it.

Sorry but you just sound pretty lazy

Let's face it, there aren't many resources out there that will use a setElementDimension function.. There's probably the admin panel and a couple more. And it's not like they get updated on daily basis, but on monthly/yearly basis really..

Link to comment

You can also keep checking player's dimension in some timer function and trigger the event when it changes. An example:

old_dimension = {} --make an array to store previous dimensions of players 
addEvent("onPlayerDimensionChange", true) 
function checkDimensions() 
    local this_dimension = {} --current dimensions of players 
    local players = getElementsByType("player") 
    for _, player in ipairs(players) do --cycle through all players 
        this_dimension[player] = getElementDimension(player) 
        if this_dimension[player] ~= old_dimension[player] then --if dimension is different than it was 
            triggerEvent("onPlayerDimensionChange", player, old_dimension[player], this_dimension[player]) 
        end 
    end 
    old_dimension = this_dimension --store this_dimension for the next check 
end 
setTimer(checkDimensions, 1000, 0) 

And then you can do:

function showDimensionChange(olddim, newdim) 
    outputChatBox(getPlayerName(source).." went from dimension "..olddim.." to dimension "..newdim..".") 
end 
addEventHandler("onPlayerDimensionChange", root, showDimensionChange) 

Not tested, but it should work. You can make put this code into a new resource. However, you will need to improve it because I only showed you how it should work. For example, if the player who just joined is checked, old_dimension[player] will be nil, therefore different than current dimension, so the event will be triggered. Also, the event isn't triggered instantly, but when dimensions are checked.

Edited by Guest
Link to comment
old_dimension = {} --make an array to store previous dimensions of players 
addEvent("onPlayerDimensionChange", true) 
function checkDimensions() 
    local this_dimension = {} --current dimensions of players 
    local players = getElementsByType("player") 
    for _, player in ipairs(players) do --cycle through all players 
        this_dimension[player] = getElementDimension(player) 
        if this_dimension[player] ~= old_dimension[player] then --if dimension is different than it was 
            triggerEvent("onPlayerDimensionChange", player, old_dimension[player], this_dimension[player]) 
        end 
    end 
    old_dimension = this_dimension --store this_dimension for the next check 
end 
setTimer(checkDimensions, 1000, 0) 

You put getElementPosition instead of getElementDimension at line 7.

Link to comment

@BinSlayer1:

So the software quality characteristic maintainability is just based on laziness?

@arezu and CrystalMV:

Thinking about it again that is actually the better idea, since I also change the palyer's dimension in a second script. I suggested that in my first post to point out that I could've written that myself, but thanks though.

Link to comment
@Kenix:

For a test I created a new resource. It only contains your code, plus this:

addCommandHandler("dimension", function(commandName, arg1) 
    arg1 = tonumber(arg1) 
    if (arg1 ~= nil) then 
        setElementDimension(getLocalPlayer(), arg1) 
    else 
        outputChatBox("You need to provide a number as argument!") 
    end 
end) 

If I now ingame use the command, my dimension is changed, however I do not get the message from your event handler. Also, there is no error output (that would show up with /debugscript 3).

If you use element data.But idk why you need use element data instead of setElementInterior.
addEvent( "onClientPlayerChangeDimension",true ) 
  
addEventHandler( "onClientPlayerChangeDimension",root, 
    function( new,old ) 
        outputChatBox ( getPlayerName( source ).."'s new dimension is "..tostring( new ).." and was " ..tostring( old ).. "!" ) 
    end 
) 
     
addEventHandler ( "onClientElementDataChange", root, 
    function ( dataName, oldValue ) 
        if getElementType ( source ) == "player" and dataName == "dimension" then 
            triggerEvent( "onClientPlayerChangeDimension",source,getElementData ( source, "dimension" ),oldValue ) 
        end 
    end  
) 

Link to comment

This implements a clientside onClientElementDimensionChange event, which triggers whenever the local player's dimension changes. The source of the event is the local player, and it passes two arguments: the current dimension and the last dimension. You could extend this by adding using triggerServerEvent, or even by looping through all streamed in elements and checking their status if isElementSyncer() returns true. That's a bit complicated however.

  
addEvent("onClientElementDimensionChange", true) 
  
local lastDimension = getElementDimension(localPlayer) 
local function processDimensionChanges() 
    local currentDimension = getElementDimension(localPlayer) 
    if currentDimension ~= lastDimension then 
        lastDimension = currentDimension 
        triggerEvent("onClientElementDimensionChange", localPlayer, currentDimension, lastDimension) 
    end 
end 
addEventHandler("onClientRender", root, processDimensionChanges) 
  
-- Example usage: 
  
local function outputDimensionChange(currentDimension, lastDimension) 
    outputChatBox("You have traveled from the "..lastDimension.." to the "..currentDimension.."!", 0, 255, 0) 
end 
addEventHandler("onClientElementDimensionChange", localPlayer, outputDimensionChange) 
  

Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...