Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

[vJASS] - Detect Reforged

Discussion in 'The Lab' started by Blarto, Apr 12, 2020.

  1. Blarto

    Blarto

    Joined:
    Jan 17, 2010
    Messages:
    150
    Resources:
    1
    Spells:
    1
    Resources:
    1
    Plug and play library/snippet

    Might be useful for debugging.

    Requires - [vJASS] - Sync Local Booleans or equivalent ([vJASS] - Sync (Game Cache), or the new BlzAPI functions) to sync values

    HOW IT WORKS:
    It creates a (platform - Walkable destructable) Throne ('XOkt' destructable ID) somewhere on the map and exploits the fact they have different models (thus different return values for GetLocationZ) in classic/reforged, and then syncs the boolean to a global array for easy access.

    This means you can detect other players playing Reforged in your map even if you do not have Reforged yourself or chosen to use classic.

    Code (vJASS):

    library DetectReforged initializer init requires BooleanSync optional TimerUtils
        globals
            private boolean array Reforged
        endglobals
     
        function IsReforged takes player p returns boolean
            return Reforged[GetPlayerId(p)]
        endfunction
     
        private function AssignReforgedFlag takes nothing returns nothing
            set Reforged[GetPlayerId(GetTriggerPlayer())] = GetSyncedBoolean()
        endfunction
     
        private function checkReforged takes nothing returns nothing
            local real x = GetRectMinX(GetWorldBounds()) + 1000
            local real y = GetRectMaxY(GetWorldBounds()) - 1000
            local location l = Location(x,y)
            local destructable d
            local real z1 = GetLocationZ(Location(x,y))
            local boolean reforged
            local integer i = 0
            set d = CreateDestructable('XOkt', x,y, 0,1,0)
            call MoveLocation(l, x, y)
       
            // 57.431 is the classic height of the throne at it's center if scale == 1
            // reforged value is 72.71558
            // so if the value is different then its reforged
            //call BJDebugMsg(R2S(GetLocationZ(l) - z1))
            set z1 = (GetLocationZ(l) - z1) * 100
            if R2I(z1) != 5743 then
                set reforged = true
                // reforged
                //call BJDebugMsg(R2S(z1))
            else
                set reforged = false
                // classic
                //call BJDebugMsg(R2S(z1))
            endif
            loop
                call SyncBoolean(Player(i), reforged, function AssignReforgedFlag)
                set i = i + 1
                exitwhen i >= bj_MAX_PLAYER_SLOTS
            endloop
       
            call RemoveLocation(l)
            call RemoveDestructable(d)
            set d = null
            set l = null
            static if LIBRARY_TimerUtils then
                call ReleaseTimer(GetExpiredTimer())
            else
                call PauseTimer(GetExpiredTimer())
                call DestroyTimer(GetExpiredTimer())
            endif
        endfunction
     
        private function init takes nothing returns nothing
            static if LIBRARY_TimerUtils then
                call TimerStart(NewTimer(), 0.0, false, function checkReforged)
            else
                call TimerStart(CreateTimer(), 0.0, false, function checkReforged)
            endif
        endfunction
    endlibrary
     
     
    Last edited: Apr 12, 2020
  2. TriggerHappy

    TriggerHappy

    Code Moderator

    Joined:
    Jun 23, 2007
    Messages:
    3,793
    Resources:
    22
    Spells:
    11
    Tutorials:
    2
    JASS:
    9
    Resources:
    22
    This is an interesting way to detect HD mode. It's nice because it's easily portable however I feel the better solution would be to import a file (.fdf, .pld, .ai) as HD only and sync whoever successfully reads the file. It has less overhead and almost no chance of being patched out.
     
  3. Blarto

    Blarto

    Joined:
    Jan 17, 2010
    Messages:
    150
    Resources:
    1
    Spells:
    1
    Resources:
    1
    They are welcome to patch this out as it will involve GetLocationZ() changes or a complete overhaul of dozens of models. Probably a safe bet they'll never do that.

    If they patch GetLocationZ to work synchronously (by forcing player 0's values or something) I'd be pleasently surprised as it fixes SO MUCH.

    If they patch models we can just create HD/SD model paths and rely on this using custom models...

    I think overall this method is relatively bulletproof. But who knows... Bliz done some dumb sht in the past.



    Here is a prototype version without a sync library (still syncing just embedded now)

    I'll test tonight (tested.. it works).

    Code (vJASS):

    library DetectReforged initializer init requires optional TimerUtils
        globals
            private boolean array Reforged
            private unit dummyReforged
            private unit dummyClassic
            private trigger selectTrigger
            private timer cleanupTimer
        endglobals
     
        function IsReforged takes player p returns boolean
            return Reforged[GetPlayerId(p)]
        endfunction
        private function cleanup takes nothing returns nothing
            static if LIBRARY_TimerUtils then
                call ReleaseTimer(GetExpiredTimer())
            else
                call PauseTimer(GetExpiredTimer())
                call DestroyTimer(GetExpiredTimer())
            endif
            call DisableTrigger(selectTrigger)
            call RemoveUnit(dummyReforged)
            call RemoveUnit(dummyClassic)
            set dummyReforged = null
            set dummyClassic = null
            set selectTrigger = null
            set cleanupTimer = null
        endfunction
        private function onSelect takes nothing returns boolean
         
            if GetTriggerUnit() == dummyReforged then
                // assume all selection events resolve in 3 sec or less
                set Reforged[GetPlayerId(GetTriggerPlayer())] = true
                call TimerStart(cleanupTimer, 3.0, false, function cleanup)
                //call BJDebugMsg(GetPlayerName(GetTriggerPlayer()) + " reforged ")
            elseif GetTriggerUnit() == dummyClassic then
                set Reforged[GetPlayerId(GetTriggerPlayer())] = false // not really needed, just for consistency
                call TimerStart(cleanupTimer, 3.0, false, function cleanup)
                //call BJDebugMsg(GetPlayerName(GetTriggerPlayer()) + " classic ")
            endif
            return false
        endfunction
     
        private function CreateDummy takes real x, real y returns unit
            local unit u
            local integer i = 0
            // create dummy unit
            set u = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), 'nrat', x, y, 0)
            // Make dummy only selectable through triggers
            call UnitAddAbility(u, 'Amrf')
            call SetUnitFlyHeight(u, 5000, 0)
            call UnitAddAbility(u, 'Aeth')
            call SetUnitScale(u, 0, 0, 0)
            call PauseUnit(u, true)
            // Hide health bar
            call UnitAddAbility(u , 'Aloc')
            call ShowUnit(u, false)
            call UnitRemoveAbility(u , 'Aloc')
            call ShowUnit(u, true)
             
            // ensure it doesn't die
            call SetUnitInvulnerable(u, true)
            // share vision
            loop
                call UnitShareVision(u, Player(i), true)
                set i = i + 1
                exitwhen i >= bj_MAX_PLAYER_SLOTS
            endloop
            return u
        endfunction
         
        private function checkReforged takes nothing returns nothing
            local real x = GetRectMinX(GetWorldBounds()) + 1000
            local real y = GetRectMaxY(GetWorldBounds()) - 1000
            local location l = Location(x,y)
            local destructable d
            local real z1 = GetLocationZ(Location(x,y))
            local integer i = 0
            local unit u
         
            set cleanupTimer = GetExpiredTimer()
            set dummyReforged = CreateDummy(x,y)
            set dummyClassic = CreateDummy(x,y)
            set d = CreateDestructable('XOkt', x, y, 0, 1, 0)
            call MoveLocation(l, x, y)
            // 57.431 is the classic height of the throne at it's center if scale == 1
            // reforged value is 72.71558
            // so if the value is different then its reforged
            //call BJDebugMsg(R2S(GetLocationZ(l) - z1))
            set z1 = (GetLocationZ(l) - z1) * 100
            if R2I(z1) == 5743 then
                // probably classic
                //call BJDebugMsg(R2S(z1))
                call SelectUnit(dummyClassic, true)
                call SelectUnit(dummyClassic, false)
            else
                call SelectUnit(dummyReforged, true)
                call SelectUnit(dummyReforged, false)
                // probably reforged
                //call BJDebugMsg(R2S(z1))
            endif
         
            call RemoveLocation(l)
            call RemoveDestructable(d)
            set d = null
            set l = null
            set u = null
        endfunction
     
        private function init takes nothing returns nothing
            local integer i = 0
            set selectTrigger = CreateTrigger()
            loop
                call TriggerRegisterPlayerUnitEvent(selectTrigger, Player(i), EVENT_PLAYER_UNIT_SELECTED, null)
                set i = i + 1
                exitwhen i >= bj_MAX_PLAYER_SLOTS
            endloop
            call TriggerAddCondition(selectTrigger, Filter(function onSelect))
            static if LIBRARY_TimerUtils then
                call TimerStart(NewTimer(), 0.0, false, function checkReforged)
            else
                call TimerStart(CreateTimer(), 0.0, false, function checkReforged)
            endif
        endfunction
    endlibrary
     
     
    Last edited: Apr 13, 2020