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

[System] Item Removal System

Your function names are too vauge.

Your coding is JASS-bourne,meaning you code like in JASS. We are in vJASS now bro.

It would be better if you use structs and this:http://www.hiveworkshop.com/forums/jass-resources-412/repo-comment-headers-192184/

I suggest you using Table,so that it would not waste hash tables.

Also,we don't use any TriggerAddAction,it always creates new thread,so we only use TriggerAddCondition because its much faster and doesn't create new thread.
 
Level 29
Joined
Oct 24, 2012
Messages
6,543
I didn't know tht about triggeraddaction ill have to change them over to triggeraddcondition. And what do u mean by my function names r 2 vague ? I don't like big function names. As for using table I haven't used anything anyone else created so I'm not sure about using table. I may change it so it can use it but 255 has tables is a lot to go through lol.

I didn't think structs would matter to use them here. Not: I have not used structs much at all so I do not know a lot of stuff about there efficiency in coding and everything like tht. I hope to be able to sit down and learn them soon.

I like the commenting thing I have up top short and to the point. Easy to find how to install use and so on. I will take a look at the comment link tht u gave me and I'll see if I like it better I will change it.
 
Last edited:
Level 29
Joined
Oct 24, 2012
Messages
6,543
Being able to pause the timer makes sense tht should be easy enough to do. What do u mean by pauseItemDecay and resumeItemDecay ? We're u just suggesting names to use for pausing the timer ?

On the function names im not sure ill ever change them I like them short it's easy to understand.

And since This is a public resource I think I will switch if over so it uses table.

Edit: I hope to be able to add the pause timer option and to make it useable with table when I get out of work. Thx for your suggestions plz keep them coming lol
 
Last edited:
Level 29
Joined
Oct 24, 2012
Messages
6,543
added the pause item timer function. lets u pause and unpause timer when u want.

also trying to get it to work w Table by bribe. i have to learn structs tho. if anyone could tell me how to assign items like i did above and how to use the condition like i did above to see if it is in Table ? ik how to create a Table array ( i think thts the one i need ) thx in advance
 
Level 29
Joined
Oct 24, 2012
Messages
6,543
ive been told do not pause repeating timers. if u pause them destroy them and remake them. what should i do then ?

edit: i think i got the table working right

edit2: i have noticed a problem tho. a pre created unit tht drops item on death does not trigger the player unit drops item event. gonna have to fix this b4 it becomes a viable system. any ideas ? i was think of every 1 second i can enumerate all items in map but id rather not do tht since u would have to set a boolean if u dont want tht item to be removed ( quest item ). all items tht were created in the editor would be removed also if i do it this way

i think i found a solution when a unit dies i can enumerate items in area around were the unit died. mybe this will work?
 
Last edited:
Seriously, this system is far too inefficient for a public resource, for several reasons:

1) Enuming all items in map area each timer interval AND looping through an array of all stored items at the same time just to decrease the item counter?
Use an item indexing system instead and use the event fired on registering the item instead. Most item indexers have all possible ways to create items on ground covered so you can avoid that enum.

2) You do not need to loop through the arrays of items every time. Instead, sort the items in your array depending on the time remaining with a linked list (that way you only need to loop through the items that decayed). When an item timer is paused, remove that item from the linked list and add it back in as soon as the timer is resumed. That way you only need to loop through all the items when an item is created or removed.

3) Your system does not have any protection against killing or removing items. Killed or removed items should be cleared from the system automaticly

4) You can avoid the search loop in your pickup trigger by having an array storing the current position in the item table (well, in this case, speed doesn't matter that much, I think, so it should be okay to loop here).

5) Improve the structure of your code to improve readability, especially the conditions.
 
Level 29
Joined
Oct 24, 2012
Messages
6,543
Well tht should help w a couple of things only problem I have is when u kill a unit and the unit drops an item the event unit drops item doesn't fire for them. I meant to have another event tht fires when a unit does then it will enum items. I forgot to out tht in and remove the one tht enum items every second.

