Desync Solution When?

Been a month now and still unable to play some of the favorite custom maps that I essentially bought the game for due to desync.
It always happens in certain periods of the game (for example in dota i always desync at around 4 minute mark (6-7mins in match)
No matter which version, so its not up to map.
Other maps which allow use of both reforged and classic do this too.
Only ones that have no real problems are maps that force everyone into classic mode it seems.

This is just ridiculous.

3 Likes

I agree, take a look for theses maps :

They removed the 4on4 map that was Desyncing me, unfortunately it was my favorite 4on4 map

Seems the solution is just to remove every map so no one can get Desynced since they don’t know how to fix anything

1 Like

I’ve been trying to look at Circle TD trollforged, and unfortunately i’m fairly certain I just don’t know enough about the coding to actually make any informed descisions.

The only thing i’ve learned browsing hiveworkshop is that there are certain functions that should not be used unless absolutely neccesary, because they are known for causing desyncs (even before reforged) and some of these maps are using them.

The most common one being getlocalplayer()

If there’s a proper way to use getlocalplayer(), i haven’t been able to find an example, only message upon message saying “DO NOT USE”

That all being said, in trollforged’s case, it seems to be used by some custom library called “The Map Meta Data Library”, which I have very little idea as to the purpose of. I think judging from the variables it might be the leaderboard?

//*  TMMDL
///////////////////////////////////////////////////////////////
/// The Map Meta Data Library
/// Version: v1.00       
/// Last Modified: April 24, 2009
/// Author Chain: Strilanc, [insert next ...]
///////////////////////////////////////////////////////////////
/// This library is used to emit standardized meta data which replay parsers and bot hosts can use to record relevant
/// game statistics like "hero kills" which would otherwise be impossible to record automatically.
///
/// In particular, the flag function can be used to indicate if a leaver should be awarded a win or not. Replays
/// don't contain enough information to easily tell winners who leave from losers who leave. (for example: people
/// who leave while end-game stats are being shown)
///////////////////////////////////////////////////////////////
/// Interface:
///   void FlagPlayer(player, flag_constant)
///   void DefineValue(name, type_constant, goal_constant, suggest_constant)
///   void UpdateValueInt(name, player, operation_constant, value)
///   void UpdateValueReal(name, player, operation_constant, value)
///   void UpdateValueString(name, player, value)
///   void DefineEvent0(name, format)
///   void DefineEvent1(name, format, argName1)
///   void DefineEvent2(name, format, argName1, argName2)
///   void DefineEvent3(name, format, argName1, argName2, argName3)
///   void LogEvent0(name)
///   void LogEvent1(name, arg0)
///   void LogEvent2(name, arg0, arg1)
///   void LogEvent3(name, arg0, arg1, arg2)
///   void LogCustom(unique_identifier, data)
///   void RaiseGuard(reason)
///////////////////////////////////////////////////////////////
/// Notes:
/// - Errors are displayed using BJDebugMsg
/// - Don't try to update a value before defining it
/// - Parsers expect a very specific format, don't screw with the library's output.
/// - If you emit a bunch of data per second, you will cause bandwidth problems for dial-up users. Try to avoid
/// emitting lots of data all at once except at the start and end of games or rounds.
/// - An event's format string uses {#} to represent arguments
/// - Calling RaiseGuard will increase the number of senders for each message from 1 to 3. This increases
/// security but uses more network bandwidth. It is done automatically if tampering is detected.
///////////////////////////////////////////////////////////////

In particular it uses it in:

///Returns true for a fixed size uniform random subset of players in the game
function MMD__isEmitter takes nothing returns boolean
    local integer i= 0
    local integer n= 0
    local integer r
    local integer array picks
    local boolean array pick_flags
    loop
        exitwhen i >= 24
        if GetPlayerController(Player(i)) == MAP_CONTROL_USER and GetPlayerSlotState(Player(i)) == PLAYER_SLOT_STATE_PLAYING then
            if n < MMD__num_senders then //initializing picks
                set picks[n]=i
                set pick_flags[i]=true
            else //maintain the invariant 'P(being picked) = c/n'
                set r=GetRandomInt(0, n)
                if r < MMD__num_senders then
                    set pick_flags[picks[r]]=false
                    set picks[r]=i
                    set pick_flags[i]=true
                endif
            endif
            set n=n + 1
        endif
        set i=i + 1
    endloop
    return pick_flags[GetPlayerId(**GetLocalPlayer()**)]
endfunction

And

///Stores previously sent messages for tamper detection purposes
    function s__MMD__QueueNode_create takes integer id,string msg returns integer
        local integer this= s__MMD__QueueNode__allocate()
        set s__MMD__QueueNode_timeout[this]=(TimerGetElapsed(MMD__clock)) + 7.0 + GetRandomReal(0, 2 + 0.1 * GetPlayerId(**GetLocalPlayer()**)) // INLINED!!
        set s__MMD__QueueNode_msg[this]=msg
        set s__MMD__QueueNode_checksum[this]=MMD__poor_hash(s__MMD__QueueNode_msg[this] , id)
        set s__MMD__QueueNode_key[this]=I2S(id)
        return this
    endfunction
    function s__MMD__QueueNode_onDestroy takes integer this returns nothing
        call FlushStoredInteger(MMD__gc, MMD__M_KEY_VAL + s__MMD__QueueNode_key[this], s__MMD__QueueNode_msg[this])
        call FlushStoredInteger(MMD__gc, MMD__M_KEY_CHK + s__MMD__QueueNode_key[this], s__MMD__QueueNode_key[this])
        set s__MMD__QueueNode_msg[this]=null
        set s__MMD__QueueNode_key[this]=null
        set s__MMD__QueueNode_next[this]=0
    endfunction

Some of it’s functions also say something about “tamper detection purposes”. So basically it’s a fucntion I don’t quite understand the purpose of, using a function that most of the wc3 mapmaking community seems to say should not be used unless absolutely neccesary.

Again I don’t know much about this though, just going on what little I can find. Apparently even Strilac, the guy who made this library, only shows up in a handful of posts on the Hive workshop site.

I also found getlocalplayer being used an extensive amount of times in Warcraft Maul Reimagined (which also has desyncs), but that one uses lua code so I am not sure if it has the same “DO NOT USE” mentality as the JASS version.

So apparently whatever this library does:
*Does not crash the game if it’s turned off
*Uses getlocalplayer() two times every round, and is used on every player at the start of the game
*I cannot immediately notice what this actually does in circle TD trollforged

I might try just turning the library’s initalize trigger off and then see if it has any effect on games.

just tried sheep vs rabbits for the first time and couple of mins in i desynced and dropped out
zzzzzzz

Desync and being disconnected are two different things.

Desync (desynchronization - it’s in the word even) happens when the two computers cannot agree what is happening.
Disconnection happens when the connection is abruptly lost (again, it’s in the word).

What you’re describing is disconnection.

But a desync causes the game to automatically disconnect you from it, so from a player standpoint the end result is the same.

And it’s still likely because of a desync. There’s even some games where the game will flatout say “SUCH AND SUCH PLAYER HAS DESYNC’D” and they will well…be gone.

And if it’s the host who desync’s the game ends altogether.

desync causes disconnect
simple as that

Well, turning off the library didn’t fix that desync issue, going to have to go see what other functions could be doing it…

Try walkable destructables. Try classic only vs reforged only. Try everyone playing at same visual settings.

So don’t ask me how, i’m not sure, but after fiddling with trollforged enough I actually got it open inside world editor. The triggers are even in GUI (except for the custom library)

For anyone who was wondering, found an odd map editor bug. If you have the editor set to default, it shows most models the way you’d expect them, under preset

However, If you force map editor to show everything in SD (classic), the model locations for non-working models is using the custom path to that model.

It seems just forcing it back to the preset fixes these.

That being said, trollforged has no custom models or destructibles. I haven’t checked for any destructible units yet. The only custom file is the splash screen.

This may however give some credence to needing to test Classic/Reforged only. If one version of the map is pointing to preset, but the same version can also be pointing to the direct path…what happens when they aren’t?

Another thought is if one of the attacked units spawns, how do the projectiles react to a unit that has no actual model size.

edit2: Some of the spells are direct pointing to models too

This is the most annoying thing ! I HOPE THEY WILL FIX IT !

1 Like

Apparently Murloc Sorcerer actually has a default pointer to a model classic does not have access to, to the point that switching it to the preset makes the game say it’s custom.

I also found a few buttons pointing to reforged buttons, and they for whatever reason actually seem to show up…don’t think that’s supposed to happen…

Learned the “Supported Modes” option only enforces graphics in the world editor. There’s no way to ensure that only reforged or only classic are in a game for testing. So testing this would rely purely on player trust.

Will probably try turning off the library completely next, but that will require a lot of time to go through and disable all functions the game calls from it.