• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Speed Hack Detection v1.1 [GUI Friendly]

A highly recommended system for any ORPG map (or any other) that uses save/load codes and needs to keep it away from speed hackers. No map is safe from cheating even by restricting certain save data to only load in LAN and online mode. Now with this system, you can at least prevent one of those cheats: speedhack.

The system allows you to detect speed hacking activity in your map either in single player, LAN, or online mode. As well as letting you decide what to do about it.

System Codes

JASS:
    // ********************************************************
    //
    //     Speed Hack Detection v1.1
    //
    // ---------------------------------------------------
    //
    // Detects when a player are using speed hacking program
    // to boost up the game speed. The system only works if
    // only the player has the sound system working and enabled.
    // So it's recommended to require them to enable the sound
    // system just like what's demonstrated.
    //
    // Installation:
    // 1. Import the sound file
    // 2. Copy the SHD trigger group to your map
    // 3. Copy SHDetectionDummy unit to your map
    // 4. Configure the system accordingly
    //
    //    Events:
    //     udg_SHD__Event equals to 1.00 => speed hack detected
    //     udg_SHD__Event equals to 2.00 => sound system disabled
    //     udg_SHD__Event equals to 3.00 => sound system enabled
    //
    // ********************************************************
 
    constant function SHD__DummyID takes nothing returns integer
        return 'h000' // SHDetectionDummy raw code
    endfunction
 
    constant function SHD__FilePath takes nothing returns string
        return "war3mapImported\\SpeedHackDetector.mp3"
    endfunction
 
    constant function SHD__FileDuration takes nothing returns real
        return 1.1
    endfunction
 
    constant function SHD__RetryThreshold takes nothing returns integer
        return 25
    endfunction
 
    function SHD__OnSelect takes nothing returns boolean
    
        local unit u = GetTriggerUnit()
        local integer id
    
        set udg_SHD__TriggeringPlayer = GetTriggerPlayer()
        set id = GetPlayerId(udg_SHD__TriggeringPlayer)
        if (u == udg_SHD__EventSync) then
            set udg_SHD__EventIndex[id] = udg_SHD__EventIndex[id] + 1
        elseif (u == udg_SHD__EventSyncEnd) then
            set udg_SHD__Event = udg_SHD__EventIndex[id]
            set udg_SHD__Event = 0
            set udg_SHD__EventIndex[id] = 0
        endif
        set udg_SHD__TriggeringPlayer = null
        set u = null
    
        return false
    endfunction
 
    function SHD__BuildEvent takes integer index returns nothing
        loop
            set index = index-1
            call SelectUnit(udg_SHD__EventSync, true)
            call SelectUnit(udg_SHD__EventSync, false)
            exitwhen index == 0
        endloop
        call SelectUnit(udg_SHD__EventSyncEnd, true)
        call SelectUnit(udg_SHD__EventSyncEnd, false)
    endfunction
 
    function SHD__Check takes nothing returns nothing
    
        if (udg_SHD__IsSoundPlaying and GetSoundIsPlaying(udg_SHD__Sound)) then
            call StopSound(udg_SHD__Sound, false, false)
            call SHD__BuildEvent(1)
        endif
        call StartSound(udg_SHD__Sound)
        set udg_SHD__IsSoundPlaying = GetSoundIsPlaying(udg_SHD__Sound)
        if (not udg_SHD__IsSoundPlaying) then
            if (udg_SHD__IsSoundEnabled) then
                call SHD__BuildEvent(2)
                set udg_SHD__IsSoundEnabled = false
            endif
        elseif (not udg_SHD__IsSoundEnabled) then
            call SHD__BuildEvent(3)
            set udg_SHD__IsSoundEnabled = true
        endif
    
    endfunction
 
    function SHD__Preload takes nothing returns nothing
    
        call StartSound(udg_SHD__Sound)
        if (GetSoundIsPlaying(udg_SHD__Sound)) then
            call StopSound(udg_SHD__Sound, false, false)
            call TimerStart(udg_SHD__Checker, SHD__FileDuration(), true, function SHD__Check)
            debug call BJDebugMsg("Preloading completed after " + I2S(udg_SHD__Counter) + "x attempts")
        elseif (udg_SHD__Counter < SHD__RetryThreshold()) then
            set udg_SHD__Counter = udg_SHD__Counter + 1
        elseif (udg_SHD__IsSoundEnabled) then
            call TimerStart(udg_SHD__Checker, SHD__FileDuration(), true, function SHD__Check)
            call SHD__BuildEvent(2)
            set udg_SHD__IsSoundEnabled = false
        endif
    
    endfunction
 
    function InitTrig_SHDetection takes nothing returns nothing
    
        local trigger t = CreateTrigger()
        local integer i = 0
    
        set udg_SHD__IsSoundEnabled = true
        set udg_SHD__EventSync      = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), SHD__DummyID(), 0, 0, 0)
        set udg_SHD__EventSyncEnd   = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), SHD__DummyID(), 0, 0, 0)
        set udg_SHD__Sound          = CreateSound(SHD__FilePath(), false, false, false, 0, 0, "")
    
        loop
            exitwhen i > 11
            call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_SELECTED, null)
            set i = i + 1
        endloop
        call TriggerAddCondition(t, Condition(function SHD__OnSelect))
        call TimerStart(udg_SHD__Checker, 0.01, true, function SHD__Preload)
        call PauseUnit(udg_SHD__EventSync   , true)
        call PauseUnit(udg_SHD__EventSyncEnd, true)
    
    endfunction
