- Joined
- Jun 23, 2007
- Messages
- 4,066
Recommended: Sync Library
Demo Map: Codeless Save and Load (Multiplayer)
Core System
Demo Map: Codeless Save and Load (Multiplayer)
Core System
JASS:
library SyncInteger uses optional UnitDex /*or any unit indexer*/, optional GroupUtils, optional xebasic, optional PlayerUtils
/***************************************************************
*
* v1.2.1, by TriggerHappy
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
*
* This library allows you to send integers to all other players through
* unit selections.
*
* _________________________________________________________________________
* 1. Installation
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* Copy the script to your map and save it (requires JassHelper *or* JNGP)
* _________________________________________________________________________
* 2. How it works
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* 1. Creates {DUMMY_COUNT} units and assigns {BASE} of them an integer from 0-{BASE}.
* The 2nd to last dummy is used to signal when the sequence of numbers is over and
* the last dummy signifies a negative number.
*
* 2. Breaks down the number you want to sync to one or more {BASE} integers,
* then selects each dummy unit assoicated with that integer.
*
* 4. The selection event fires for all players when the selection has been sycned
*
* 5. The ID of the selected unit is one of the {BASE} numbers. The current
* total (starts at 0) is multiplied by {BASE} and the latest synced integer is
* added to that. The process will repeat until it selects the 2nd to last dummy,
* and the total is our result.
* _________________________________________________________________________
* 3. Proper Usage
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* - Dummies must be select-able (no locust)
*
* - Run the script in debug mode while testing
*
* _________________________________________________________________________
* 4. Struct API
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* struct SelectionSync
*
* static method create takes nothing returns thistype
*
* method syncValue takes player p, integer number returns boolean
* method destroy takes nothing returns nothing
* _________________________________________________________________________
* 5. Function API
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* function SyncInteger takes player p, integer number returns boolean
*
* function GetSyncedInteger takes nothing returns integer
* function GetSyncedInstance takes nothing returns integer
* function GetSyncedPlayer takes nothing returns player
* function GetSyncedPlayerId takes nothing returns integer
* function IsPlayerSyncing takes player p returns boolean
* function IsPlayerIdSyncing takes integer pid returns boolean
* function IsSyncEnabled takes nothing returns boolean
* function SyncIntegerToggle takes boolean flag returns nothing
* function SyncIntegerEnable takes nothing returns nothing
* function SyncIntegerDisable takes nothing returns nothing
*
* function OnSyncInteger takes filterfunc func returns triggercondition
* function RemoveSyncEvent takes triggercondition action returns nothing
* function TriggerRegisterSyncEvent takes trigger t, integer eventtype returns nothing
*
* function SyncTerminate takes boolean destroyEvent returns nothing
*
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* -http://www.hiveworkshop.com/threads/syncinteger.278674/
*
*/
globals
// create a struct instance for global use
public constant boolean DEFAULT_INSTANCE = true
// owner of the dummy units
public constant player DUMMY_PLAYER = Player(PLAYER_NEUTRAL_PASSIVE)
// Dummy can *not* have locust and must be selectabe.
public constant integer DUMMY_ID = 'hfoo'
// allow debug messages (also requries JassHelper Debug Mode)
public constant boolean ALLOW_DEBUGGING = true
// higher == more dummies but less selections (faster)
public constant integer BASE = 10
// two higher than BASE (jasshelper doesn't allow BASE + 2)
public constant integer DUMMY_COUNT = 12
// endconfig
constant integer EVENT_SYNC_INTEGER = 1
public integer DefaultInstance = 0
private trigger OnSelectTrigger = CreateTrigger()
private trigger EventTrig = CreateTrigger()
private real FireEvent = 0
private group SelectionGroup
private integer LastPlayer
private integer LastSync
private integer LastInstance
private player LocalPlayer
private integer array ActiveSyncs
private real DUMMY_X = 0
private real DUMMY_Y = 0
private integer array DummyInstance
endglobals
function GetSyncedInteger takes nothing returns integer
return LastSync
endfunction
function GetSyncedPlayer takes nothing returns player
return Player(LastPlayer)
endfunction
function GetSyncedInstance takes nothing returns integer
return LastInstance
endfunction
function GetSyncedPlayerId takes nothing returns integer
return LastPlayer
endfunction
function IsPlayerIdSyncing takes integer pid returns boolean
return ActiveSyncs[pid] > 0
endfunction
function IsPlayerSyncing takes player p returns boolean
return ActiveSyncs[GetPlayerId(p)] > 0
endfunction
function IsSyncEnabled takes nothing returns boolean
return IsTriggerEnabled(OnSelectTrigger)
endfunction
function SyncIntegerEnable takes nothing returns nothing
call EnableTrigger(OnSelectTrigger)
endfunction
function SyncIntegerDisable takes nothing returns nothing
call DisableTrigger(OnSelectTrigger)
endfunction
function SyncIntegerToggle takes boolean flag returns nothing
if (flag) then
call EnableTrigger(OnSelectTrigger)
else
call DisableTrigger(OnSelectTrigger)
endif
endfunction
function OnSyncInteger takes filterfunc func returns triggercondition
return TriggerAddCondition(EventTrig, func)
endfunction
function RemoveSyncEvent takes triggercondition action returns nothing
call TriggerRemoveCondition(EventTrig, action)
endfunction
function TriggerRegisterSyncEvent takes trigger t, integer eventtype returns nothing
call TriggerRegisterVariableEvent(t, SCOPE_PREFIX + "FireEvent", EQUAL, eventtype)
endfunction
public function FireEvents takes real eventtype returns nothing
set FireEvent = eventtype
set FireEvent = 0
endfunction
// This function is called when a unit is selected.
private function OnSelect takes nothing returns boolean
local unit u = GetTriggerUnit()
local player p = GetTriggerPlayer()
local integer id = GetPlayerId(p)
local integer udata = GetUnitUserData(u)
local SelectionSync this = DummyInstance[udata]
local boolean isNeg = (this.Dummy[DUMMY_COUNT-1] == u)
local integer index = this.DummyID[udata] - 1
if (this <= 0) then
return false
endif
if (isNeg) then
set this.SyncingValue[id] = this.SyncingValue[id]*-1
endif
if (isNeg or this.Dummy[DUMMY_COUNT-2] == u) then
set ActiveSyncs[id] = ActiveSyncs[id] - 1
// The number is finished syncing, fire the events
set LastPlayer = id
set LastSync = this.SyncingValue[id]
set LastInstance = this
set FireEvent = EVENT_SYNC_INTEGER
call TriggerEvaluate(EventTrig)
// Reset variables
set FireEvent = 0
set this.SyncingValue[id] = -1
else
if (this.SyncingValue[id] == -1) then
set this.SyncingValue[id] = 0
endif
// Build the number we are trying to sync
set this.SyncingValue[id] = this.SyncingValue[id] * BASE + index
endif
set u = null
return false
endfunction
private keyword SyncIntegerInit
// This struct allows us to dynamically create a group of units
// which we can use to synchronize our integer through unit selections.
struct SelectionSync
public unit array Dummy[DUMMY_COUNT]
public integer array DummyID[DUMMY_COUNT]
public integer array SyncingValue[12]
public static method debugger takes boolean b, string s returns nothing
static if (ALLOW_DEBUGGING and DEBUG_MODE) then
if (b) then
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "|c00FF0000" + SCOPE_PREFIX + s + "|r")
endif
endif
endmethod
static method create takes nothing returns thistype
local thistype this = thistype.allocate()
local integer i = 0
local integer uid
debug call .debugger(OnSelectTrigger == null, "[SelectionSync.create()] OnSelectTrigger is null and has no events attached to it.")
debug call .debugger(this.Dummy[0] != null, "[SelectionSync.create()] Dummy not null!")
loop
exitwhen i >= DUMMY_COUNT
set this.Dummy[i] = CreateUnit(DUMMY_PLAYER, DUMMY_ID, DUMMY_X, DUMMY_Y, i)
set uid = GetUnitUserData(this.Dummy[i])
if (uid == 0) then
set uid = ( (this-1) * DUMMY_COUNT ) + (i + 1)
call SetUnitUserData(this.Dummy[i], uid)
endif
debug call .debugger((i == 0) and (this.Dummy[i] == null), "[SelectionSync.create()] Dummy unit is null (check DUMMY_ID).")
debug call .debugger((i == 0) and (GetUnitAbilityLevel(this.Dummy[i], 'Aloc') > 0), "[SelectionSync.create()] Dummy units must be selectable (detected locust).")
set this.DummyID[uid] = i + 1
set DummyInstance[uid] = this
// Make dummy only selectable through triggers
call UnitAddAbility(this.Dummy[i], 'Amrf')
call SetUnitFlyHeight(this.Dummy[i], 5000, 0)
call UnitAddAbility(this.Dummy[i], 'Aeth')
call SetUnitScale(this.Dummy[i], 0, 0, 0)
call PauseUnit(this.Dummy[i], true)
// Hide health bar
call UnitAddAbility(this.Dummy[i], 'Aloc')
call ShowUnit(this.Dummy[i], false)
call UnitRemoveAbility(this.Dummy[i], 'Aloc')
call ShowUnit(this.Dummy[i], true)
set i = i + 1
endloop
return this
endmethod
method syncValue takes player p, integer number returns boolean
local integer x = number
local integer i = 0
local integer d = BASE
local integer j = 0
local integer n = 0
local integer l = 0
local integer playerId = GetPlayerId(p)
local unit u
local unit last
debug call .debugger(OnSelectTrigger == null, "[SelectionSync.syncValue()] OnSelectTrigger is destroyed.")
debug call .debugger(IsSyncEnabled() == false, "[SelectionSync.syncValue()] OnSelectTrigger is disabled.")
if (not IsSyncEnabled()) then
return false
endif
set ActiveSyncs[playerId] = ActiveSyncs[playerId] + 1
// Check if the number is negative
if (number < 0) then
set d = DUMMY_COUNT-1
set number = number * -1
endif
loop
set x = x/(BASE)
exitwhen x==0
set i=i+1
endloop
// Count how many units are selected
call GroupEnumUnitsSelected(SelectionGroup, p, null)
set bj_groupCountUnits = 0
set u = FirstOfGroup(SelectionGroup)
loop
exitwhen u == null
set last = u
call GroupRemoveUnit(SelectionGroup, u)
set bj_groupCountUnits = bj_groupCountUnits + 1
set u = FirstOfGroup(SelectionGroup)
endloop
// If the queue is full, de-select the last unit which
// will allow us to select a dummy, and hopefully
// avoid a flickering effect.
if (bj_groupCountUnits >= 12 and LocalPlayer == p) then
call SelectUnit(last, false)
endif
set j=R2I(Pow(BASE, i))
loop
set n = j
set x = number/n
set j = j / BASE
if (LocalPlayer == p) then
call SelectUnit(this.Dummy[x], true)
call SelectUnit(this.Dummy[x], false)
endif
set number = number-x*n
exitwhen i == 0
set i = i - 1
endloop
if (LocalPlayer == p) then
call SelectUnit(this.Dummy[d], true)
call SelectUnit(this.Dummy[d], false)
if (bj_groupCountUnits >= 12) then
call SelectUnit(last, true)
endif
endif
set u = null
set last = null
return true
endmethod
method destroy takes nothing returns nothing
local integer i = 0
loop
exitwhen i >= DUMMY_COUNT
call RemoveUnit(this.Dummy[i])
set this.Dummy[i] = null
set i = i + 1
endloop
endmethod
implement SyncIntegerInit
endstruct
function SyncInteger takes player p, integer number returns boolean
debug call SelectionSync.debugger(DefaultInstance == 0, "[SyncInteger()] DefaultInstance is not initialized (make sure DEFAULT_INSTANCE is true")
return SelectionSync(DefaultInstance).syncValue(p, number)
endfunction
function SyncTerminate takes boolean destroyEvents returns boolean
local integer i = 0
if (OnSelectTrigger == null and EventTrig == null) then
return false
endif
if (destroyEvents) then
call DestroyTrigger(OnSelectTrigger)
call DestroyTrigger(EventTrig)
set OnSelectTrigger = null
set EventTrig = null
static if not LIBRARY_GroupUtils then
call DestroyGroup(SelectionGroup)
set SelectionGroup = null
endif
else
call SyncIntegerDisable()
endif
if (DefaultInstance > 0) then
call SelectionSync(DefaultInstance).destroy()
endif
return true
endfunction
//===========================================================================
private module SyncIntegerInit
private static method onInit takes nothing returns nothing
local integer i = 0
local integer j
loop
call TriggerRegisterPlayerUnitEvent(OnSelectTrigger, Player(i), EVENT_PLAYER_UNIT_SELECTED, null)
set i = i + 1
exitwhen i==bj_MAX_PLAYER_SLOTS
endloop
call TriggerAddCondition(OnSelectTrigger, Filter(function OnSelect))
static if (LIBRARY_GroupUtils) then
set SelectionGroup=ENUM_GROUP
else
set SelectionGroup=CreateGroup()
endif
static if (LIBRARY_PlayerUtils) then
set LocalPlayer=User.Local
else
set LocalPlayer=GetLocalPlayer()
endif
set DUMMY_X = GetCameraBoundMaxX() + 2000
set DUMMY_Y = GetCameraBoundMaxY() + 2000
static if (DEFAULT_INSTANCE) then
set DefaultInstance = SelectionSync.create()
endif
endmethod
endmodule
endlibrary
Last edited: