wc3campaigns
WC3C Homepage - www.wc3c.netUser Control Panel (Requires Log-In)Engage in discussions with other users and join contests in the WC3C forums!Read one of our many tutorials, ranging in difficulty from beginner to advanced!Show off your artistic talents in the WC3C Gallery!Download quality models, textures, spells (vJASS/JASS), systems, and scripts!Download maps that have passed through our rigorous approval process!

Go Back   Wc3C.net > Warcraft III Modding > Developer's Corner > Triggers & Scripts
User Name
Password
Register Rules Get Hosted! Chat Pastebin FAQ and Rules Members List Calendar



Reply
 
Thread Tools Search this Thread
Old 07-04-2011, 03:58 PM   #1
Yrth
User
 
Yrth's Avatar
 
Join Date: Jul 2010
Posts: 76

Yrth has little to show at this moment (4)

Default [vJASS] WispWheel

Purpose: To create wisp wheels in as generic a way as possible and allow them to be manipulated easily.

Use: Primarily in mazing maps, this library uses up a hashtable per instantiation and thus isn't particularly viable for most maps.
I've played a very very large amount of mazes and have seen maybe 1 that used hashtables at all, as such: hashtable use in mazes is not a problem as far as hitting the maximum number of hashes in a map goes.
The way its done utilizes every aspect of the hashtable. the keys correspond to the spoke number and position in that spoke and map to the correct unit.
To make the equivalent using arrays, I'd have to put a hard cap on the number of spokes possible in any wheel

Code:
Expand JASS:

questions:
1. hashtable functions
so in the code i used bj stuff to access the hashtable
this is for a simple reason
i have no idea what the hashtable functions are
i tried updating jass helper but that didn't help
is there a list of the new functions that go with hashtables?
or at least could someone tell me the equivalent for the ones I used in my code?

2. onDestroy
it might be helpful to some map makers (of mazes) to be able to destroy wisp wheels.
personally, I would rather leave the wisp wheel on a level (albeit paused) then destroy it and have to create it again later on, but some people might want to destroy them
in the camera help thread I made a little while back, anitarf said that a group would automatically be recycled along with the struct as long as it wasn't destroyed.
will this apply for hashtables as well?
and in anitarf's example he cleared his group when the last instance was being recycled. because the hashtable is iterated through with wheel specific parameters - I won't run into any problems with old variables for previous wheels, but the lookup speed would still be slower. as such, how do you clear a hashtable?

3.
are there any glaring flaws/leaks in my code? besides the bj hash functions that is.


as always, thanks very much to anyone for some pointers
(0x000000)
(0x000001)
Yrth is offline   Reply With Quote
Sponsored Links - Login to hide this ad!
Old 07-04-2011, 04:01 PM   #2
Bribe
User
 
Bribe's Avatar
 
Join Date: Mar 2010
Posts: 233

Submissions (1)

Bribe will become famous soon enough (30)Bribe will become famous soon enough (30)

Send a message via AIM to Bribe
Default

For BJ replacements, I advise an MPQ browser so you can extract common.j, common.ai, blizzard.j and cheats.j

Having blizzard.j open in a properly-highlighted text editor is very useful and fixes problems like "waiting for TESH to update"
Bribe is offline   Reply With Quote
Old 07-04-2011, 05:20 PM   #3
Anitarf
Procrastination Incarnate


Development Director
 
Join Date: Feb 2004
Posts: 8,190

Submissions (19)

Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)

2008 Spell olympics - Fire - SilverApproved Map: Old School Alliance TacticsHero Contest #2 - 3rd PlaceSpell making session 2 winner

Default

Quote:
Originally Posted by Yrth
The way its done utilizes every aspect of the hashtable. the keys correspond to the spoke number and position in that spoke and map to the correct unit.
To make the equivalent using arrays, I'd have to put a hard cap on the number of spokes possible in any wheel
Okay, but that's not really a problem. You set the hard cap using a constant value in the calibration header that the users can set as needed. Then, the units for each spoke can be stored in groups. You could even store all the units of a wheel in a single group, even if their order isn't the same each time you loop through it, why should it matter, aren't all the units in the wheel the same anyway?

By the way, I haven't played many maze maps so I don't know what's the point of this wheel. All the code seems to do is rotate a few lines of units in a circle around a central unit.
__________________
Anitarf is offline   Reply With Quote
Old 07-04-2011, 05:26 PM   #4
BBQ
User
 
Join Date: May 2011
Posts: 85

Submissions (2)

BBQ will become famous soon enough (30)BBQ will become famous soon enough (30)

Default

Quote:
Originally Posted by Yrth
1. hashtable functions
so in the code i used bj stuff to access the hashtable
this is for a simple reason
i have no idea what the hashtable functions are
i tried updating jass helper but that didn't help
is there a list of the new functions that go with hashtables?
or at least could someone tell me the equivalent for the ones I used in my code?
Expand Hashtable API (common.j):

Expand Hashtable API (Blizzard.j):

Quote:
Originally Posted by Yrth
2. onDestroy
it might be helpful to some map makers (of mazes) to be able to destroy wisp wheels.
personally, I would rather leave the wisp wheel on a level (albeit paused) then destroy it and have to create it again later on, but some people might want to destroy them
in the camera help thread I made a little while back, anitarf said that a group would automatically be recycled along with the struct as long as it wasn't destroyed.
will this apply for hashtables as well?
and in anitarf's example he cleared his group when the last instance was being recycled. because the hashtable is iterated through with wheel specific parameters - I won't run into any problems with old variables for previous wheels, but the lookup speed would still be slower. as such, how do you clear a hashtable?
  1. Hashtable recycling is virtually impossible.
  2. FlushParentHashtable(hashtable) flushes the whole hashtable, but also makes it unusable (this is exactly why recycling hashtables is "virtually impossible"), while FlushChildHashtable(hashtable, integer) only flushes the values stored under a given parent key.
Quote:
Originally Posted by Yrth
3. are there any glaring flaws/leaks in my code? besides the bj hash functions that is.
  1. Hashtables have a 256-instance limit, which means that your map cannot use more than 256 hashtables simultaneously. You generally shouldn't care about that limit, but you're using one hashtable per wisp wheel. That's a lot. Use something like Bribe's Array library instead.
  2. Why is your rotate method declared as stub? It doesn't make sense.
  3. You should put your wPeriodic static method below the rotate method in order to avoid calling it via trigger evaluations (remember, direct calls can only be done only if the callee is above the caller).

Last edited by BBQ : 07-04-2011 at 07:33 PM.
BBQ is offline   Reply With Quote
Old 07-04-2011, 11:06 PM   #5
Yrth
User
 
Yrth's Avatar
 
Join Date: Jul 2010
Posts: 76

Yrth has little to show at this moment (4)

Default

Quote:
For BJ replacements, I advise an MPQ browser so you can extract common.j, common.ai, blizzard.j and cheats.j

Having blizzard.j open in a properly-highlighted text editor is very useful and fixes problems like "waiting for TESH to update"
ty for the tip

Quote:
Then, the units for each spoke can be stored in groups. You could even store all the units of a wheel in a single group, even if their order isn't the same each time you loop through it, why should it matter, aren't all the units in the wheel the same anyway?
the order is somewhat important to do things as efficiently as possible
each unit needs a move coordinate suited specifically to it
that coordinate is easily given by utilizing the key values as factors
it would be possible to do this with a group, but you would need a lot more calculations and function calls - ie. if hashtable use is not a problem its much much faster

Quote:
You set the hard cap using a constant value in the calibration header that the users can set as needed. Then, the units for each spoke can be stored in groups
sweet
ermm
how?

Quote:
By the way, I haven't played many maze maps so I don't know what's the point of this wheel. All the code seems to do is rotate a few lines of units in a circle around a central unit.
if you have time, I attached a test map that illustrates what a wisp wheel does (you dont have to actually open it though, so shouldn't mess with your recently opened)
in a maze each wisp in the wheel has collision

also if you ever feel like playing a few more mazes, you should shoot me a message/pm :D
kinda curious, did gameslayer's Platform Escape use your keyboard event library?

Quote:
Hashtables have a 256-instance limit, which means that your map cannot use more than 256 hashtables simultaneously. You generally shouldn't care about that limit, but you're using one hashtable per wisp wheel. That's a lot. Use something like Bribe's Array library instead.
hmm you're right
the most wisp wheels i've ever seen in any maze is about 20 and thats being generous with the number
for mine, I plan to use 40 or so tops
as cool as bribe's array looks, it shares the same problem as anitarf's idea in respect to how to store the wisp wheel
Its not really a question of how best to store it, the hashtable is a perfect solution to it... minus the problem that using hashtables en masse is taboo
Maybe it'd be best to include a ConservativeWheel struct in the library that doesn't use the hashtable (but also is far more inefficient)

Quote:
FlushParentHashtable(hashtable) flushes the whole hashtable, but also makes it unusable (this is exactly why recycling hashtables is "virtually impossible"), while FlushChildHashtable(hashtable, integer) only flushes the values stored under a given parent key.
so I could flush every child hashtable because I know exactly how many keys (number spokes) are in every hashtable created. will this be enough to recycle the table? even though I didn't touch, nor know how to, the parent keys (outside of the full flush).

Quote:
Why is your rotate method declared as stub? It doesn't make sense.
because I have several different types of wheel that are extended from simplewheel
but because they aren't relevant to this, I didn't see any reason to post them
I edited out most of the stuff that hinted about them, but I missed the stub declaration.
only rotate is a stub, because only rotate needs to be changed

this actually made me think of an important question
I know that all structs that are children/parent share the same maximum of 8190 possible instances, but do they also share the same List Module?
It seems like they do, but this is important enough to get verification

Quote:
You should put your wPeriodic static method below the rotate method in order to avoid calling it via trigger evaluations (remember, direct calls can only be done only if the callee is above the caller).
ohhhh ok
tyvm I had no idea

anyways ty anitarf, bribe and bbq for the tips
Attached Files
File Type: w3x wispwheelworkshop.w3x (30.0 KB, 7 views)
Yrth is offline   Reply With Quote
Old 07-04-2011, 11:37 PM   #6
BBQ
User
 
Join Date: May 2011
Posts: 85

Submissions (2)

BBQ will become famous soon enough (30)BBQ will become famous soon enough (30)

Default

Quote:
Originally Posted by Yrth
hmm you're right
the most wisp wheels i've ever seen in any maze is about 20 and thats being generous with the number
for mine, I plan to use 40 or so tops
as cool as bribe's array looks, it shares the same problem as anitarf's idea in respect to how to store the wisp wheel
Its not really a question of how best to store it, the hashtable is a perfect solution to it... minus the problem that using hashtables en masse is taboo
Maybe it'd be best to include a ConservativeWheel struct in the library that doesn't use the hashtable (but also is far more inefficient)
No, using a DualArray is the same as using a hashtable (both provide 2D syntax, so instead of using a hashtable per struct instance, you'd use a DualArray per struct instance), except that you aren't really using a hashtable (well, you are, but it's just a single hashtable). What the Array library does in that aspect is key generation and collision avoidance.

Since JASS uses 32-bit signed integers, the parent- and child-keys can be anywhere from -(2^31) to 2^31 - 1. That means that you can store a lot of data in a single hashtable. And as I said, that's where theurl Array library comes in handy.

Quote:
Originally Posted by Yrth
so I could flush every child hashtable because I know exactly how many keys (number spokes) are in every hashtable created. will this be enough to recycle the table? even though I didn't touch, nor know how to, the parent keys (outside of the full flush).
Sure, if you manage to flush all the data from the hashtable, then I see no problem. But still, you should use a DualArray for that purpose. That way, you wouldn't even have to worry about recycling, because the Array library recycles them per se.

Quote:
Originally Posted by Yrth
this actually made me think of an important question
I know that all structs that are children/parent share the same maximum of 8190 possible instances, but do they also share the same List Module?
It seems like they do, but this is important enough to get verification
Yes, the child acquires all methods and members of the parent struct (of course, there are "special cases", such as interfaces, stub methods ...).

Quote:
Originally Posted by Yrth
ohhhh ok
tyvm I had no idea
Well, if that method was meant to be a stub, then there's no need to do what I said, because stub methods are always called via trigger evaluations. But you should keep that in mind for future reference.

Last edited by BBQ : 07-05-2011 at 12:19 AM.
BBQ is offline   Reply With Quote
Old 07-05-2011, 03:02 AM   #7
Yrth
User
 
Yrth's Avatar
 
Join Date: Jul 2010
Posts: 76

Yrth has little to show at this moment (4)

Default

Quote:
No, using a DualArray is the same as using a hashtable (both provide 2D syntax, so instead of using a hashtable per struct instance, you'd use a DualArray per struct instance), except that you aren't really using a hashtable (well, you are, but it's just a single hashtable). What the Array library does in that aspect is key generation and collision avoidance.

oh okay, very cool - I wasn't as far as dual array when I posted last.
I'll probably try to do this, but first I wanna take care of the existing bugs

specifically the bugs with wPause and wUnpause
here is the shortened current code with what I'm pretty sure are the only relevant parts
just below it is the complete current code - just in case what's shown in the first isn't enough

Expand JASS:

Expand JASS:

so when i call .wPause() on a wheel, all rotation stops, which is perfect
but when i cal .wUnpause() on the same wheel, the game goes into overdrive and lags too badly to even quit
however, in the very few frames you get, you can see that the wheel has resumed rotation

the ability to pause/unpause wheels is crucial for this to be useful
any ideas are much welcome and appreciated

just in case, the newest test map is attached
Attached Files
File Type: w3x wispwheelworkshop.w3x (29.9 KB, 6 views)
Yrth is offline   Reply With Quote
Old 07-05-2011, 11:13 AM   #8
Anitarf
Procrastination Incarnate


Development Director
 
Join Date: Feb 2004
Posts: 8,190

Submissions (19)

Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)

2008 Spell olympics - Fire - SilverApproved Map: Old School Alliance TacticsHero Contest #2 - 3rd PlaceSpell making session 2 winner

Default

Here, try this. No hashtable used.

Expand JASS:

If you feel this is too inefficient, you could always use a LinkedList instead of a group.
__________________
Anitarf is offline   Reply With Quote
Old 07-05-2011, 10:46 PM   #9
Yrth
User
 
Yrth's Avatar
 
Join Date: Jul 2010
Posts: 76

Yrth has little to show at this moment (4)

Default

very cool, anitarf - i'll try this when i get home
tyvm
i'm wondering if the count variable you made will collide with the one from ListModule though?

personally I think it'd be plenty efficient - but I'll offer several different types to suit whatever the maze maker wants


also I have an update on narrowing down the problem with pausing and unpausing wheels

on map creation 5 wheels are added to the list (and begin rotating) and all is well
if I pause then unpause any of those wheels, the game lags out - however the wheel does rotate (for 2ish very sketchy frames)

if I pause all the current wheels in the map, then i can unpause 1 wheel (or sets of wheels) just fine
however something weird happened when I was testing this
to pause/unpause the wheels I was using these triggers

Expand JASS:
Expand JASS:
Expand JASS:
Expand JASS:

basically red has 5 wisp wheels that all run at once (or not at all) and blue has just the 1.

anyways here's the weird thing(s):
if I pause both, I can unpause them (even both at the same time), but I can't unpause either if I haven't already paused them both
(possibly unrelated) if I pause unpause them enough - the game gets very confused. ie typing -off, will pause the wrong wisp wheel or typing -on will unpause both red and blues wheels (both unpause test triggers)
once things start getting entangled, they never get better without a restart

anyways, ideas are much appreciated
Yrth is offline   Reply With Quote
Old 07-06-2011, 07:27 AM   #10
Anitarf
Procrastination Incarnate


Development Director
 
Join Date: Feb 2004
Posts: 8,190

Submissions (19)

Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)

2008 Spell olympics - Fire - SilverApproved Map: Old School Alliance TacticsHero Contest #2 - 3rd PlaceSpell making session 2 winner

Default

Quote:
//use of thistype because it might not be called by a simple wheel
Doesn't matter, any struct that extends simplewheel also counts as a simplewheel. "thistype" gets replaced with the implementing struct's name at compile time anyway so it will say simplewheel in the final code.


The sudden drop in fps would suggest that a lot more code is suddenly being executed. Two scenarios come to mind: either one of the loops isn't exiting properly or the timer starts expiring way more often.

I don't see how the timer could do that, but to rule it out completely change your code so that you start the timer in an onInit method and then don't start/pause it in the create/wUnpause/wPause methods.

As for the loops, I found a bug in listModule that would cause it to bug if a null struct instance (0) was accidentally added to the list, however I don't see you doing that anywhere and besides, if anything this bug would cause the loop to exit sooner. Still, you can fix it by changing the if statement in the listAdd method to if inlist or destroying or this==0 then.

Other than this, I'm out of ideas since the other loops appear like they should be completely unaffected by pausing/unpausing. Try these changes for now and if the problem persists, we'll try to figure out something else.
__________________

Last edited by Anitarf : 07-06-2011 at 07:27 AM.
Anitarf is offline   Reply With Quote
Old 07-07-2011, 12:28 AM   #11
Yrth
User
 
Yrth's Avatar
 
Join Date: Jul 2010
Posts: 76

Yrth has little to show at this moment (4)

Default

Quote:
I don't see how the timer could do that, but to rule it out completely change your code so that you start the timer in an onInit method and then don't start/pause it in the create/wUnpause/wPause methods.
k, I deleted every call on the timer and added
Expand JASS:

but the problem persisted
fixing the problem you found in ListModule had no effect either

Quote:
The sudden drop in fps would suggest that a lot more code is suddenly being executed
I feel like the odd circumstances where it occurs (mostly where it doesn't occur) should be a big clue, but I have no idea what sort of bug would result in such weird problems
and its not like its a temporary lag spike from executing a gigantic function, its permanent (probably) and only gets worse until the game crashes.


I went through the ListModule code until I understood the bug you found (and all the rest of it)
the only thing I don't understand is why
Collapse JASS:
thistype(0).prev
is equivalent to the last element in the list
is thistype(n) equal to the nth newest instantiation of a struct? but that wouldn't work either.
Yrth is offline   Reply With Quote
Old 07-07-2011, 10:42 PM   #12
Anitarf
Procrastination Incarnate


Development Director
 
Join Date: Feb 2004
Posts: 8,190

Submissions (19)

Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)

2008 Spell olympics - Fire - SilverApproved Map: Old School Alliance TacticsHero Contest #2 - 3rd PlaceSpell making session 2 winner

Default

Quote:
Originally Posted by Yrth
k, I deleted every call on the timer and added
Expand JASS:

but the problem persisted
fixing the problem you found in ListModule had no effect either
Yeah, there was another much more serious bug in ListModule that I missed. I posted a correction in my reply to the ListModule thread.

Quote:
the only thing I don't understand is why
Collapse JASS:
thistype(0).prev
is equivalent to the last element in the list
is thistype(n) equal to the nth newest instantiation of a struct? but that wouldn't work either.
thistype(0).prev is equivalent to the last element in the list because that's how the code is written. It uses the 0th index of the array, which is otherwise unused, as the head of the list. This streamlines the listAdd and listRemove methods since the head of the list is itself a node rather than being separate values. Compare the two possible implementations:
Collapse original (with fixed bugs):
module List
    private static boolean destroying = false
    private boolean inlist = false
    
    readonly static integer count = 0
    
    readonly thistype next = 0
    readonly thistype prev = 0
    
    static method operator first takes nothing returns thistype
        return thistype(0).next
    endmethod
    
    static method operator last takes nothing returns thistype
        return thistype(0).prev
    endmethod
    
    method listRemove takes nothing returns nothing
        if not inlist then
            return
        endif
        set inlist = false
        set prev.next = next
        set next.prev = prev
        set count = count - 1
    endmethod

    method listAdd takes nothing returns nothing
        if inlist or destroying or this==0 then
            return
        endif
        set inlist = true
        set last.next = this
        set prev = last
        set thistype(0).prev = this
        set next=thistype(0)
        set count = count + 1
    endmethod
    
    static method listDestroy takes nothing returns nothing
        local thistype this = last
            set destroying = true
            loop
                exitwhen this == 0
                call destroy()
                set this = prev
            endloop
            set destroying = false
    endmethod
    
endmodule
Collapse alternative:
module List
    private static boolean destroying = false
    private boolean inlist = false
    
    readonly static integer count = 0
    
    readonly thistype next = 0
    readonly thistype prev = 0

    readonly thistype first = 0
    readonly thistype last = 0
    
    method listRemove takes nothing returns nothing
        if not inlist then
            return
        endif
        set inlist = false
        if prev==0 then
            set first.next = next
        else
            set prev.next = next
        endif
        if next==0 then
            set last.prev = prev
        else
            set next.prev = prev
        endif
        set count = count - 1
    endmethod

    method listAdd takes nothing returns nothing
        if inlist or destroying then
            return
        endif
        set inlist = true
        if last==0 then
            set first.next = this
            set prev = thistype(0)
        else
            set last.next = this
            set prev = last
        endif
        set last = this
        set next = thistype(0)
        set count = count + 1
    endmethod
    
    static method listDestroy takes nothing returns nothing
        local thistype this = last
            set destroying = true
            loop
                exitwhen this == 0
                call destroy()
                set this = prev
            endloop
            set destroying = false
    endmethod
    
endmodule
__________________
Anitarf is offline   Reply With Quote
Old 07-07-2011, 11:53 PM   #13
Yrth
User
 
Yrth's Avatar
 
Join Date: Jul 2010
Posts: 76

Yrth has little to show at this moment (4)

Default

Quote:
thistype(0).prev is equivalent to the last element in the list because that's how the code is written. It uses the 0th index of the array, which is otherwise unused, as the head of the list. This streamlines the listAdd and listRemove methods since the head of the list is itself a node rather than being separate values.
ohhhh i see. I never realized you could do that

Quote:
Yeah, there was another much more serious bug in ListModule that I missed. I posted a correction in my reply to the ListModule thread.
tytyty so much
seriously i'm considering naming my firstborn anitarf
well
mb not
we'll see how much i like the kid

the wisp wheel works like a charm :DDDD
Yrth is offline   Reply With Quote
Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off


All times are GMT. The time now is 02:45 PM.


Affiliates
The Hubb The JASS Vault Clan WEnW Campaign Creations Clan CBS GamesModding Flixreel Videos

Powered by vBulletin (Copyright ©2000 - 2019, Jelsoft Enterprises Ltd).
Hosted by www.OICcam.com
IT Support and Services provided by Executive IT Services