Contents

Speed Hack Detection (Map)

Reviews
KILLCIDE
I'll take your word that you didn't encounter any desyncs in your MP tests. I can definitely see this being a useful system for any map. The only downside is that you need sound enabled for it to work. The workaround of course is just forcing players...

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
Awesome if this really works and by the way speed hacking in multiplayer without disconnecting is now possible. Has been for a while.
It does work. It can detect 1.04x speed up and above seemingly with 100% precision.

Actually, yes it's very possible if all clients are using speedhack altogether at perfect timing (so easy to achieve: 1. Pause the game 2. All clients start the speed hack 3. Resume the game) I just didn't think of that possibility and making excuses because I was too lazy to test in multiplayer. And some RPG maps provide different save/load code for SP and LAN mode. In case the player plays the RPG in LAN but alone, the system shall prevent him from speed hacking so he can't use that cheated save data on online plays.

So, I will enable and check if the system work for multiplayer in the next update.
 
Last edited:

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
Nope, constant function is a jass feature since the jurassic. : )

EDIT:
I've tested the system can actually work in multiplayer. However handling the event isn't trivial at all. The detection runs asynchronously for each client. Thus, I have to sync the detection events from the hacker to all other clients, without interrupting with user control of course, which is so far not possible.

A solution I can think of is to use exec function feature (I suppose executing function locally won't cause desync) but it will completely wipe out the GUI friendliness. Is that okay?

I don't need to do such thing if I just disable the system if there are more than 1 players tho. But it's going to open one probability for hacker to get through the detection by playing the map in multiplayer using emulator. So which one do you think is better?
 
Last edited:
Always more then one method of GUI friendliness, I suggest upgrading the system to work in multiplayer then try to think of a way to make it easier for GUI'ers. As both JASS and GUI is technically the same, should always be a way to make at least an interface for GUI'ers. I would really like to be able to use this in multiplayer without much cost of memory/processing.


Edit: Also speedhacking doesn't require all clients to have it and/or for the game to be paused, guess it most likely depends on the type of it. Just game time seems to work perfectly.
 
Level 37
Joined
Jul 22, 2015
Messages
3,485
I'll take your word that you didn't encounter any desyncs in your MP tests. I can definitely see this being a useful system for any map. The only downside is that you need sound enabled for it to work. The workaround of course is just forcing players to have sound enabled like you mentioned.

Needs Fixed

  • Nothing

Suggestions

  • A description for SHD_RetryThreshold would be nice
  • exitwhen i > 11 -> exitwhen i == bj_MAX_PLAYER_SLOTS for clarity :p
  • Since you're only adding one event, it's okay to use TriggerRegisterAnyUnitEventBJ()
  • Any particular reason why the periodic timeout is set to 0.01? If not, I would just make it configurable
  • in SHD__OnSelect, you only use udg_SHD__TriggeringPlayer to get the player id. Seems wasteful to declare a local just for that. I would just do: set id = GetPlayerId(GetTriggerPlayer())

Status

Approved
 

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
Oh baha my mistake. I saw you nulling the variable, so I assumed it was a local. Regardless, my suggestion still stands! You can get rid of that variable all together then.
Get rid of what variable btw?

Actually, this can also be configured to detect speed down hack as well. But to be able to detect both at once, it will require two timers/sounds/checker & preloader functions etc etc. And I think no one is stupid enough to use speed hack only to slow down the game. But anyway, in case someone need it, then don't hesitate to make a post here. So far I just think it's an unnecessary yet costy feature.
 

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
I don't see the purpose of udg_SHD__TriggeringPlayer. You use it to store whoever the GetTriggerPlayer() is, and you only use it once in your entire system, and that is inside GetPlayerId().
Again, it's the event response, it's needed in the other triggers to acknowledge the detected player.
 
Top