Jump to content

setElementData VS triggerServer/ClientEvent


Recommended Posts

Hello, i doubt with choosing setElementData or triggerServerEvent.

As i can see on source code, setElementData is nothing but "OnElementDataChange" event + triggerServerEvent function made in sourcecode by developers themself.

https://code.google.com/p/mtasa-blue/source/browse/trunk/MTA10_Server/mods/deathmatch/logic/CElement.cpp

void CElement::SetCustomData ( const char* szName, const CLuaArgument& Variable, CLuaMain* pLuaMain, bool bSynchronized, CPlayer* pClient, bool bTriggerEvent ) 
{ 
    assert ( szName ); 
    if ( strlen ( szName ) > MAX_CUSTOMDATA_NAME_LENGTH ) 
    { 
        // Don't allow it to be set if the name is too long 
        CLogger::ErrorPrintf ( "Custom data name too long (%s)\n", *SStringX ( szName ).Left ( MAX_CUSTOMDATA_NAME_LENGTH + 1 ) ); 
        return; 
    } 
  
    // Grab the old variable 
    CLuaArgument oldVariable; 
    const SCustomData * pData = m_pCustomData->Get ( szName ); 
    if ( pData ) 
    { 
        oldVariable = pData->Variable; 
    } 
  
    // Set the new data 
    m_pCustomData->Set ( szName, Variable, pLuaMain, bSynchronized ); 
  
    if ( bTriggerEvent ) 
    { 
       [size=6][b] // Trigger the onElementDataChange event on us 
        CLuaArguments Arguments; 
        Arguments.PushString ( szName ); 
        Arguments.PushArgument ( oldVariable ); 
        Arguments.PushArgument ( Variable ); 
        CallEvent ( "onElementDataChange", Arguments, pClient );[/b][/size] 
    } 
} 

My questions

1)If so, even user can make absolutly the same in lua script using tables+register some event like "onCustomMadeDataChangeEvent"+triggerServerEvent/triggerClientEvent functions ?

2) And main: what should i prefer: ready to use "setElementData" or selfmade but doing exactly the same system with triggerServerEvent/triggerClientEvent?

First desire is to use setElementData becouse it made in source via c++.

BUT!

As we can see here

  
CLuaArguments Arguments; 
        Arguments.PushString ( szName ); 
        [b]Arguments.PushArgument ( oldVariable );[/b] 
        Arguments.PushArgument ( Variable ); 
        CallEvent ( "onElementDataChange", Arguments, pClient ); 

Arguments.PushArgument ( oldVariable ); means we transfer old value EVERYTIME to EVERYCLIENT when element data changed?

So, if so, in selfmade triggerServerEvent + arguments i can send only new value value (skip oldValue), saving some bandwidth in each event, each client.

Someone can say that it is not critical, but it means that we save 50% bandwidth.

Did i understand it correctly?

Thanks!

Link to comment

Some new investigation gives answers :)

Looks like setElementData does NOT transfer oldValue.

https://code.google.com/p/mtasa-blue/source/browse/trunk/MTA10/mods/deathmatch/logic/rpc/CElementRPCs.cpp

void CElementRPCs::SetElementData ( CClientEntity* pSource, NetBitStreamInterface& bitStream ) 
{ 
    unsigned short usNameLength; 
    if ( bitStream.ReadCompressed ( usNameLength ) ) 
    { 
        // We should never receive an illegal name length from the server 
        if ( usNameLength > MAX_CUSTOMDATA_NAME_LENGTH ) 
        { 
            CLogger::ErrorPrintf ( "RPC SetElementData name length > MAX_CUSTOMDATA_NAME_LENGTH" ); 
            return; 
        } 
        SString strName; 
        CLuaArgument Argument; 
        if ( bitStream.ReadStringCharacters ( strName, usNameLength ) && Argument.ReadFromBitStream ( bitStream ) ) 
        { 
            pSource->SetCustomData ( strName, Argument, NULL ); 
        } 
    } 
} 

Its just set new value, then triggers on(Client)DataChange event giving to that event new and old value (on that machine where event called).

I still need confirmation and advice...

Link to comment
  • MTA Team

You're correct on what you stated above. onClientElementDataChange won't send the old value, since the client already knows it.

I'd suggest you to use a custom system based upon triggerClientEvent, since element datas have a few issues:

They're synced to everyone

Whenever you change an Elementdata on the server/client the information will be synced to any connected client. This is often not necessary, but simply a waste of bandwidth. Why would a remote player be required to know the exact amount of fuel in a vehicle far away? That information is only useful for the driver of the vehicle, so you'd waste a ton of bandwidth which could be used by MTA for better synchronization.

Anyone can modify them

Without some additional security scripts (which is easily possible, but often overlooked) any client can modify Elementdatas of any element. This allows cheaters with modified clients to cheat themselves various things like money or even admin rights.

Link to comment

Thanks for answer.

Anyone can modify them

Without some additional security scripts (which is easily possible, but often overlooked) any client can modify Elementdatas of any element. This allows cheaters with modified clients to cheat themselves various things like money or even admin rights.

Didnt devepolers fix it in 1.1?

Still can see

addEventHandler('onElementDataChange', root, 
    function(dataName, oldValue ) 
        if getElementType(source)=='player' and checkClient( false, source, 'onElementDataChange', dataName ) then 
            setElementData( source, dataName, oldValue ) 
            return 
        end 
    end 
) 

in admin/server/admin_server.lua. But saw some posts from developers about fixing problem with fake client+setElementData in 1.1 and above. Isnt it correct?

But, basing on wiki, triggerServerEvent can be faked too, like setElementData. In case with triggerServerEvent i still must to control who does that (like in system with setElementData). Does it mean triggerServerEvent does not free me from writing exactly the same (in base) some additional security scripts?

Does that mean that saving bandwidht is only one real reason to use triggerServerOnly not setElementData.

Link to comment

Keep talking to myself :)

I prefer to use custom system based upon triggerClientEvent.

I thought that "setElementData VS trigger*Event" is "bandwidth VS CPU" (in case all another things 100% the same - mean in case i really need to sync data with every client does not matter using trigger*event or setElementData), but...

Using setElementData we not only transfer more bytes, we need to process them, so every byte(packet, message?) needs CPU time. So CPU "argument" suffering too)))

Even trigger*Event force u to write your overcode, debug it, maintain it, even the same already done in setElementData its better way to prefer trigger*Event becouse it let u save bandwith+some CPUtime wasting to deal with that packets (in case you really have possibility to do it in your mode - not everytime its possible, but in 99% cases i think...).

I still need confirmation and advice...

Link to comment
  • MTA Team
Didnt devepolers fix it in 1.1?

There are always new cheats being developed. The Anticheat is constantly updated, but you can never be aware of all cheats out there at all times. You can't ever trust a client.

The security advantage of a custom system based upon event triggers is that by default you do not have an insecure system. With ElementDatas you need to take action to prevent cheaters. With custom event triggers you might as well chose to not allow clients to change certain data by simply not implementing the corresponding events serverside.

Link to comment
  • 1 month later...
They're synced to everyone

Whenever you change an Elementdata on the server/client the information will be synced to any connected client. This is often not necessary, but simply a waste of bandwidth. Why would a remote player be required to know the exact amount of fuel in a vehicle far away? That information is only useful for the driver of the vehicle, so you'd waste a ton of bandwidth which could be used by MTA for better synchronization.

That's why I made this request: http://bugs.mtasa.com/view.php?id=7950

Link to comment
  • Recently Browsing   0 members

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