When an item gets killed sold or removed by some other means definitely has to be covered in this system. To be honest I just forgot about tht lol thx

I only have one item timer. When the timer goes off it just adds a +1 to each item in the array. Tht way when the item array hits ur specific time u want the items to remove at then the item is removed.

Also can u check and see I'm not sure I'm using table the right way. When I enum items its supposed to check the isnotintable condition the one w enum items. It does work when first adding the item to table but when enumerating through items it still enumerates the items tht r in table. Ill have to check all of these suggestions after work. Thx for the good suggestions. I'm not sure if I will use indexer or anything like tht but I will check what's the best way to do it and go from there.

also next time u comment on something plz say the function name w the comment.
 
Last edited:
Jesus, will someone ever make an Item Indexer and post it in the JASS section? :(

edit

JASS:
struct Items extends array
function PauseItemTimer takes boolean b returns nothing
function DoNotRemoveItem takes item itm, boolean b returns nothing
function RemoveItemWithDiffTime takes item i, integer T returns nothing

Honestly, the API isn't very good :/

DoNotRemoveItem isn't a proper function name in any programming/scripting language.

struct Items is too vague. The name should be referring to some sort of recycler or recycling unit.
Something like ItemSweeper or MapItemCleaner or whatever. Anything specific to this library would be good.

PauseItemTimer is also a pretty bad name as it can be referring to any timer that deals with items.

You have 2 options here:
  • Move the functions to the body of the struct so you can shorten the names after beefing up the struct name.
  • Beef up the function names so that they fit into the library. Also, follow everyone's naming conventions here :v.

Personally, I would just put them in the struct because coming up for a good name for the second function is really difficult.

JASS:
struct ItemSweeper extends array
    static method start takes nothing returns nothing
    static method pause takes nothing returns nothing
    static method resume takes nothing returns nothing

    static method isPaused takes nothing returns boolean
    static method isRunning takes nothing returns boolean

    static method protectItem takes item it returns nothing
    static method unprotectItem takes item it returns nothing
    static method isItemProtected takes item it returns boolean

    static method setItemExpiration takes item it, real time returns nothing
    static method getItemExpiration takes item it returns real
endstruct
 
Last edited:
Level 29
Joined
Oct 24, 2012
Messages
6,543
ok tht makes sense. hopefully i can change them like tht soon. i just started learning structs so i think i need to learn a little more about them. hopefully trying to make this a good system will do tht for me. it may take a while since i dont have much time to work on this stuff atm but hopefully soon i can do it. thx for ur suggestions
 
Last edited:
It would need to hook CreateItem or at least provide a function for creating items that would index the items on its own.

EnumItems would only need to be called once at t = 0 to catch items created by some other source like external .j files (Blizzard.j for example)

This indexer would also listen to Shop events and run code accordingly.
Can't think of anything else that would be needed.

Really, the only thing that's stopping some people is the hooking.
Hook just seems... sloppy.
 
Level 29
Joined
Oct 24, 2012
Messages
6,543
Mybe I could make a function or method tht takes the same fields as create item but also adds it to my item removal system? Tht way instead of doing call createitem they call my custom function ? What are ur thoughts on tht ? It would get rid of the enum items which would be really nice but it would require ppl using this system to call the custom function to create items. I would still need to enumerate items when a unit is killed tho otherwise it will miss the items tht killed units drop. But if these units are made to drop item on death through triggers this would be fine.
 
Last edited:
Level 29
Joined
Oct 24, 2012
Messages
6,543
mybe something like this ? if u think this is a good idea do u have a better name lol ? i was thinking just createItem since the normal one is CreateItem.
JASS:
    static method createItemPlusIndex takes integer id, real x, real y returns item // better name ?
        local item itm
        local thistype this
        set itm = CreateItem( id, x, y)
        call this.create( itm)
        return itm
    endmethod
 
Level 29
Joined
Oct 24, 2012
Messages
6,543
which one is the way i should do it in my system ? i could put it in as a struct or a function.

the other thing to take in as consideration is how fast is enumerating through items with a condition tht checks if its in Table ?
Also how fast is Getwidgetlife ? i am using this every second. so if you think tht is too much to do in a second then i will have to change tht.
It loops through all the structs so its called as many times as there is items on the map.

the only other thing to deal w after this is to decide whats the best way to add items to the system tht drop on unit death. i could put a requirement tht all item drops tht deal w a unit death have to be triggered. which i believe most are triggered anyways. i do not believe this will affect when a unit has an inventory and drops items on death.
 
Last edited:
deathismyfriend said:
Also how fast is Getwidgetlife ? i am using this every second. so if you think tht is too much to do in a second then i will have to change tht.

Don't be silly, you can do 500 GetWidgetLife checks and it wouldn't matter.

deathismyfriend said:
which one is the way i should do it in my system ? i could put it in as a struct or a function.

You don't need to do this. An Item Indexer (a totally other resource) would have to take care of that shit for you.

Almia said:
Mag
ItemDex?

Yes.
1h55G743Uov.png


deathismyfriend said:
the other thing to take in as consideration is how fast is enumerating through items with a condition tht checks if its in Table ?

You wouldn't need to check if they're in the Table with a search, you would have to use another table to store booleans while using their handle Ids as indexes.

deathismyfriend said:
the only other thing to deal w after this is to decide whats the best way to add items to the system tht drop on unit death. i could put a requirement tht all item drops tht deal w a unit death have to be triggered. which i believe most are triggered anyways. i do not believe this will affect when a unit has an inventory and drops items on death.

There's a limit to how far the items can spawn from the dead unit right?
Create a rect with a certain size and center it around a dead unit, then enum the items in that rect. You would have to run this code using a 0-second timer to be safe though.
 
Level 29
Joined
Oct 24, 2012
Messages
6,543
Ok thx for the advice and is there a link to ItemDex ?
@Almia: sry didn't know u were suggesting a system / resource.

The way I check tht there in Table is
JASS:
ItemTable.has( GetHandleID( item))
Is the the right way ?

And as for the small rect I created one and made a timer .25 seconds after unit death it seems to work good I was hoping there was a better way but thx for clearing tht up for me.
Umm only one problem. Can u tell me how to store things other than integers in Table by Bribe ?

Thx for all ur help. Thx for ur help to Almia
 
I checked your updated system and you still loop through all items in the table every timer interval. I already explained this is not needed because:

1) You can count up the game time instead of decreasing the remaining time of existance for items. It's basicly the "if the prophet does not go to the mountain, the mountain walks to the prophet" kind of idea.
2) Store your items in a table keyed by the expected time removal; every time the global game counter is incremented, you only need to check the items that are keyed to that specific counter value

Easy way to get rid of useless looping in the periodic timer function.


@ offtopic: Yes please, we want some ItemDex!
 
Ah come on... it isn't that complicated:
You count up game time with a timer iterating a global integer by 1 every second. Then you store your items to a table, parent key is the game time integer when the item is created + amount of time until it disappears. Then you store that item to that parentkey.

Every second you can now check all items inside this particular parent key. Pro solution: use a stack or linked list.


This is the optimized system written in pseudo-code:

Item adding mechanic:
- get global time integer
- add the item to the table:
parent key = global time integer + time until item is removed
child key = number of items listed to that parent key + 1 (better solution: add it to a stack)
- store the parent and child key of that item in the same table by parent key = GetHandleId(item) to avoid search loops when wanting to remove the item before it times out

Remove item mechanic:
- get the parent and child key for that item in the item table by looking them up in the table (use the GetHandleId(item) parent key to get them without a search loop)
- clean the item from the table
- move the last item inside that specific parent key up to the position of the removed item (or simply use a stack to do that automaticly)
- decrement the item count for that parent key
- fire the item removal event (it should throw one!)

Every 1 seconds:
- increment global time integer
- loop through all items inside parent key = global time integer and fire the remove method for them


This is how you could write that system to make it effective. All operations are O(1) complexity instead of the O(n) that you use.
 
Good to see you used the ideas I suggested.

some things I still noticed:

1) the time interval until a dropped item is enumed by a rect seems pretty random. Why 0.25 seconds? did you test that? Make sure the interval is as short as possible, to avoid cross-interactions and possible bugs. I bet that 0.00 seconds is enough.

2) your destroy method should have a protection against double frees (you know, people can remove items by trigger and forget to unregister the item to the system before). Add an if GetItemTypeId != 0 then block around RemoveItem and SetWidgetLife.

3) You can get rid of a lot of methods in your API by combining functionality in similar methods.
- resume and pause should be combined to one method: static method pause takes boolean returns nothing (boolean true = pausing, boolean false = unpausing, just like PauseUnit() native)
- createItem should be removed. addItem is enough imho. It shouldn't be the task of this system to actually create the item that you want to add
- protect and unprotect item should be combined to one method like pause and unpause
- isTimerPaused and isTimerRunning are redundant. Remove isTimerPaused.

4) You never define the size of the rect. You definitely should! Also, why a preplaced rect? Simply create a private rect on init by your system!

5) Something that is not neccessarily connected to your system, but should be included:
People usually have inventory systems that drop items instantly back on the ground if they can not be carried by the specific hero/unit. People can abuse this to reset the timer on the item infinitely even if they are not allowed to pick that item up. The item should only be cleared from the system if it remains in the inventory longer than 0.01 seconds [time span should be configurable, in case people use inventory systems with delays].
 
Level 29
Joined
Oct 24, 2012
Messages
6,543
Ok some good points the protect item and unprotected item and the pause and resume we're suggested that way by magtheridon that's y there like that. The createitem will be removed the getunittypeid will be put in there and ill check o. The other stuff u suggested and hopefully be able to do all of it. The inventory thing is a great idea that should be easy to detect. Ill have to check on the istimerpaused and the other one I may of not noticed I had the one when I was typing it and thx for all ur help.
about the preplaced rect i didnt know u could create a rect till recently lol. also r u sure that get itemTypeID will work?
 
Last edited:
You can rely on RegisterPlayerUnitEvent to shorten the Init function and to make things more efficient overall after implementing this into a large map with a lot of triggers running on the same events.

JASS:
static method addItem takes item itm returns nothing
    local thistype data = thistype.create( itm)
endmethod
->
JASS:
static method addItem takes item itm returns nothing
    call create(itm)
endmethod

To get rid of the evil red BJ call to get the playable map rect, hold Ctrl and click on it in the editor. Have fun c: (You'll see how you can inline it)

The addManipItem function crashes the thread because data has no value when you call data.create(itm).

These are some of the things I can notice.
 
Level 29
Joined
Oct 24, 2012
Messages
6,543
i thought that this was a safe BJ event to use ? plz correct me if im wrong
JASS:
TriggerRegisterAnyUnitEventBJ

this method
JASS:
private static method addManipItem takes nothing returns boolean
            /* passes manipulated items to AddItem method and checks if timer is running */
            local item itm = GetManipulatedItem()
            local thistype data
            if not itemTable.has(GetHandleId( itm)) and not dontRemoveItem.has(GetHandleId( itm)) then
                call data.create( itm)
            endif
            return false
        endmethod
does have something stored in itm. it gets the dropped item that triggers this to run. it then checks if its in the tables i have made. if it isnt then it adds it to the table through the create method. also its updated if i have to change the other BJs then i will update again.
 
I was referring to the GetPlayableMapRect() BJ :p
It's totally fine, but it's useless because it just returns a rect global variable.

When I said that addManipItem is reading invalid variables, I was referring to the data variable.

I just realized that create is a static method so data will be ignored when parsing this to JASS code ;/

In that case, you don't need data. You can simply do call create(itm).
 
Top