• 🏆 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!

[JASS] Damage Unit Once

Status
Not open for further replies.
Level 12
Joined
Feb 23, 2007
Messages
1,030
So I have a pseudo-attack detection system (It works as long as the units attack speed isn't changed). Glaive Thrower attacks, it creates a glaive and moves the glaive foward every 0.04 seconds. It damages any enemy units it comes in contact with. The problem is I only want it to damage them once. It ends up instantly killing every unit lol

Can't find the problem @_@ If you could comment on my use of structs it would be greatly appreciated as well.

JASS:
scope GlaiveThrower

private constant function GlaiveID takes nothing returns integer
    return 'e00C'
endfunction

private constant function GlaiveProjectileID takes nothing returns integer
    return 'n004'
endfunction

private function Conditions takes nothing returns boolean
    return GetUnitTypeId(GetAttacker()) == GlaiveID()
endfunction

private function Conditions2 takes nothing returns boolean
    return GetUnitTypeId(GetTriggerUnit()) == GlaiveID() and GetHandleInt(GetTriggerUnit(),"special")!= null
endfunction

private function GlaiveFilter takes nothing returns boolean
    return IsUnitInRangeXY(GetFilterUnit(),TempReal1,TempReal2,TempReal3) and IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(TempUnit)) and IsUnitType(GetFilterUnit(), UNIT_TYPE_FLYING) == false and GetUnitState(GetFilterUnit(), UNIT_STATE_LIFE)>.4 and IsUnitInGroup(GetFilterUnit(),TempGroup) == false
endfunction

globals
    trigger gg_trg_GlaiveThrowerAttackCancel
endglobals

private struct Glaive
    timer t
    unit u
    unit a
    group g = CreateGroup()
    real x
    real y
    integer c
    
    method onDestroy takes nothing returns nothing
        set this.t = null
        set this.u = null
        set this.a = null
        call DestroyGroup(this.g)
        set this.g = null
    endmethod
endstruct

private struct Time
    timer t
    method onDestroy takes nothing returns nothing
        set this.t = null
    endmethod
endstruct

private function MoveProjectile takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local Glaive str = Glaive(GetHandleInt(t,"str"))
    local unit u = str.u
    local real x = str.x
    local real y = str.y
    local real x2 = GetUnitX(u)
    local real y2 = GetUnitY(u)
    local integer c = str.c-1
    local group g = CreateGroup()
    local unit p
    
    set TempUnit = u
    set TempGroup = str.g
    set TempReal1 = x2
    set TempReal2 = y2
    set TempReal3 = 100
    call GroupEnumUnitsInRange(g,x2,y2,TempReal3+MC(),Condition(function GlaiveFilter))
    call SetUnitPosition(u,x2+x,y2+y)
    
    loop
        set p = FirstOfGroup(g)
        exitwhen p==null
        call GroupAddUnit(str.g,p)
        call UnitDamageTarget(u,p,80,true,false,ATTACK_TYPE_MELEE,DAMAGE_TYPE_SPIRIT_LINK,WEAPON_TYPE_WHOKNOWS)
        call GroupRemoveUnit(g,p)
    endloop

    if c==0 then
        call RemoveUnit(u)
        call str.destroy()
        call ReleaseTimer(t)
    else
        set str.c = c
    endif

    call GroupClear(TempGroup)
    call DestroyGroup(g)
    set t = null
    set u = null
    set g = null
endfunction

private function TimerActions takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local Glaive str = Glaive(GetHandleInt(t,"str"))
    local unit a = str.a
    local unit u = str.u
    local real x = GetUnitX(a)
    local real y = GetUnitY(a)
    local real f = Atan2(y-GetUnitY(u),x-GetUnitX(u))
    local real x2 = x+40*Cos(f)
    local real y2 = y+40*Sin(f)

    call FlushStoredInteger(LocalVars(),I2S(H2I(a)),"special")
    call FlushStoredInteger(LocalVars(),I2S(H2I(t)),"str")
    call ReleaseTimer(t)
    set t = NewTimer()
    call SetHandleInt(t,"str",str)
    set str.u = CreateUnit(GetOwningPlayer(a),GlaiveProjectileID(),x,y,0)
    set str.x = x-x2
    set str.y = y-y2
    set str.c = 30
    call TimerStart(t,0.04,true,function MoveProjectile)

    set t = null
    set a = null
    set u = null
endfunction

private function Actions takes nothing returns nothing
    local unit u = GetTriggerUnit()
    local unit a = GetAttacker()
    local timer t = NewTimer()
    local Glaive str = Glaive.create()
    local Time time = Time.create()

    set str.u=u
    set str.a=a
    set str.t = t
    set time.t = t
    call SetHandleInt(t,"str",str)
    call SetHandleInt(a,"special",time)
    call TimerStart(t,0.10,false,function TimerActions)

    set u = null
    set a = null
    set t = null
endfunction

private function Actions2 takes nothing returns nothing
    local unit u = GetTriggerUnit()
    local Time str = GetHandleInt(u,"special")
    local timer t = str.t
    local Glaive str2 = GetHandleInt(t,"str")

    call str.destroy()
    call str2.destroy()
    call FlushStoredInteger(LocalVars(),I2S(H2I(u)),"special")
    call FlushStoredInteger(LocalVars(),I2S(H2I(t)),"str")
    call ReleaseTimer(t)

    set u = null
endfunction

//===========================================================================
function InitTrig_GlaiveThrower takes nothing returns nothing
    local integer a = 0
    set gg_trg_GlaiveThrower = CreateTrigger()
    set gg_trg_GlaiveThrowerAttackCancel = CreateTrigger()
    
    loop
        exitwhen a==MaxPlayers()
        call TriggerRegisterPlayerUnitEvent(gg_trg_GlaiveThrower,Player(a),EVENT_PLAYER_UNIT_ATTACKED,null)
        set a = a+1
    endloop

    call TriggerAddCondition(gg_trg_GlaiveThrower, Condition(function Conditions))
    call TriggerAddAction(gg_trg_GlaiveThrower, function Actions)
    call TriggerAddCondition(gg_trg_GlaiveThrowerAttackCancel, Condition(function Conditions2))
    call TriggerAddAction(gg_trg_GlaiveThrowerAttackCancel, function Actions2)
endfunction

endscope
 
Level 11
Joined
Feb 22, 2006
Messages
752
As far as I can tell, you don't actually check to see if you've already detected collision with a unit before damaging the unit. You just load all the units you detect into a group, then clear the group.

For every timer callback, you need to enumerate all units within range then check to see if the unit is in some unit group where you store units you've already collided with. Only if they're not in that group do you damage them. Then you save every unit you enumerated (regardless of whether they were in the group or not) into another group or better yet an array (since you don't need to do any searches) and then AFTER you've done the enumeration, clear the unit group and load all the units you saved into the first group. This way, if a unit leaves the collision area and then somehow reenters it later, it will correctly trigger a new collision.
 
Level 12
Joined
Feb 23, 2007
Messages
1,030
I check for units in range and if they are not in a unit group. If they aren't in the group and are in range, then I deal damage to them and add them to the group and clear the enumerated group all at the same time.

JASS:
call GroupEnumUnitsInRange(g,x2,y2,TempReal3+MC(),Condition(function GlaiveFilter))
Enumerate the group
JASS:
set TempGroup = str.g
Set a global variable = struct group (the group of already damaged units)
JASS:
return IsUnitInRangeXY(GetFilterUnit(),TempReal1,TempReal2,TempReal3) and IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(TempUnit)) and IsUnitType(GetFilterUnit(), UNIT_TYPE_FLYING) == false and GetUnitState(GetFilterUnit(), UNIT_STATE_LIFE)>.4 and IsUnitInGroup(GetFilterUnit(),TempGroup) == false
Check if the unit is in range and not in a certain group (This is the filter for the enumeration.
JASS:
loop
        set p = FirstOfGroup(g)
        exitwhen p==null
        call GroupAddUnit(str.g,p)
        call UnitDamageTarget(u,p,80,true,false,ATTACK_TYPE_MELEE,DAMAGE_TYPE_SPIRIT_LINK,WEAPON_TYPE_WHOKNOWS)
        call GroupRemoveUnit(g,p)
    endloop

I add the unit to the struct group, damage the unit, then remove it from the enumerated group.

Why wont it work?
 
Level 12
Joined
Feb 23, 2007
Messages
1,030
JASS:
call GroupClear(TempGroup)

You clear the group before the next timer callback, so by the time you check to see if any units are in the groups, NO units are ever in the group cuz you cleared it the last time around.

I don't think you're right.

JASS:
set TempGroup = str.g

I do this right before enumerating the group

While looping through the group, I take all enumerated units and add them to str.g

JASS:
call GroupAddUnit(str.g,p)

Each time I set TempGroup = str.g
 
Last edited:
Level 11
Joined
Feb 22, 2006
Messages
752
str.g and TempGroup are pointers, not groups. If you set TempGroup = str.g (which you do), you are making TempGroup point to the same group as str.g. So when you call GroupClear(TempGroup), you are clearing the same group that str.g points to so the next timer callback when you set the new local TempGroup = str.g, the group they're both pointing to (the SAME group) is empty.
 
Level 11
Joined
Feb 22, 2006
Messages
752
You could do GroupAddGroup, or you could do something like this (this also fixes your boolexpr leak):

JASS:
scope GlaiveThrower initializer init

globals
    private group g = CreateGroup()
    private boolexpr filterExpr
    private Glaive temp
    private unit array picked
    private integer pickedN = 0
endglobals

private function filter takes nothing returns boolean
    local unit u = GetFilterUnit()
    if ( ...conditions... and IsUnitInGroup(u, temp.g) == false) then // check conditions
        // do your damage stuff here...
    endif
    // add unit to array to mark it as picked
    set picked[pickedN] = u
    set pickedN = pickedN + 1
    set u = null
    return false
endfunction

// blah, blah...
private function MoveProjectile....
    // ...
    local integer i = 0
    // ...
    set temp = str
    call GroupEnumUnitsInRange(g, x2, y2, TempReal3+MC(), filterExpr) // enumerate through all units in range
    call GroupClear(str.g) // clear the group in the struct
    // add every picked unit to the group
    loop
        exitwhen (i >= pickedN)
        call GroupAddUnit(str.g, picked[i])
        set i = i + 1
    endloop
    set pickedN = 0 // "reset" the array
    // ...
endfunction

private function init takes nothing returns nothing
    set filterExpr = Condition(function filter)
endfunction

OR...you can just use xecollider. It does literally the SAME thing.
 
Level 12
Joined
Feb 23, 2007
Messages
1,030
So use an array to setup the groups. Alrighty :D

What do I do with the Glaive temp? It has a group that isn't destroyed (Gosh I feel like a total newb)

EDIT: I implemented the new filter, but it says GlaiveTemp isn't of the type that allows . syntax.

JASS:
private function GlaiveFilter takes nothing returns boolean
    local unit u = GetFilterUnit()
    
    if (IsUnitInRangeXY(u,TempReal1,TempReal2,TempReal3) and IsUnitEnemy(u, GetOwningPlayer(TempUnit)) and IsUnitType(u, UNIT_TYPE_FLYING) == false and GetUnitState(u, UNIT_STATE_LIFE)>.4 and IsUnitInGroup(u, GLAIVETEMP.g) == false) then
        call UnitDamageTarget(GLAIVETEMP.u,p,80,true,false,ATTACK_TYPE_MELEE,DAMAGE_TYPE_SPIRIT_LINK,WEAPON_TYPE_WHOKNOWS)
    endif
    
    set PICKED[PICKEDN] = u
    set PICKEDN = PICKEDN + 1
    set u = null
    return false
endfunction
 
Last edited:
Level 11
Joined
Feb 22, 2006
Messages
752
Are you sure you declared it as a global variable of type Glaive? i.e. this needs to be somewhere in your scope:

JASS:
globals
    private Glaive GLAIVETEMP
endglobals

And the temp variable simply allows you to get access to the right Glaive struct instance in the filter. When you set a variable to something, you're not making another copy of it, you're just making another variable point to the same object.

So:

JASS:
    local Glaive a = Glaive.create()
    local Glaive b = a // this doesn't create a new Glaive instance, it just makes b point to the same instance as a
    set a.c = 5
    call BJDebugMsg(I2S(b.c)) // will print "5" because a.c and b.c both point to the same integer
 
Level 12
Joined
Feb 23, 2007
Messages
1,030
JASS:
globals
    private group TEMPGROUP = CreateGroup()
    private boolexpr FILTER
    private Glaive GLAIVETEMP
    private unit array PICKED
    private integer PICKEDN = 0
    trigger gg_trg_GlaiveThrowerAttackCancel
endglobals

This is what I have for globals, it continues to return the error.

(Why do I feel like Gamecache is better than structs?)
 

Cokemonkey11

Spell Reviewer
Level 29
Joined
May 9, 2006
Messages
3,534
sorry to jump in so late, but can you tell us what the syntax error is?

Gamecache is better than structs because it can be used in a way that makes it appear cleaner, however it is in fact slower and deprecated, and could cease to work at any minute blizzard decides to release a wc3 update that fixes the double return bug.

From waht I can see in your last post, I'm guessing you either forgot to keyword the Glaive struct, or you forgot to put the struct declaration above the global declaration.
 
Level 12
Joined
Feb 23, 2007
Messages
1,030
GLAIVETEMP is not of a type that allows . syntax
JASS:
if (IsUnitInRangeXY(u,TempReal1,TempReal2,TempReal3) and IsUnitEnemy(u, GetOwningPlayer(TempUnit)) and IsUnitType(u, UNIT_TYPE_FLYING) == false and GetUnitState(u, UNIT_STATE_LIFE)>.4 and IsUnitInGroup(u, GLAIVETEMP.g) == false) then

There's the line it says fails.
 
Level 12
Joined
Feb 23, 2007
Messages
1,030
I'll just show the whole thing again.

JASS:
scope GlaiveThrower

private constant function GlaiveID takes nothing returns integer
    return 'e00C'
endfunction

private constant function GlaiveProjectileID takes nothing returns integer
    return 'n004'
endfunction

private struct Glaive
    group g = CreateGroup()
    timer t
    unit u
    unit a
    real x
    real y
    integer c

    method onDestroy takes nothing returns nothing
        set this.t = null
        set this.u = null
        set this.a = null
        call DestroyGroup(this.g)
        set this.g = null
    endmethod
endstruct

globals
    private group TEMPGROUP = CreateGroup()
    private boolexpr FILTER
    private Glaive GLAIVETEMP
    private unit array PICKED
    private integer PICKEDN = 0
    trigger gg_trg_GlaiveThrowerAttackCancel
endglobals

private struct Time
    timer t
    method onDestroy takes nothing returns nothing
        set this.t = null
    endmethod
endstruct

private function Conditions takes nothing returns boolean
    return GetUnitTypeId(GetAttacker()) == GlaiveID()
endfunction

private function Conditions2 takes nothing returns boolean
    return GetUnitTypeId(GetTriggerUnit()) == GlaiveID() and GetHandleInt(GetTriggerUnit(),"special")!= null
endfunction

private function GlaiveFilter takes nothing returns boolean
    local unit u = GetFilterUnit()
    
    if (IsUnitInRangeXY(u,TempReal1,TempReal2,TempReal3) and IsUnitEnemy(u, GetOwningPlayer(TempUnit)) and IsUnitType(u, UNIT_TYPE_FLYING) == false and GetUnitState(u, UNIT_STATE_LIFE)>.4 and IsUnitInGroup(u, GLAIVETEMP.g) == false) then
        call UnitDamageTarget(GLAIVETEMP.u,u,80,true,false,ATTACK_TYPE_MELEE,DAMAGE_TYPE_SPIRIT_LINK,WEAPON_TYPE_WHOKNOWS)
    endif
    
    set PICKED[PICKEDN] = u
    set PICKEDN = PICKEDN + 1
    set u = null
    return false
endfunction

private function MoveProjectile takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local Glaive str = Glaive(GetHandleInt(t,"str"))
    local real x2 = GetUnitX(str.u)
    local real y2 = GetUnitY(str.u)
    local integer i = 0

    set str.c = str.c - 1
    set GLAIVETEMP = str
    set TempReal1 = x2
    set TempReal2 = y2
    set TempReal3 = 100
    call GroupEnumUnitsInRange(TEMPGROUP,x2,y2,TempReal3+MC(), FILTER)
    call GroupClear(str.g)
    call SetUnitPosition(str.u,x2+str.x,y2+str.y)
    
    loop
        exitwhen (i >= PICKEDN)
        call GroupAddUnit(str.g, PICKED[i])
        set i = i + 1
    endloop
    
    set PICKEDN = 0

    if str.c == 0 then
        call RemoveUnit(str.u)
        call str.destroy()
        call ReleaseTimer(t)
    endif

    call DestroyGroup(TEMPGROUP)
    set t = null
endfunction

private function TimerActions takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local Glaive str = Glaive(GetHandleInt(t,"str"))
    local unit a = str.a
    local unit u = str.u
    local real x = GetUnitX(a)
    local real y = GetUnitY(a)
    local real f = Atan2(y-GetUnitY(u),x-GetUnitX(u))
    local real x2 = x+40*Cos(f)
    local real y2 = y+40*Sin(f)

    call FlushStoredInteger(LocalVars(),I2S(H2I(a)),"special")
    call FlushStoredInteger(LocalVars(),I2S(H2I(t)),"str")
    call ReleaseTimer(t)
    set t = NewTimer()
    call SetHandleInt(t,"str",str)
    set str.u = CreateUnit(GetOwningPlayer(a),GlaiveProjectileID(),x,y,0)
    set str.x = x-x2
    set str.y = y-y2
    set str.c = 30
    set str.g = CreateGroup()
    call TimerStart(t,0.04,true,function MoveProjectile)

    set t = null
    set a = null
    set u = null
endfunction

private function Actions takes nothing returns nothing
    local unit u = GetTriggerUnit()
    local unit a = GetAttacker()
    local timer t = NewTimer()
    local Glaive str = Glaive.create()
    local Time time = Time.create()

    set str.u=u
    set str.a=a
    set str.t = t
    set time.t = t
    call SetHandleInt(t,"str",str)
    call SetHandleInt(a,"special",time)
    call TimerStart(t,0.10,false,function TimerActions)

    set u = null
    set a = null
    set t = null
endfunction

private function Actions2 takes nothing returns nothing
    local unit u = GetTriggerUnit()
    local Time str = GetHandleInt(u,"special")
    local timer t = str.t
local Glaive str2 = GetHandleInt(t,"str")

    call str.destroy()
    call str2.destroy()
    call FlushStoredInteger(LocalVars(),I2S(H2I(u)),"special")
    call FlushStoredInteger(LocalVars(),I2S(H2I(t)),"str")
    call ReleaseTimer(t)

    set u = null
endfunction

//===========================================================================
function InitTrig_GlaiveThrower takes nothing returns nothing
    local integer a = 0
    set gg_trg_GlaiveThrower = CreateTrigger()
    set gg_trg_GlaiveThrowerAttackCancel = CreateTrigger()
    set FILTER = Condition(function GlaiveFilter)

    loop
        exitwhen a==MaxPlayers()
        call TriggerRegisterPlayerUnitEvent(gg_trg_GlaiveThrower,Player(a),EVENT_PLAYER_UNIT_ATTACKED,null)
        set a = a+1
    endloop

    call TriggerAddCondition(gg_trg_GlaiveThrower, Condition(function Conditions))
    call TriggerAddAction(gg_trg_GlaiveThrower, function Actions)
    call TriggerAddCondition(gg_trg_GlaiveThrowerAttackCancel, Condition(function Conditions2))
    call TriggerAddAction(gg_trg_GlaiveThrowerAttackCancel, function Actions2)
endfunction

endscope
 
Level 11
Joined
Feb 22, 2006
Messages
752
Gamecache is better than structs because it can be used in a way that makes it appear cleaner

What...????

however it is in fact slower and deprecated

Not deprecated. And whether or not it's "slower" depends on the situation.

and could cease to work at any minute blizzard decides to release a wc3 update that fixes the double return bug

Why would they do that? I'm pretty sure they know that mapmakers are exploiting that bug to no end, and since it has no adverse side effects, there's no reason for them to "fix" it.

keyword the Glaive struct, or you forgot to put the struct declaration above the global declaration.

You never need to keyword globals. And struct declarations don't have to be "above" global declarations.

@Dreadnought: Well, I have no idea what is wrong, because I just replicated your code in my WE and I get back no syntax errors. What version of jasshelper are you using?
 

Cokemonkey11

Spell Reviewer
Level 29
Joined
May 9, 2006
Messages
3,534
What...????
It's shorter and easier to read?
Not deprecated. And whether or not it's "slower" depends on the situation.
It is, by definition it could be removed or changed at any time, and slower refers to the fact that it HAS to access game cache and for MUI use it creates multiple timers instead of 1 global one. A struct stack is thousands of times faster.
Why would they do that? I'm pretty sure they know that mapmakers are exploiting that bug to no end, and since it has no adverse side effects, there's no reason for them to "fix" it.
You're months behind on discussion. Historically blizzard's ruined tons of maps including dota to fix things if they believed they were bugs. And better yet, Toadcop's proved much worse things can come from abusation of this bug besides slower code. I suggest you read around on the jass vault and wc3c.
You never need to keyword globals. And struct declarations don't have to be "above" global declarations.
Got it, thanks for clearing that up
@Dreadnought: Well, I have no idea what is wrong, because I just replicated your code in my WE and I get back no syntax errors. What version of jasshelper are you using?
 
Level 11
Joined
Feb 22, 2006
Messages
752
It's shorter and easier to read?

How is:

JASS:
call StoreInteger(localCache, H2I(u), H2I(fx))
set fx = GetStoredInteger(localCache, H2I(u))

easier to read than:

JASS:
set data.fx = fx
set fx = data.fx

It is, by definition it could be removed or changed at any time, and slower refers to the fact that it HAS to access game cache and for MUI use it creates multiple timers instead of 1 global one.

Wait...when did we start talking about timers...

A struct stack is thousands of times faster.

I'm pretty sure an O(n) search through a 5000-member array is going to be slower (on average) than gamecache.

Historically blizzard's ruined tons of maps including dota to fix things if they believed they were bugs

The bug has been known for a WHILE now (years...). If blizz was going to fix it, they'd have done it alrdy. And ruining dota? Wow did blizz actually get something right for a change?...

And better yet, Toadcop's proved much worse things can come from abusation of this bug besides slower code

I have no doubt you can abuse the return bug in all the wrong ways. But if you use it CORRECTLY, there's no harm done. And the slower code issue isn't a problem anymore if you have jasshelper.

I suggest you read around on the jass vault and wc3c.

I DO read around on wc3c. Half the systems/scripts there use Table, which uses..........GAMECACHE.
 

Cokemonkey11

Spell Reviewer
Level 29
Joined
May 9, 2006
Messages
3,534
How is:

JASS:
call StoreInteger(localCache, H2I(u), H2I(fx))
set fx = GetStoredInteger(localCache, H2I(u))

easier to read than:

JASS:
set data.fx = fx
set fx = data.fx
Sorry for any misunderstanding, but when I refer to struct and GC type stuff I generally think in terms of a MUI repeated function, like a spell with a timer. Getting data stored in GC from an expired timer is a lot cleaner and easier to understand than looping through all the structs in a struct stack, using temporary structs, destroying structs, and when to do what with structs that are destroyed within the stack. I hope that makes sense.
Wait...when did we start talking about timers...
Generally for me the main use of GC/Structs Stacks is getting repeated MUI data with a timer (think like knockback)
I'm pretty sure an O(n) search through a 5000-member array is going to be slower (on average) than gamecache.
Assuming that only 1 game cache is used and 5000 members are always being used? But the general public doesn't call 5000 members or use only 1 gamecache.
The bug has been known for a WHILE now (years...). If blizz was going to fix it, they'd have done it alrdy. And ruining dota? Wow did blizz actually get something right for a change?...
I don't disagree, I'm not a fan of dota either, but blizzard is.
I have no doubt you can abuse the return bug in all the wrong ways. But if you use it CORRECTLY, there's no harm done. And the slower code issue isn't a problem anymore if you have jasshelper.
I don't think you understand, the problem that was discovered recently with DR is something that can be exploited in a manner similar to a buffer overflow. Using the bug to add or remove information from a pointer can be used to inject arbitrary byte code into any map on wc, and can be used to get data outside warcraft as well. A true VXer could destroy someone's computer with a simple map on bnet. For proofs, toadcop was able to run a cmd prompt and begin running commands through this simple bug by an intermediate understanding of bytecode and where to send a pointer. The point of all this is to explain that this isn't just a bug that can be avoided, it's a serious problem that devs of real programs are payed to look for in their own stuff.
I DO read around on wc3c. Half the systems/scripts there use Table, which uses..........GAMECACHE.

Table and timerutil's are examples of very well made GC systems. Not much I can say here other than that they are a lot cleaner and faster than the standard Get/Store Data...
 
Level 21
Joined
Aug 21, 2005
Messages
3,699
You're months behind on discussion. Historically blizzard's ruined tons of maps including dota to fix things if they believed they were bugs. And better yet, Toadcop's proved much worse things can come from abusation of this bug besides slower code. I suggest you read around on the jass vault and wc3c.
The bugs are related to bad usage of H2I. You shouldn't use it if you don't know how to use it and avoid those bugs. If you know how to use it, there's no problem with the returnbug.
Oh and blizzard probably won't solve things by fixing the returnbug. They would effectively kill the modding community at this stage.

It is, by definition it could be removed or changed at any time, and slower refers to the fact that it HAS to access game cache and for MUI use it creates multiple timers instead of 1 global one. A struct stack is thousands of times faster.

Struct stacks aren't thousands of times faster. They're obviously faster, but stacks often aren't the best solution, where gamecache provides a faster solution because it uses hashing. Slow hashing, but still hashing that provides you with a constant searchtime instead of o(n) array searchtimes.
Even for "small" stacks o(n) is still slower than gamecache.

I don't think you understand, the problem that was discovered recently with DR is something that can be exploited in a manner similar to a buffer overflow.

A code variable, when returned, provides a direct memory adress. Handle variables, when returned, provide an index to a handletable only known to the virtual machine. So the returnbug on code is of a total different dimension than the returnbug on handles. Returning handles casted to integers only potentially causes handle corruption, which only happens if you're an irresponsible jass scripter.

Table and timerutil's are examples of very well made GC systems. Not much I can say here other than that they are a lot cleaner and faster than the standard Get/Store Data...
It still uses gamecache and the returnbug, which is what you consider to be slow and buggy. Does the fact it's faster and uses vjass syntactical suggar change anything to the fact it used GC and returnbug?

At dreadnought: struct stacks work like this:

JASS:
struct MyStruct
    private unit u
    static MyStruct array data
    static integer last
    private integer index

    // Upon creating the struct:
    local MyStruct this = MyStruct.allocate()
    set MyStruct.data[MyStruct.last] = this
    set this.index = MyStruct.last
    set MyStruct.last = MyStruct.last + 1
    return this
    
    // Upon destruction:
    set MyStruct.last = MyStruct.last - 1
    set MyStruct.data[this.index] = MyStruct.last

    // Upon spellcast
    local unit target = GetSpellTargetUnit()
    local integer i = 0
    loop
        exitwhen i >= MyStruct.last
        if MyStruct.data[i].u == caster then
            // we found the correct data struct
        endif
    endloop

It is obvious that the more MyStructs are allocated, the larger the stack and the longer you could be searching for the correct datastruct you're looking for. For most spells stacks are better, but for many systems, the stack will be too large to effeciently search through.
 
Status
Not open for further replies.
Top