HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Desync through GetCameraTargetPositionLoc() or not?

08-06-2006, 10:53 PM#1
MasterofSickness
Hi again!
I want to use the following, and I'm not sure whether this creates a desync or not:
Trigger:
Custom script: if GetLocalPlayer()==GetTriggerPlayer() then
Custom script: set Loc2=GetCameraTargetPositionLoc()
Custom script: endif

This trigger gives Loc2 the position of the cam of the the triggering player.
Now when I creat any unit at Loc2...
Is the unit created for all players at the same position? namely at Loc2 OR is the unit created at the center of the map for the others players? OR even the unit isn't created for the others?

The problem I have is, that I want to creat a unit if any player presses "escape" at the triggering players cameraposition,
so that when the same player presses esc a 2nd time he will be paned to the created unit and the unit will be deleted.


EDIT1:
Or instead of creating a unit... what is this good for: native CreateCameraSetup
Should I store the location information in a var array for every player so that there won't be a desync conflict?, if there would be a desync...


EDIT2:
Help please...
08-07-2006, 01:47 AM#2
PitzerMike
You'll have to sync the camera target x/y values.
Information on that can be found here: http://www.wc3jass.com/viewtopic.php?t=2676
08-07-2006, 10:15 AM#3
MasterofSickness
Thanks for joining PitzerMike, but I have read this linked thread already before I created this thread...
I reread the thread a 2nd time and now I use this SyncInteger function:

Collapse JASS:
// optimized SyncInteger function for 12 bits
function Sync12BitInteger takes player p, integer unsynced returns integer
  local integer array source_int
  local integer array target_int
  local unit array u
  local integer i = 0
  local group sel = CreateGroup()
  local unit c = null
  local integer synced = 0

  loop // extract the bits
    exitwhen i >= 12
    set source_int[i] = ModuloInteger(unsynced, 2)
    set unsynced = unsynced / 2
    set i = i + 1
  endloop

  set i = 0
  loop // create units to select
    exitwhen i >= 12
    set u[i] = CreateUnit(p, 'nshf', GetStartLocationX(GetPlayerStartLocation(p)), GetStartLocationY(GetPlayerStartLocation(p)), 0)
    set i = i + 1
  endloop

  call SyncSelections() // save old selection
  call GroupEnumUnitsSelected(sel, p, null)

  if (GetLocalPlayer() == p) then
    call ClearSelection()
    set i = 0
    loop // send bits
      exitwhen i >= 12
        if source_int[i] == 0 then
          call SelectUnit(u[i], false)
        else
          call SelectUnit(u[i], true)
        endif
        set i = i + 1
    endloop
  endif
  //call TriggerSleepAction(0)
  call SyncSelections()
  set i = 0
  loop // read bits
    exitwhen i >= 12
    if IsUnitSelected(u[i], p) then
      set target_int[i] = 1
    else
      set target_int[i] = 0
    endif
    set i = i + 1
  endloop

  if (GetLocalPlayer() == p) then
    call ClearSelection()
  endif
  loop  // restore old selection
    set c = FirstOfGroup(sel)
    exitwhen c == null
    if (GetLocalPlayer() == p) then
      call SelectUnit(c, true)
    endif
    call GroupRemoveUnit(sel, c)
  endloop
  call SyncSelections()

  set i = 0
  loop // remove units to select
    exitwhen i >= 12
    call RemoveUnit(u[i])
    set i = i + 1
  endloop

  set i = 11
  loop // rebuild integer
    exitwhen i < 0
    set synced = 2 * synced + target_int[i]
    set i = i - 1
  endloop
  return synced
endfunction

function GetGridId takes real x, real y returns integer
    local real dx = (GetRectMaxX(GetWorldBounds()) - GetRectMinX(GetWorldBounds())) / 64
    local real dy = (GetRectMaxY(GetWorldBounds()) - GetRectMinY(GetWorldBounds())) / 64
    local integer xi = R2I((x - GetRectMinX(GetWorldBounds())) / dx)
    local integer yi = R2I((y - GetRectMinY(GetWorldBounds())) / dy)
    return (yi * 64) + xi
endfunction

function GetGridIdX takes integer id returns real
    local real dx = (GetRectMaxX(GetWorldBounds()) - GetRectMinX(GetWorldBounds())) / 64
    return (ModuloInteger(id, 64) + 0.5) * dx + GetRectMinX(GetWorldBounds())
endfunction

function GetGridIdY takes integer id returns real
    local real dy = (GetRectMaxY(GetWorldBounds()) - GetRectMinY(GetWorldBounds())) / 64
    local integer temp = id / 64
    return (temp + 0.5) * dy + GetRectMinY(GetWorldBounds())
endfunction

function SyncLoc takes player p, location l returns location
    local integer s = Sync12BitInteger(p,GetGridId(GetLocationX(l),GetLocationY(l)))
    local location synced = Location(GetGridIdX(s),GetGridIdY(s))
    call RemoveLocation(l)
    return synced
endfunction

I tested it with 2 players over LAN and for player1 it works almost right
1) When I use these functions I get 7 flying sheeps for short! (selected and also created at the map, which looks horrible)
-> my map can have till 8 human players, so do I get 7 because of that? Actualy I should get arround 12 units as the trigger says...
-> but why do I get sheeps at all??? I want no sheeps *argh*
2) When I try to create a unit for player6 over the location:
Collapse JASS:
local location synced= SyncLoc(GetTriggerPlayer(),GetCameraTargetPositionLoc())
then the unit is created at the bottom left corner of the map always and not at the current camera position!?

A quote from you PitzerMike:
Quote:
You can definitely cut out:

// save old selection
...
//restore old selection


You could also cut out:

// create units to select
...
//remove units to select

But only if you are using units from a preplaced pool to select/check.
You shouldn't mess with SyncSelections.
Question: Well, I have no idea what units from a preplaced pool to select/check are or how to use them instead.
What can I delete from the trigger and what do I have to change and how to have no sheeps and selection?

Ah, and btw: Everytime I read a post of yours Mike I'm getting very hungry!
08-07-2006, 03:48 PM#4
PitzerMike
Of course you will not want to create sheep but an invisible dummy unit instead. So you can replace the 'nshf' in this code line:

Collapse JASS:
set u[i] = CreateUnit(p, 'nshf', GetStartLocationX(GetPlayerStartLocation(p)), GetStartLocationY(GetPlayerStartLocation(p)), 0)

with the unit type id of the invisible dummy unit. Alternatively, as already mentioned you could use preplaced units, then you wouldn't have to create new units whenever you sync a value. To do that you could simply place 12 of your dummy units for each player, save them to an array and then replace the above-shown code line with something like:

Collapse JASS:
 u[i] = udg_yourunitarray[GetPlayerId(p) * 12 + i] 

and remove the loop that kills the selector units at the end of the script
Collapse JASS:
  set i = 0
  loop // remove units to select
    exitwhen i >= 12
    call RemoveUnit(u[i])
    set i = i + 1
  endloop

That way the selector units don't have to be re-created every time.

It can't work for player 6 if only 2 players are in the game. Player 6 won't actually have a camera position if he's not in the game.

EDIT: And please save GetWorldBounds() to a variable at initialization and use that instead of calling GetWorldBounds() over and over, it leaks.
08-07-2006, 04:06 PM#5
MasterofSickness
1)
Quote:
It can't work for player 6 if only 2 players are in the game. Player 6 won't actually have a camera position if he's not in the game.
With player 6 I ment: Player(6) - Orange
So, what I have is:
Player Red (1) is in the game
Player Orange (6) is in the game
(These are the 2 players)
When I use these triggers with (1) then everything is ok
When I use these triggers with (6) then, as said, there is no camera detected

For TriggerPlayer:
Trigger:
Custom script: local location synced= SyncLoc(GetTriggerPlayer(),GetCameraTargetPositionLoc())
This works for Player (1) - Red, but why not for Player (6) - Orange?
GetTriggerPlayer would be Player(5) for Orange... I don't understand the problem.
Every player constantly has any camera position! Or what do I think wrong here...

Anyhow we must have misunderstood us...
-> If I start a game with only 1 player and for that player I choose Player(5) - Orange, then it works again!
So what causes this problem with 2 players?

I FOUND OUT THAT IT ONLY WORKS FOR THE ONE WHO OPENED THE MAP!
I NOW KNOW FROM WHAT FUNC THE PROBLEM COMES,
AND IT IS NO TRIGGER OF MINE!!!
I used this original trigger from AIAndy & PipeDream and the same problem occured (cameraposition of joiners is always at map bottom in the left corner):
Collapse JASS:
function SyncLoc takes player p, location l returns location
    local integer s = Sync12BitInteger(p,GetGridId(GetLocationX(l),GetLocationY(l)))
    local location synced = Location(GetGridIdX(s),GetGridIdY(s))
    call RemoveLocation(l)
    return synced
endfunction

function PingCamera takes player p returns nothing
    local location synced= SyncLoc(p,GetCameraTargetPositionLoc())
    call PingMinimap(GetLocationX(synced),GetLocationY(synced),5.0)
endfunction
(+ the sync function from AIAndy)
This is the point where I seriously need help!
I have no idea what is wrong in these complicated triggers... PitzerMike?
If you don't believe, then try a map with these triggers with 2 players and let the one who joined fire this trigger.

2)
So the units must be selected?
I only ask because you see the selected units very shortly flushing in the menu everytime they get selected.
Hmmm... then what would happen if I give them the ability locust / 'Aloc'?
08-08-2006, 09:59 AM#6
PitzerMike
Quote:
Originally Posted by MasterofSickness
[u][size="4"]
2)
So the units must be selected?
I only ask because you see the selected units very shortly flushing in the menu everytime they get selected.
Hmmm... then what would happen if I give them the ability locust / 'Aloc'?

If you gave them locust the whole thing wouldn't work. Because the system is based on syncing selections.
However, you can simply give them an unselectable dummy model, disable their selection circle (negative height), shadow and minimap display and you'll not notice the selector units any more.

I'm not sure what's wrong for the other players. I'll try to find my original test map in which it worked.

EDIT: Here's the map. It shows that the sync-functions do work.
Attached Files
File type: w3xSync12Bit.w3x (17.0 KB)
08-13-2006, 01:14 PM#7
MasterofSickness
Big thanks for the test map, but I think it also does not work there...

How it should work I think:

1st player presses ESC:
PC of Player(0)
Local index: 2014
Synced index of Player 1: 2014
PC of Player(1)
Local index: 752
Synced index of player 1: 2014
2nd player presses ESC:
PC of Player(1)
Local index: 752
Synced index of player 2: 752
PC of Player(0)
Local index: 2014
Synced index of Player 2: 752

BUT, now, how it actually works:

1st player presses ESC:
PC of Player(0)
Local index: 2014
Synced index of Player 1: 2014
PC of Player(1)
Local index: 752
Synced index of player 1: 2014
2nd player presses ESC:
PC of Player(1)
Local index: 752
Synced index of player 2: 0
PC of Player(0)
Local index: 2014
Synced index of Player 2: 0

So, this Result of 0 is wrong or?
Shouldn't there be the 752?
I used your posted map...
08-13-2006, 01:17 PM#8
Vexorian
try this?

Collapse JASS:
set Loc2=GetCameraTargetPositionLoc()
if GetLocalPlayer()==GetTriggerPlayer() then
   //do stuff with Loc2 variable , but don't do anything that could change the actual gameplay or the count of handles.
endif

GetCameraTargetPositionLoc acts the same as GetLocalPlayer()
08-13-2006, 01:30 PM#9
MasterofSickness
All I want is a little system, that works like this:
When any player presses ESC, then either save the current camera-position of the trigger player or toggle to his saved camera-position if it already exist...

Now, how can I save this camera-position without changing the actual gameplay so that I can check later if it already exist?
08-13-2006, 03:02 PM#10
Vexorian
Well if the saved camera position is not a new location (using MoveLocation) or is a pair of coordinates, and you do not use the saved position for things that affect gameplay, then this should work correctly without desyncs although this is a rather unpredictable area.
08-17-2006, 03:23 PM#11
MasterofSickness
K, inspired from Vex's idea of making an array var that is only used for the respectively player I wrote this trigger:
("udg_BoolAr" is a boolean array from the Var-menue;
"udg_LocAr" is a location array from the Var-menue)
Collapse JASS:
function Trig_Esc_Actions takes nothing returns nothing
    local texttag tt=CreateTextTag()
    local group g=CreateGroup()
    local location Loc1=GetStartLocationLoc(GetPlayerStartLocation(GetTriggerPlayer()))
    local location Loc2=udg_LocAr[GetPlayerId(GetTriggerPlayer())]
    if udg_BoolAr[GetPlayerId(GetTriggerPlayer())]==false then
    // Pan Cam to StartLoc
    set udg_BoolAr[GetPlayerId(GetTriggerPlayer())]=true
    call DisplayTextToForce( GetPlayersAll(), "startloc" )
    if GetLocalPlayer()==GetTriggerPlayer() then
    set udg_LocAr[GetPlayerId(GetTriggerPlayer())]=GetCameraTargetPositionLoc()
    call SetCameraPosition(GetLocationX(Loc1),GetLocationY(Loc1))
    endif
    set g=GetUnitsInRangeOfLocMatching(64,Loc1,null)
    set bj_groupCountUnits=0
    call ForGroup(g, function CountUnitsInGroupEnum)
    if bj_groupCountUnits==1 then
    call SelectUnitForPlayerSingle(FirstOfGroup(g),GetTriggerPlayer())
    endif
    call SetTextTagText(tt,StringCase(GetPlayerName(GetTriggerPlayer()), true) + ",|n|cffC000FF>Escape<|r |cffFF80FFdrücken für letzten Punkt.|r",0.018)
    call SetTextTagPos(tt,GetLocationX(Loc1),GetLocationY(Loc1),10)
    else
    // Pan Cam to LastLoc
    set udg_BoolAr[GetPlayerId(GetTriggerPlayer())]=false
    call DisplayTextToForce( GetPlayersAll(), "lastloc" )
    if GetLocalPlayer()==GetTriggerPlayer() then
    set udg_LocAr[GetPlayerId(GetTriggerPlayer())]=Loc1
    call SetCameraPosition(GetLocationX(Loc2),GetLocationY(Loc2))
    endif
    call SetTextTagText(tt,"|cffC000FF>Escape<|r |cffFF80FFdrücken|num Perspektive zu ändern.|r",0.018)
    call SetTextTagPos(tt,GetLocationX(Loc2),GetLocationY(Loc2),10)
    endif
    call SetTextTagPermanent(tt,false)
    call SetTextTagLifespan(tt,5)
    call SetTextTagVisibility(tt,(GetLocalPlayer()==GetTriggerPlayer()))
    // ClearMemory
    call DestroyGroup(g)
    call RemoveLocation(Loc1)
    call RemoveLocation(Loc2)
    set g=null
    set Loc1=null
    set Loc2=null
    set tt=null
endfunction

//===========================================================================
function InitTrig_Esc takes nothing returns nothing
    set gg_trg_Esc = CreateTrigger(  )
    call TriggerRegisterPlayerEventEndCinematic( gg_trg_Esc, Player(0) )
    call TriggerRegisterPlayerEventEndCinematic( gg_trg_Esc, Player(1) )
    call TriggerRegisterPlayerEventEndCinematic( gg_trg_Esc, Player(2) )
    call TriggerRegisterPlayerEventEndCinematic( gg_trg_Esc, Player(3) )
    call TriggerRegisterPlayerEventEndCinematic( gg_trg_Esc, Player(5) )
    call TriggerRegisterPlayerEventEndCinematic( gg_trg_Esc, Player(6) )
    call TriggerRegisterPlayerEventEndCinematic( gg_trg_Esc, Player(7) )
    call TriggerRegisterPlayerEventEndCinematic( gg_trg_Esc, Player(10) )
    call TriggerAddAction( gg_trg_Esc, function Trig_Esc_Actions )
endfunction

For 1 player it already works quite fine, but I still have to test, if it really doesn't cause desyncs in games with more players...
Perhaps you can give me a few tips whether I should change or correct anything. I would be very glad if some of you have a short look at the trigger.
Thanks!

EDIT:
Please have a look at it...
08-18-2006, 07:51 AM#12
BertTheJasser
I donot get what the fuss is all about. Plx explain again for me.
As far as I understood, you want to create a system that, makes some selection units only selectable for some specific players? Plx reply.

EDIT:
What do you think of hiding the unit for all players except the special player:
Collapse JASS:
call ShowUnit(selector,GetLocalPlayer()==specificplayer)
Not: I do not know if hiding affects the gamplay nor if it causes a desync.
08-18-2006, 08:05 AM#13
MasterofSickness
Quote:
When any player presses ESC, then either save the current camera-position of the trigger player or toggle to his saved camera-position if it already exist...

Hmmm, ok, I try to explain with an example:
1) Player(0)-RED presses ESC for the very 1st time
2) The current CameraView of RED is saved under location A and the camera of RED instantly pans to location B (any preplaced location)
3) Player(0)-RED presses ESC for a 2nd time
4) The camera of RED instantly pans to location A which was saved in "2)"

5) Player(0)-RED presses ESC for a 3rd time
6) The current CameraView of RED is saved under location A and the camera of RED instantly pans to location B (the preplaced location)
.
.
.


I especially want to use this for players who plays my map for the first time.
So, it is said at map start, that when they press ESC, then they will get to their main base. When they press ESC again, they will get back to their last location.


Quote:
As far as I understood, you want to create a system that, makes some selection units only selectable for some specific players?
You mean this vpartv of the trigger?
Collapse JASS:
    set g=GetUnitsInRangeOfLocMatching(64,Loc1,null)
    set bj_groupCountUnits=0
    call ForGroup(g, function CountUnitsInGroupEnum)
    if bj_groupCountUnits==1 then
    call SelectUnitForPlayerSingle(FirstOfGroup(g),GetTriggerPlayer())
    endif
It just should give the triggering player its main base to selection when he pans there and when there is no other unit in range.
08-18-2006, 08:21 AM#14
BertTheJasser
Test it out!
Collapse JASS:
globals
gamecache udg_somecache //must be initialisized
endglobals

function home_x takes integer playerid returns real
return 0. //  the depending players hoe location x
endfunction

function home_y takes integer playerid returns real
return 0. //  the depending players hoe location y
endfunction

function camera_xy takes nothing returns nothing
local player p=GetTriggerPlayer()
local integer i=GetPlayerId(p)
local string s=I2S(i)+"[playerpos]"
// if no stored value, boolean will return false
//this is at the first time important
    if not GetStoredBoolean(udg_somecache,s,"[b]") then
        if GetLocalPlayer()==p then
            call SetCameraPosition(home_x(i),home_y(i))
            // if it does not work, move this part out of the if-then-else
            call StoreReal(udg_somecache,s,"[x]",GetCameraTargetPositionX())
            call StoreReal(udg_somecache,s,"[y]",GetCameraTargetPositionY())
        endif 
        call StoreBoolean(udg_somecache,s,"[b]",true)

    else
        call FlushStoredBoolean(udg_somecache,s,"[b]")
       //will make the func return false, as it is flushed/cleaned
        if GetLocalPlayer()==p then
            call SetCameraPosition(GetStoredReal(udg_somecache,s,"[x]"),GetStoredReal(udg_somecache,s,"[y]"))
        endif
    endif

set p=null
endfunction

function// .... Initalisation of the trigger  ..blabla
//GC initialisation
if udg_somecache==null then
    call FlushGameCache(InitGameCache("somecache"))
    set udg_somecache=InitGameCache("somecache")
endif

If it is true what vex said, this should work

EDIT: Code updated
08-18-2006, 01:17 PM#15
MasterofSickness
Hmmm, I think I get it, but:

1)
with more then 1 player it would not work or?
I mean the integer var "udg_check"...
Mustn't it be an integer array for every player?

2)
how does the gamecache work?...
I get the Storing and GetStore, but doesn't there leak anything?
Don't you have to clean the... oh w8, these are real-values you save to gamecache... so, these are cleared from memory at the end of the trigger automatically? No, that's wrong too, because then you wouldn't store them *argh*
So, these real - values stay in memory... and yes, they also have to stay there, otherwise it would not work,
but what happens when new real values get stored for the same string s for "x" and "y"?
Will the old values just get overwritten or will the old values be lost in memory and there come 2 new values in addition?
Sorry, but with gamecache I have almost no experience...