HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Function for Differentiating For Replays (This time I mean it)

07-15-2007, 03:06 AM#1
PandaMine
This time I mean it, it will work in Single and Multiplayer and uses the fact that for replays
1) PauseGame has no effect
2) GetCameraTargetPositionX/GetCameraTargetPositionY and SetCameraPosition have different effects

Since PauseGame has no effect in replays, if you set the CameraPosition while the game is paused, in an actual game the camera will move (when using trigger sleep) however in the replay it wont move, this is easily detectable

NOTE: It will cause a noticable pause, so its a good idea to do this during the loading mechanisms of a map and not during actual game play. As far as I know its the only 100% fool proof way to detect it

Here it is, Thx heaps to Toadcop who mentioned the fact that GetCameraTargetPositionX/GetCameraTargetPositionY acts differently in replays and Captain Griffein for his constant support and remember IMPOSSIBLE IS NOTHING (and no I'm not an official sponsor for Adidas)

Collapse JASS:
function AMHS_IsInGame takes nothing returns boolean
local boolean output
local real currentx = GetCameraTargetPositionX()
local real currenty = GetCameraTargetPositionY()
local real x = currentx + 2
local real y = currenty + 2

call PauseGame(true)
call TriggerSleepAction(0)
call SetCameraPosition(x,y)
call TriggerSleepAction(0)
call PauseGame(false)
if GetCameraTargetPositionX() == x and GetCameraTargetPositionY() == y then
set output = true
else
set output = false
endif
call SetCameraPosition(currentx,currenty)
set currentx = 0
set currenty = 0
set x = 0
set y = 0
return output
endfunction
07-15-2007, 06:26 AM#2
Pyrogasm
As I said in the other thread, this might work also:
Collapse JASS:
globals
    timer IsGameReplay_Timer
endglobals

function IsGameReplay_Child takes nothing returns nothing
    set IsGameReplay_Timer = CreateTimer()
    call TriggerSleepAction(0.00)
    call TimerStart(IsGameReplay_Timer, 1.00, false, null)
    call PauseGame(true)
endfunction    
    
function IsGameReplay takes nothing returns boolean
    local real Time
    call ExecuteFunc("IsGameReplay_Child")
    call TriggerSleepAction(0.50)
    call PauseGame(false)
    set Time = TimerGetElapsed(IsGameReplay_Timer)
    call DestroyTimer(IsGameReplay_Timer)
    return Time > 0.00
endfunction
07-15-2007, 08:05 AM#3
PandaMine
Im going to test it now, however when I did my tests timers are also paused when the game is (even in replays). That was the original method I used to try and detect replays.

EDIT #2 Nope doesnt work, just as I thought. Even timers are paused when the PauseGame native is used so there is no difference between the 2. The ONLY 2 things that are unaffected by PauseGame are camera actions and triggersleepaction
07-15-2007, 08:32 AM#4
Captain Griffen
We're a step closer, but not yet all the way.

It works on battle.net single player. However, if you run it on map initialisation, then you don't get control back. Having any gap means this doesn't occur.

When testing in MP, there is a desync and it returns as a replay.

EDIT: Checked it, and GetCameraTargetX/Y is, as expected, the culprite. You'll need to sync them.
07-15-2007, 09:23 AM#5
Captain Griffen
This works, and has been testing online, multiplayer.

NB: It may screw up if any start locations are very close to x=0, but that isn't the case in Warlords, so it's fine for me.

Credits:

Toadcop - Noticed GetCamera____ differs from game to replay.
PandaMine - Noticed that PauseGame + camera moving could be used to exploit it.
AIAndy - SyncInteger function.
PitzerMike - SyncInteger function optimised for 12 bits.
Captain Griffen - Testing and slight optimisation/finalisation.
Jacek - Testing.

EDIT: This DID work. Now it doesn't. Or I changed it after it worked. Or something. I'll get back to you.

EDIT 2: This works. Double checked.

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


globals
    boolean IsGame
    boolean IsReplay
endglobals

function AMHS_IsInGame takes nothing returns boolean
    local boolean output
    local integer pi = GetPlayerId(GetLocalPlayer())
    local integer x

    call PauseGame(true)
    call TriggerSleepAction(0.)
    call SetCameraPosition(0., 0.)
    call TriggerSleepAction(0.)
    call PauseGame(false)

    set x = R2I(GetCameraTargetPositionX()+0.5)
    set x = Sync12BitInteger(Player(0), x)

    set output = (x==0.)

    call SetCameraPosition(GetStartLocationX(pi), GetStartLocationY(pi))

    return output
endfunction

function Init_AntiMapHack takes nothing returns nothing
    call EnableUserControl(false)

    call TriggerSleepAction(0.)

    set IsGame = AMHS_IsInGame()
    set IsReplay = not(IsGame)

    call EnableUserControl(true)
endfunction
07-15-2007, 10:52 AM#6
PandaMine
Woops, forgot about desync, thanks heaps Captain Griffen.

BTW im about to re-upload into resources AMHS v2.00 with this new function, hopefully all will be well

EDIT here is the link for the resubmit
http://www.wc3campaigns.net/showthread.php?t=95416
07-15-2007, 12:22 PM#7
Toadcop
there are problems with syncing data =\ only with host it works well (i don't know why) maybe cause i got to big latency... you would better test it.
07-15-2007, 01:01 PM#9
Captain Griffen
That function can be used to sync the data from any player, using selections. I arbitarily picked player 0/1. I really suggest no one uses that exact method I posted, since it is a big dodgy as a generic system (fine for Warlords though).
07-15-2007, 02:10 PM#10
PitzerMike
Quote:
Originally Posted by Toadcop
there are problems with syncing data =\ only with host it works well (i don't know why) maybe cause i got to big latency... you would better test it.

Using selections to sync values works fine as far as 12- bits are concerned.
07-15-2007, 02:56 PM#11
Toadcop
lol !
but !
Code:
  ...
  if GetLocalPlayer()==Player(i) then
     call SelectUnit(dummy,true)
  endif
  if IsUnitSelected(dummy,Player(i)) then
     call echo("work !")
  endif
  ...

this code work fine in single player. BUT in mp i doesnt work ! 100% (i have simple create a mp game and played with a computer player) and no meassage appears ! that why i wrote the post above. i donnu but ! i bet it's not only be me so and possibly this algorithm can cause DeSyncs ! so i would be careful.
07-15-2007, 02:58 PM#12
Captain Griffen
The SyncInteger function works.
07-15-2007, 03:09 PM#13
Vexorian
Nothing is impossible.
But there are things that are hardcoded, and on different levels of complexity on how well can we hack the wc3 engine to do them....
07-15-2007, 03:16 PM#14
PitzerMike
Quote:
Originally Posted by Toadcop
lol !
but !
Code:
  ...
  if GetLocalPlayer()==Player(i) then
     call SelectUnit(dummy,true)
  endif
  if IsUnitSelected(dummy,Player(i)) then
     call echo("work !")
  endif
  ...

this code work fine in single player. BUT in mp i doesnt work ! 100% (i have simple create a mp game and played with a computer player) and no meassage appears ! that why i wrote the post above. i donnu but ! i bet it's not only be me so and possibly this algorithm can cause DeSyncs ! so i would be careful.

You seem to misunderstand the concept of multiplayer games. Playing against a computer player doesn't make it a multiplayer game.
A computer player doesn't have his own computer, where an instance of the game runs on. GetLocalPlayer() will return the same player for the computer player and for the player controlled by you.
You also missed the call to SyncSelections -> that means your test code is simply wrong.

And this WORKS and does NOT desync. It has been used in AMAI for years and is thoroughly tested.

Better read the code again, until you understand it.
07-15-2007, 05:29 PM#15
Toadcop
SyncSelections() - aahhh ! i thinked what it's a custom function ^^