Yes, this is that what the title also says, an independent synchronization library for syncing integers. You also could see one that is made by Nestharus and also he used in his new File I/O.
Everything that you might read is in the documentation, I way not like repeating myself And before you start suggesting to put comments everywhere I must note I will likely not do that, if you want to know anything about it just ask me here.
YES, It works online, multiplayer tested. If you got desync problems, and also followed the steps to debug it but you still have problem please contact me here or in PM/VM.
Update:
1.01 -> Setting Queue to "FiFo"
JASS:
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// SYNCHRONIZATION LIBRARY //
// by Geries, also special thanks to Magtheridon96, without him I far not be finished. //
// //
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// What is this? //
// This is a system which is made to synchronize local integers with other players at 100% success and that high //
// as we can reach within warcraft. Most users won't find any way to use this, but others who know preloaders and also //
// know it's possibilities may find this useful. I don't say that this is the best or there will noone make better but //
// right now this part of warcraft is unknown to almost every modder. I don't know if local file saving will have a //
// future, but if it will, then this can be something from the whole thing can get started. //
// //
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// / //
// Pros: - Pretty fast, 2500 integers in 26.8 seconds / *Cons: - May make your scripts extremely laggy during a //
// online. This is more than Nestharus' max / synchronization. If you adjust the configuration //
// speed. ;p / reals you can make sync process slower, but //
// - No data loss because it does synchronization / you can keep your scripts under control. This //
// in more steps. / also highly reduces the chance of a disconnect. //
// - Everything can be converted into integers.* / - If a player loose connection for a while at the //
// - You can have multiple sync tables to use t / data verification part it has a high chance for //
// a time. / disconnection. You can reduce this threat with //
// - You can store unlimited integers. / adjusting intervals, especially the Verification //
// / timeout. It will make sync slower but also safer. //
// *if you have a good string hash conversion stuff then / //
// you can store more than 4 characters into one integer / *We only saw that only a single event has few second //
// Nes: As I remember your record was somewhere at 250 / delay during sync. You can guess what can happen to a //
// character per seconds. Now I have more than 370 :P / keyboard movement system... //
// / //
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// / //
// API: / Use: //
// / //
// static method init takes nothing returns sync / local sync mysync = sync.init( ) //
// - Create an empty sync table. / //
// / //
// method addVal takes string storeCode , integer storedVar returns nothing / call mysync.AddVal( "MyVar" , 12345678 ) //
// - Store your value into sync table. Using storeCode you will be able to / OR //
// retrieve your value after sync. You can only store value before / set mysync["MyVar"] = 12345678 //
// synchronizating. / //
// / //
// method readVal takes string storeCode returns integer / local integer i = mysync.readVal( "MyVar" ) //
// - Retrieving your value after synchronizating. Only work after / OR //
// synchronizating! / local integer i = mysync["MyVar"] //
// / //
// method startSync takes player varOwner , trigger whenRdy returns nothing / call mysync.startSync( Player( 0 ) , Trig ) //
// - Start the synchronization. ALL OTHER PLAYER WILL HAVE SAME VALUES / //
// AFTER SYNCHRONIZATION WITH THE PLAYER YOU SET! Set up a trigger which / //
// will be executed when synchronization is complete and you can read your / //
// data. This process cannot be undone and can't be stopped! / //
// / //
// method flush takes nothing returns nothing / call mysync.flush( ) //
// - Destroys sync table pernamently. / //
// / //
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
library SyncLib2
// Configurations - you can make experimental varies of configures and maybe you can make it even more faster
globals
// After sending final verification data, the system basically do nothing, just let's time for the
// verification data to be synced. If a player can't broadcast the verification data in time will
// get disconnected unless other player has the same data and was able to sync it succesfully.
// If you care more about safety just adjust this value
private constant real Verification_Timeout = 4.5
// Time delay between two data verification period. Changing only this will likely not affect anything.
private constant real Verification_Period = 0.001
// Time delay between two sync period. Reducing this value will result less succesful sync periods.
// This does not cause any threat.
private constant real Sync_Period = 0.05
// Sync table at sync is divided into smaller parts. These parts get synced at every sync period with
// more or less success. Changing this value may result different speeds. This does not cause any threat.
private constant integer Sync_Loop_Size = 50
// Time between synchronization and the start of verification. Reducing this value will result
// less succesful sync periods. This does not cause any threat.
private constant real Sync_Timeout = 1.5
// Enabling host var update will cause that after every sync turn all of the synchronizating player's
// value stored will be updated. I noticed once that while synchronizating the sync player's data stored
// in the gamecache just got zerofied. So because of this I put this option here. It takes pretty much performance
// so just disable if you want to.
private constant boolean Enable_Updating_Host_Var = true
endglobals
struct sync extends array
private gamecache SyncA
private integer SyncC
private player SyncPlayer
private trigger SyncTrigger
private integer SyncPhase
private static boolean Error
private static player Player
private static gamecache Cache
private static integer LofS = 0
private static integer FofS = 0
private static integer LofR = 0
private static sync array Schedule_A
private static sync ON = 0
private static integer SyncStatus
private static constant hashtable VarStorage = InitHashtable( )
// ENGINE
private static method TSSD takes nothing returns nothing
call TriggerSyncStart( )
endmethod
private static method TSRD takes nothing returns nothing
call TriggerSyncReady( )
endmethod
private static method finalv takes nothing returns nothing
if .Error then
call StoreBoolean( .Cache , "A" , "0" , true )
call TriggerSleepAction( 0.0 )
call SyncStoredBoolean( .Cache , "A" , "0" )
else
call FlushStoredBoolean( .Cache , "A" , "0" )
call TriggerSleepAction( 0.0 )
endif
endmethod
private static method verify takes nothing returns nothing
local integer i
local boolean b = false
if GetLocalPlayer( ) != .Player then
if .SyncStatus < Sync_Loop_Size then
set i = 0
else
set i = .SyncStatus - Sync_Loop_Size
endif
loop
set i = i + 1
if not HaveStoredInteger( .Cache , "0" , I2S( i ) ) then
call StoreBoolean( .Cache , I2S( ( .SyncStatus - .ON.SyncC ) / Sync_Loop_Size ) , "0" , true )
set b = true
set .Error = true
exitwhen true
endif
exitwhen i == .SyncStatus
endloop
endif
call ExecuteFunc( sync.TSSD.name )
if b then
call SyncStoredBoolean( .Cache , "A" , I2S( ( .SyncStatus - .ON.SyncC ) / Sync_Loop_Size ) )
endif
call ExecuteFunc( sync.TSRD.name )
endmethod
private static method update takes nothing returns nothing
local integer i = .SyncStatus + 1000
if GetLocalPlayer( ) == .Player then
loop
set .SyncStatus = .SyncStatus + 1
call StoreInteger( .Cache , "0" , I2S( .SyncStatus ) , LoadInteger( .VarStorage , .ON , .SyncStatus ) )
exitwhen .SyncStatus == i or .SyncStatus == .ON.SyncC
endloop
else
set .SyncStatus = .SyncStatus + 1000
if .SyncStatus > .ON.SyncC then
set .SyncStatus = .ON.SyncC
endif
endif
if .SyncStatus != .ON.SyncC then
call ExecuteFunc( sync.update.name )
endif
endmethod
private static method exec takes nothing returns nothing
local integer i
if .SyncStatus < Sync_Loop_Size then
set i = 0
else
set i = .SyncStatus - Sync_Loop_Size
endif
if GetLocalPlayer( ) == .Player then
loop
set i = i + 1
call SyncStoredInteger( .Cache , "0" , I2S( i ) )
exitwhen i == .SyncStatus
endloop
else
call FlushStoredBoolean( .Cache , "A" , I2S( ( .SyncStatus - .ON.SyncC ) / Sync_Loop_Size ) )
endif
endmethod
private static method engine takes nothing returns nothing
local integer i
if .ON.SyncPhase == 2 then
if .SyncStatus <= 0 then
if GetPlayerSlotState( .Player ) == PLAYER_SLOT_STATE_PLAYING then
set .ON.SyncPhase = 3
static if Enable_Updating_Host_Var then
call ExecuteFunc( sync.update.name )
else
set .SyncStatus = .ON.SyncC
endif
set .Error = false
call TimerStart( GetExpiredTimer( ) , Sync_Timeout , false , function sync.engine )
else
set .ON.SyncPhase = 6
call TimerStart( GetExpiredTimer( ) , 0.0 , false , function sync.engine )
endif
return
else
call TimerStart( GetExpiredTimer( ) , Sync_Period , false , function sync.engine )
endif
call ExecuteFunc( sync.TSSD.name )
call ExecuteFunc( sync.exec.name )
call ExecuteFunc( sync.TSRD.name )
set .SyncStatus = .SyncStatus - Sync_Loop_Size
elseif .ON.SyncPhase == 3 then
if .SyncStatus <= 0 then
if GetPlayerSlotState( .Player ) == PLAYER_SLOT_STATE_PLAYING then
set .ON.SyncPhase = 4
call ExecuteFunc( sync.TSSD.name )
call ExecuteFunc( sync.finalv.name )
call ExecuteFunc( sync.TSRD.name )
call TimerStart( GetExpiredTimer( ) , Verification_Timeout , false , function sync.engine )
set .Error = false
else
set .ON.SyncPhase = 6
call TimerStart( GetExpiredTimer( ) , 0.0 , false , function sync.engine )
endif
return
else
call TimerStart( GetExpiredTimer( ) , Verification_Period , false , function sync.engine )
endif
call ExecuteFunc( sync.verify.name )
set .SyncStatus = .SyncStatus - Sync_Loop_Size
elseif .ON.SyncPhase == 4 then
if not .Error then
set .Error = GetStoredBoolean( .Cache , "A" , "0" )
set .SyncStatus = .ON.SyncC
if not .Error then
set .ON.SyncPhase = 5
call TriggerExecute( .ON.SyncTrigger )
if .FofS != 0 then
set .ON = .Schedule_A[.FofS]
set .FofS = .FofS + 1
if .FofS > .LofS then
if LofR != 0 then
set .FofS = 1
set .LofS = .LofR
set .LofR = 0
else
set .FofS = 0
set .LofS = 0
endif
endif
set .SyncStatus = .ON.SyncC
set .Player = .ON.SyncPlayer
set .Cache = .ON.SyncA
call TimerStart( GetExpiredTimer( ) , 0.0 , false , function sync.engine )
else
call DestroyTimer( GetExpiredTimer( ) )
set .ON = 0
endif
return
endif
endif
if GetStoredBoolean( .Cache , "A" , I2S( ( .SyncStatus - .ON.SyncC ) / Sync_Loop_Size ) ) then
call ExecuteFunc( sync.TSSD.name )
call ExecuteFunc( sync.exec.name )
call ExecuteFunc( sync.TSRD.name )
call TimerStart( GetExpiredTimer( ) , Sync_Period , false , function sync.engine )
else
call TimerStart( GetExpiredTimer( ) , 0.0 , false , function sync.engine )
endif
set .SyncStatus = .SyncStatus - Sync_Loop_Size
if .SyncStatus <= 0 then
if GetPlayerSlotState( .Player ) == PLAYER_SLOT_STATE_PLAYING then
set .ON.SyncPhase = 3
static if Enable_Updating_Host_Var then
call ExecuteFunc( sync.update.name )
else
set .SyncStatus = .ON.SyncC
endif
set .Error = false
call FlushStoredMission( .Cache , "A" )
call TimerStart( GetExpiredTimer( ) , Sync_Timeout , false , function sync.engine )
else
set .ON.SyncPhase = 6
call TimerStart( GetExpiredTimer( ) , 0.0 , false , function sync.engine )
endif
endif
elseif .ON.SyncPhase == 7 then
call FlushGameCache( .Cache )
call TimerStart( GetExpiredTimer( ) , 1.5 , false , function sync.engine )
set .ON.SyncPhase = 8
elseif .ON.SyncPhase == 8 then
set .ON.SyncPhase = 0
set .ON.SyncPlayer = null
set .ON.SyncTrigger = null
set .ON.SyncC = 0
set .ON.SyncA = null
set i = LoadInteger( .VarStorage , -1 , 0 ) + 1
call SaveInteger( .VarStorage , -1 , 0 , i )
call SaveInteger( .VarStorage , -1 , i , .ON )
if .FofS != 0 then
set .ON = .Schedule_A[.FofS]
set .FofS = .FofS + 1
if .FofS > .LofS then
if LofR != 0 then
set .FofS = 1
set .LofS = .LofR
set .LofR = 0
else
set .FofS = 0
set .LofS = 0
endif
endif
set .SyncStatus = .ON.SyncC
set .Player = .ON.SyncPlayer
set .Cache = .ON.SyncA
call TimerStart( GetExpiredTimer( ) , 0.0 , false , function sync.engine )
else
call DestroyTimer( GetExpiredTimer( ) )
set .ON = 0
endif
elseif .ON.SyncPhase == 6 then
call FlushGameCache( .Cache )
call TimerStart( GetExpiredTimer( ) , 1.5 , false , function sync.engine )
call FlushChildHashtable( .VarStorage , .ON )
set .ON.SyncPhase = 9
elseif .ON.SyncPhase == 9 then
set .ON.SyncA = InitGameCache( "Sync" + I2S( .ON ) )
set .ON.SyncPhase = 5
call TriggerExecute( .ON.SyncTrigger )
if .FofS != 0 then
set .ON = .Schedule_A[.FofS]
set .FofS = .FofS + 1
if .FofS > .LofS then
if LofR != 0 then
set .FofS = 1
set .LofS = .LofR
set .LofR = 0
else
set .FofS = 0
set .LofS = 0
endif
endif
set .SyncStatus = .ON.SyncC
set .Player = .ON.SyncPlayer
set .Cache = .ON.SyncA
call TimerStart( GetExpiredTimer( ) , 0.0 , false , function sync.engine )
else
call DestroyTimer( GetExpiredTimer( ) )
set .ON = 0
endif
endif
endmethod
// ENDENGINE
method operator []= takes string storeCode , integer storedVar returns nothing
debug if this.SyncPhase != 0 then
if this.SyncPhase == 1 then
set storeCode = storeCode + "x"
if GetStoredInteger( this.SyncA , storeCode , "0" ) == 0 then
set this.SyncC = this.SyncC + 1
call SaveInteger( .VarStorage , this , this.SyncC , storedVar )
call StoreInteger( this.SyncA , storeCode , "0" , this.SyncC )
if storedVar != 0 then
call StoreInteger( this.SyncA , "0" , I2S( this.SyncC ) , storedVar )
endif
debug else
debug call DisplayTimedTextToPlayer( GetLocalPlayer( ) , 0 , 0 , 60 , "|cffff0000[Synchronization]: StoreCode already used.|r" )
endif
debug else
debug call DisplayTimedTextToPlayer( GetLocalPlayer( ) , 0 , 0 , 60 , "|cffff0000[Synchronization]: You can't store new value to this table.|r" )
endif
debug else
debug call DisplayTimedTextToPlayer( GetLocalPlayer( ) , 0 , 0 , 60 , "|cffff0000[Synchronization]: Sync table does not exist|r" )
debug endif
endmethod
method operator [] takes string storeCode returns integer
debug if this.SyncPhase != 0 then
if this.SyncPhase == 5 then
if GetLocalPlayer( ) != this.SyncPlayer then
return GetStoredInteger( this.SyncA , "0" , I2S( GetStoredInteger( SyncA , storeCode + "x" , "0" ) ) )
else
return LoadInteger( .VarStorage , this , GetStoredInteger( this.SyncA , storeCode + "x" , "0" ) )
endif
debug else
debug call DisplayTimedTextToPlayer( GetLocalPlayer( ) , 0 , 0 , 60 , "|cffff0000[Synchronization]: You can't read table now.|r" )
endif
debug else
debug call DisplayTimedTextToPlayer( GetLocalPlayer( ) , 0 , 0 , 60 , "|cffff0000[Synchronization]: Sync table does not exist|r" )
debug endif
return 0
endmethod
method startSync takes player varOwner , trigger executeOnFinish returns nothing
debug if this.SyncPhase != 0 then
if this.SyncPhase == 1 then
if GetPlayerSlotState( varOwner ) == PLAYER_SLOT_STATE_PLAYING and GetPlayerController( varOwner ) == MAP_CONTROL_USER then
set this.SyncPhase = 2
set this.SyncPlayer = varOwner
else
set this.SyncPhase = 6
endif
set this.SyncTrigger = executeOnFinish
if .ON == 0 then
set .ON = this
set .SyncStatus = this.SyncC
set .Player = varOwner
set .Cache = this.SyncA
call TimerStart( CreateTimer( ) , 0.0 , false , function sync.engine )
else
if .LofR > 0 then
set .LofR = .LofR + 1
set .Schedule_A[.LofR] = this
else
if LofS != 8191 then
if .LofS == 0 then
set .FofS = 1
endif
set .LofS = .LofS + 1
set .Schedule_A[.LofS] = this
else
set .LofR = .LofR + 1
set .Schedule_A[.LofR] = this
endif
endif
endif
debug else
debug call DisplayTimedTextToPlayer( GetLocalPlayer( ) , 0 , 0 , 60 , "|cffff0000[Synchronization]: Can't clear sync table now.|r" )
endif
debug else
debug call DisplayTimedTextToPlayer( GetLocalPlayer( ) , 0 , 0 , 60 , "|cffff0000[Synchronization]: Sync table does not exist|r" )
debug endif
endmethod
method addVal takes string storeCode , integer storedVar returns nothing
debug if this.SyncPhase != 0 then
if this.SyncPhase == 1 then
set storeCode = storeCode + "x"
if GetStoredInteger( this.SyncA , storeCode , "0" ) == 0 then
set this.SyncC = this.SyncC + 1
call SaveInteger( .VarStorage , this , this.SyncC , storedVar )
call StoreInteger( this.SyncA , storeCode , "0" , this.SyncC )
if storedVar != 0 then
call StoreInteger( this.SyncA , "0" , I2S( this.SyncC ) , storedVar )
endif
debug else
debug call DisplayTimedTextToPlayer( GetLocalPlayer( ) , 0 , 0 , 60 , "|cffff0000[Synchronization]: StoreCode already used.|r" )
endif
debug else
debug call DisplayTimedTextToPlayer( GetLocalPlayer( ) , 0 , 0 , 60 , "|cffff0000[Synchronization]: You can't store new value to this table.|r" )
endif
debug else
debug call DisplayTimedTextToPlayer( GetLocalPlayer( ) , 0 , 0 , 60 , "|cffff0000[Synchronization]: Sync table does not exist|r" )
debug endif
endmethod
method readVal takes string storeCode returns integer
debug if this.SyncPhase != 0 then
if this.SyncPhase == 5 then
if GetLocalPlayer( ) != this.SyncPlayer then
return GetStoredInteger( this.SyncA , "0" , I2S( GetStoredInteger( SyncA , storeCode + "x" , "0" ) ) )
else
return LoadInteger( .VarStorage , this , GetStoredInteger( this.SyncA , storeCode + "x" , "0" ) )
endif
debug else
debug call DisplayTimedTextToPlayer( GetLocalPlayer( ) , 0 , 0 , 60 , "|cffff0000[Synchronization]: You can't read table now.|r" )
endif
debug else
debug call DisplayTimedTextToPlayer( GetLocalPlayer( ) , 0 , 0 , 60 , "|cffff0000[Synchronization]: Sync table does not exist|r" )
debug endif
return 0
endmethod
method flush takes nothing returns nothing
debug if this.SyncPhase != 0 then
if this.SyncPhase == 1 or this.SyncPhase == 5 then
set this.SyncPhase = 7
if .ON == 0 then
set .ON = this
set .Cache = this.SyncA
call TimerStart( CreateTimer( ) , 0.0 , false , function sync.engine )
else
if .LofR > 0 then
set .LofR = .LofR + 1
set .Schedule_A[.LofR] = this
else
if LofS != 8191 then
if .LofS == 0 then
set .FofS = 1
endif
set .LofS = .LofS + 1
set .Schedule_A[.LofS] = this
else
set .LofR = .LofR + 1
set .Schedule_A[.LofR] = this
endif
endif
endif
debug else
debug call DisplayTimedTextToPlayer( GetLocalPlayer( ) , 0 , 0 , 60 , "|cffff0000[Synchronization]: Can't clear sync table now.|r" )
endif
debug else
debug call DisplayTimedTextToPlayer( GetLocalPlayer( ) , 0 , 0 , 60 , "|cffff0000[Synchronization]: Sync table does not exist|r" )
debug endif
endmethod
static method init takes nothing returns sync
local sync i = LoadInteger( .VarStorage , -1 , 0 )
if i > 0 then
call SaveInteger( .VarStorage , -1 , 0 , i - 1 )
set i = LoadInteger( .VarStorage , -1 , i )
else
set i = LoadInteger( .VarStorage , -1 , -1 ) + 1
if i != 8192 then
call SaveInteger( .VarStorage , -1 , -1 , i )
else
debug call DisplayTimedTextToPlayer( GetLocalPlayer( ) , 0 , 0 , 60 , "|cffff0000[Synchronization]: You reached sync table limit.|r" )
return 0
endif
endif
set i.SyncA = InitGameCache( "Sync" + I2S( i ) )
set i.SyncC = 0
set i.SyncPhase = 1
return i
endmethod
endstruct
endlibrary
YES, It works online, multiplayer tested. If you got desync problems, and also followed the steps to debug it but you still have problem please contact me here or in PM/VM.
Update:
1.01 -> Setting Queue to "FiFo"
Once we made 1250 character per second test with no loss, except Magtheridon got disconnected
Attachments
Last edited: