- Joined
- Jun 23, 2007
- Messages
- 4,066
Uploaded to resource section
JASS Submission Thread
Tested in battle.net with 2 players (high ping) and 32 integers were sent in under a second (thanks to Solu9 for testing)
I wanted to post here before submitting to the spells section. At the core of this there are two libraries, SyncInteger and SyncString. They use selection events to sync values to all players in the map. This has been attempted before with game cache or the trigger sync natives but they were reported to be too slow. I haven't looked at their implementations but my script isn't using any of those natives.
This is useful for many different reasons but the first thing that came to mind was a code-less save / load system. This would offer the ability to carry progress or data between maps (in multiplayer) without having to type in a long code.
Anyway, here are the core libraries used to actually sync the data.
(Code is a WIP)
I tested these libraries using 4 different computers, two of which were on a completely different non-local connection (4G network). All of them had a ping of about 200, yet the data was synced basically instantly. I tested this on W3Arena (simulated battle.net) because I couldn't test four computers simultaneously on battle.net, so if someone could help confirm the speeds on B.NET it would be appreciated.
Here's a simple example:
I also stumbled upon another way to sync integers.
http://www.hiveworkshop.com/forums/pastebin.php?id=36k0u8
Attached below is an example of a codeless save/load system. It's technically not codeless, you just don't have to type anything. I will hopefully upload a much more advanced example to the spells section.
JASS Submission Thread
Tested in battle.net with 2 players (high ping) and 32 integers were sent in under a second (thanks to Solu9 for testing)
I wanted to post here before submitting to the spells section. At the core of this there are two libraries, SyncInteger and SyncString. They use selection events to sync values to all players in the map. This has been attempted before with game cache or the trigger sync natives but they were reported to be too slow. I haven't looked at their implementations but my script isn't using any of those natives.
This is useful for many different reasons but the first thing that came to mind was a code-less save / load system. This would offer the ability to carry progress or data between maps (in multiplayer) without having to type in a long code.
Anyway, here are the core libraries used to actually sync the data.
(Code is a WIP)
JASS:
library SyncInteger initializer Init // requires SyncString
globals
private constant player DUMMY_PLAYER = Player(PLAYER_NEUTRAL_PASSIVE)
private trigger T=CreateTrigger()
private integer LastSynced=0
private player LastPlayer
unit array SyncIntegerDummy
endglobals
function GetSyncedInteger takes nothing returns integer
return LastSynced
endfunction
function GetSyncedPlayer takes nothing returns player
return LastPlayer
endfunction
function OnSyncInteger takes code func returns nothing
call TriggerAddCondition(T, Filter(func))
endfunction
function SyncInteger takes integer playerId, integer number returns boolean
local group g
local unit u
if (number > SYNC_MAX_NUM) then
return false
endif
set g = CreateGroup()
call GroupEnumUnitsSelected(g, Player(playerId), null)
set u = FirstOfGroup(g)
call DestroyGroup(g)
set g = null
if (GetLocalPlayer() == Player(playerId)) then
call ClearSelection()
call SelectUnit(SyncIntegerDummy[number], true)
call ClearSelection()
call SelectUnit(u, true)
endif
set u = null
return true
endfunction
private function OnSelect takes nothing returns boolean
local unit u = GetTriggerUnit()
local player p = GetTriggerPlayer()
local integer id = GetPlayerId(p)
if (SyncIntegerDummy[GetUnitUserData(u)] == u) then
set LastSynced=GetUnitUserData(u)
set LastPlayer=p
call TriggerEvaluate(T)
endif
set u = null
return false
endfunction
private function CreateDummies takes nothing returns nothing
local integer i = 0
static if (LIBRARY_UnitDex) then
set UnitDex.Enabled = false
endif
loop
exitwhen i > SYNC_MAX_NUM
set SyncIntegerDummy[i]=CreateUnit(DUMMY_PLAYER, XE_DUMMY_UNITID, 0, 0, i)
call SetUnitUserData(SyncIntegerDummy[i], i)
set i = i + 1
endloop
static if (LIBRARY_UnitDex) then
set UnitDex.Enabled = true
endif
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
local integer i = 0
loop
call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_SELECTED, null)
set i = i + 1
exitwhen i==bj_MAX_PLAYER_SLOTS
endloop
call TriggerAddCondition(t, Filter(function OnSelect))
call TimerStart(CreateTimer(), 0, false, function CreateDummies)
endfunction
endlibrary
JASS:
library SyncString initializer Init requires SyncInteger
globals
private constant string ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 abcdefghijklmnopqrstuvwxyz.,!?@#$%^&*()-=<>/\\[]{};:'\"`"
constant integer MAX_STRING_LEN = 32
constant string SYNC_TERM_CHAR = "`"
constant integer SYNC_MAX_NUM = StringLength(ALPHABET)
private string array SyncedStr
private boolean array Syncing
private timer array SyncTimer
private integer array SyncCounter
private string Last=""
private trigger E=CreateTrigger()
endglobals
function IsSyncingString takes player p returns boolean
return Syncing[GetPlayerId(p)]
endfunction
function GetSyncedString takes nothing returns string
return Last
endfunction
function OnSyncString takes code func returns nothing
call TriggerAddCondition(E, Filter(func))
endfunction
function I2Char takes integer i returns string
return SubString(ALPHABET, i, i + 1)
endfunction
function Char2I takes string c returns integer
local integer i = 0
local string s
loop
set s = I2Char(i)
exitwhen i > SYNC_MAX_NUM
if (s == c) then
return i
endif
set i = i + 1
endloop
return 0
endfunction
private function OnSyncAction takes nothing returns nothing
local integer pid = GetPlayerId(GetSyncedPlayer())
local string char = I2Char(GetSyncedInteger())
set SyncCounter[pid]=SyncCounter[pid]+1
if (char == SYNC_TERM_CHAR) then
if (SyncCounter[pid] >= MAX_STRING_LEN) then
set Last=SyncedStr[pid]
set Syncing[pid] = false
set SyncedStr[pid] = ""
set SyncCounter[pid]=0
call TriggerEvaluate(E)
endif
else
set SyncedStr[pid] = SyncedStr[pid] + I2Char(GetSyncedInteger())
endif
endfunction
function SyncChar takes integer playerId, string c returns boolean
return SyncInteger(playerId, Char2I(c))
endfunction
function SyncString takes integer pid, string s, integer len returns boolean
local integer i = 0
if (Syncing[pid]) then
return false
endif
set Syncing[pid] = true
loop
exitwhen i > len
call SyncChar(pid, SubString(s, i, i + 1))
set i = i + 1
endloop
call SyncChar(pid, SYNC_TERM_CHAR)
return true
endfunction
private function Init takes nothing returns nothing
local integer i = 0
loop
exitwhen i > 15
set SyncedStr[i]=""
set Syncing[i]=false
set SyncCounter[i]=0
set i = i + 1
endloop
call OnSyncInteger(function OnSyncAction)
endfunction
endlibrary
I tested these libraries using 4 different computers, two of which were on a completely different non-local connection (4G network). All of them had a ping of about 200, yet the data was synced basically instantly. I tested this on W3Arena (simulated battle.net) because I couldn't test four computers simultaneously on battle.net, so if someone could help confirm the speeds on B.NET it would be appreciated.
Here's a simple example:
JASS:
scope Example initializer Init
globals
private boolean array IsSyncExample
endglobals
private function OnRecieveString takes nothing returns boolean
local player p = GetSyncedPlayer()
local string s = GetSyncedString()
local integer pid = GetPlayerId(p)
if (not IsSyncExample[pid]) then
return false
endif
set IsSyncExample[pid] = false
call BJDebugMsg("Recieved \"" + s + "\" from " + GetPlayerName(p))
return false
endfunction
private function OnGameStart takes nothing returns nothing
local player from = Player(0)
local integer pid = GetPlayerId(from)
local string s = ""
if (GetLocalPlayer() == from) then
set s = "Hello"
endif
set IsSyncExample[pid] = true
call SyncString(pid, PopulateString(s), MAX_STRING_LEN) // must define a length
endfunction
private function Init takes nothing returns nothing
call TimerStart(CreateTimer(), 0, false, function OnGameStart)
call OnSyncString(function OnRecieveString)
endfunction
endscope
I also stumbled upon another way to sync integers.
http://www.hiveworkshop.com/forums/pastebin.php?id=36k0u8
Last edited: