Login
Register
Menu
Home
Forum
JassDoc
Types
Functions
Variables
Help
Chat
Media
Search
Search posts
WC3 JASS.com
"The Jass Vault" plus vJASS and Zinc
WC3 Modding Information Center
Forum
Warcraft (WC3) Modding
Warcraft III Resources
Warcraft III Spells and Systems
Codes & Snippets
UnitRecycler
Warcraft III:
Maps
Models
Skins
Icons
Spells / Systems
Tools
Tutorials
Snippets
JASS vJASS Spells and Systems
Tutorials
Chat @Discord
vJASS & Zinc Documentation
For the latest documentation about how it works vJASS and Zinc language layers for Warcraft III, please follow these links:
Jasshelper documentation
-
Zinc documentation
-
WC3 Optimizer documentation
UnitRecycler
Codes & Snippets
Started by
AGD
Views
7674
Replies
3
Users
3
2
1
1
Pages:
1
Go Down
0 Members and 1 Guest are viewing this topic.
Rating
Average Score
- 5 / 5
«
Created: June 30, 2017, 12:03:32 PM by moyack
»
AGD
Newbie - level 1
Posts:
14
WC3 Models: 0
WC3 Tutorials: 0
WC3 Tools: 0
WC3 Maps: 0
WC3 Skins: 0
WC3 Icons: 0
WC3 Spells: 0
Reputation:
0
Just a Man in the Back
UnitRecycler
on:
November 02, 2016, 03:36:36 AM
Category:
Units
Language:
vJASS
Related Topics or Resources
Hibrid TimerUtils
by
moyack
[Snippet] RegisterPlayerUnitEvent
by
Magtheridon96
[Snippet] New Table
by
Bribe
[Snippet] ReviveUnit
by
Purgeandfire
A useful library which allows you to recycle units (even dead ones, but they must leave a corpse), avoiding yet another permanent 0.04kb memory leak for each future CreateUnit() call.
Script
Code: jass
library
UnitRecycler
/* v1.3b
|=============|
| Author: AGD |
|=============|
*/
requires
/*
*/
ReviveUnit
/* https://wc3modding.info/4469/snippet-reviveunit/
*/
UnitDex
/* http://www.hiveworkshop.com/threads/system-unitdex-unit-indexer.248209/
*/
optional
Table
/* https://wc3modding.info/4611/snippet-new-table/
*/
optional
TimerUtils
/* https://wc3modding.info/5352/hibrid-timerutils/
*/
optional
RegisterPlayerUnitEvent
/* https://wc3modding.info/4907/snippet-registerplayerunitevent/
This system is important because CreateUnit() is one of the most processor-intensive function in
the game and there are reports that even after they are removed, they still leave some bit of memory
consumption (0.04 KB) on the RAM. Therefore it would be very helpful if you can minimize unit
creation or so. This system also allows you to recycle dead units to avoid permanent 0.04 KB memory
leak for each future CreateUnit() call. */
//! novjass
[Credits]
Aniki - For suggesting ideas on further improvements
|-----|
| API |
|-----|
function
GetRecycledUnit
takes
player
owner,
integer
rawCode,
real
x,
real
y,
real
facing
returns
unit
/*
- Returns unit of specified ID from the stock of recycled units. If there's none in the stock that
matched the specified unit's rawcode, it will create a new unit instead
- Returns null if the rawcode's unit-type is a hero or non-existent
*/
function
GetRecycledUnitEx
takes
player
owner,
integer
rawCode,
real
x,
real
y,
real
facing
returns
unit
/*
- Works similar to GetRecycledUnit() except that if the input rawcode's unit-type is a hero, it will
be created via CreateUnit() instead
- You can use this as an alternative to CreateUnit()
*/
function
RecycleUnit
takes
unit
u
returns
boolean
/*
- Recycles the specified unit and returns a boolean value depending on the success of the operation
- Does nothing to hero units
*/
function
RecycleUnitEx
takes
unit
u
returns
boolean
/*
- Works similar to RecycleUnit() except that if <u> is not recyclable, it will be removed via
RemoveUnit() instead
- You can use this as an alternative to RemoveUnit()
*/
function
RecycleUnitDelayed
takes
unit
u,
real
delay
returns
nothing
/*
- Recycles the specified unit after <delay> seconds
*/
function
RecycleUnitDelayedEx
takes
unit
u,
real
delay
returns
nothing
/*
- Works similar to RecycleUnitDelayed() except that it calls RecycleUnitEx() instead of RecycleUnit()
*/
function
UnitAddToStock
takes
integer
rawCode
returns
boolean
/*
- Creates a unit of type ID and adds it to the stock of recycled units then returns a boolean value
depending on the success of the operation
*/
//! endnovjass
//CONFIGURATION SECTION
globals
/* The owner of the stocked/recycled units
*/
private
constant
player
OWNER =
Player
(15)
/* Determines if dead units will be automatically recycled
after a delay designated by the <constant function
DeathTime below>
*/
private
constant
boolean
AUTO_RECYCLE_DEAD =
true
/* Error debug message prefix
*/
private
constant
string
ERROR_PREFIX =
"|CFFFF0000Operation Failed: "
endglobals
/* The delay before dead units will be recycled in case AUTO_RECYCLE_DEAD == true */
static
if
AUTO_RECYCLE_DEAD
then
private
constant
function
DeathTime
takes
unit
u
returns
real
/*if <condition> then
return someValue
elseif <condition> then
return someValue
endif */
return
8.00
endfunction
endif
/* When recycling a unit back to the stock, these resets will be applied to the
unit. You can add more actions to this or you can delete this textmacro if you
don't need it. */
//! textmacro_once UNIT_RECYCLER_RESET
call
SetUnitScale
(u, 1, 0, 0)
call
SetUnitVertexColor
(u, 255, 255, 255, 255)
call
SetUnitFlyHeight
(u,
GetUnitDefaultFlyHeight
(u), 0)
//! endtextmacro
//END OF CONFIGURATION
/*==== Do not do changes below this line if you're not so sure on what you're doing ====*/
native
UnitAlive
takes
unit
u
returns
boolean
globals
private
keyword
S
private
integer
count = 0
private
real
unitCampX
private
real
unitCampY
private
integer
array
stack
private
boolean
array
stacked
endglobals
private
function
GetIndex
takes
integer
rawCode
returns
integer
static
if
LIBRARY_Table
then
local
integer
i = S.table.
integer
[rawCode]
if
i == 0
then
set
count = count + 1
set
S.table.
integer
[rawCode] = count
set
i = count
endif
else
local
integer
i =
LoadInteger
(S.hash, -1, rawCode)
if
i == 0
then
set
count = count + 1
call
SaveInteger
(S.hash, -1, rawCode, count)
set
i = count
endif
endif
return
i
endfunction
static
if
DEBUG_MODE
then
private
function
Debug
takes
string
msg
returns
nothing
call
DisplayTimedTextToPlayer
(
GetLocalPlayer
(), 0, 0, 60,
"|CFFFFCC00[Unit Recycler]|R "
+ msg)
endfunction
endif
function
GetRecycledUnit
takes
player
owner,
integer
rawCode,
real
x,
real
y,
real
facing
returns
unit
local
integer
i
if
not
IsHeroUnitId
(rawCode)
then
set
i = GetIndex(rawCode)
if
stack[i] == 0
then
set
bj_lastCreatedUnit
=
CreateUnit
(owner, rawCode, x, y, facing)
debug
call
Debug(
GetUnitName
(
bj_lastCreatedUnit
) +
" stock is empty, creating new "
+
GetUnitName
(
bj_lastCreatedUnit
))
else
static
if
LIBRARY_Table
then
set
bj_lastCreatedUnit
= S.hash[i].
unit
[stack[i]]
else
set
bj_lastCreatedUnit
=
LoadUnitHandle
(S.hash, i, stack[i])
endif
set
stacked[GetUnitId(
bj_lastCreatedUnit
)] =
false
call
PauseUnit
(
bj_lastCreatedUnit
,
false
)
call
SetUnitOwner
(
bj_lastCreatedUnit
, owner,
true
)
call
SetUnitPosition
(
bj_lastCreatedUnit
, x, y)
call
SetUnitFacing
(
bj_lastCreatedUnit
, facing)
set
stack[i] = stack[i] - 1
debug
call
Debug(
"Retrieving "
+
GetUnitName
(
bj_lastCreatedUnit
) +
" from stock"
)
endif
debug
if
bj_lastCreatedUnit
==
null
then
debug
call
Debug(ERROR_PREFIX +
"Specified unit-type does not exist"
)
debug
endif
else
debug
call
Debug(ERROR_PREFIX +
"Attemp to retrieve a hero unit"
)
return
null
endif
return
bj_lastCreatedUnit
endfunction
function
GetRecycledUnitEx
takes
player
owner,
integer
rawCode,
real
x,
real
y,
real
facing
returns
unit
if
not
IsHeroUnitId
(rawCode)
then
return
GetRecycledUnit(owner, rawCode, x, y, facing)
endif
debug
call
Debug(
"Cannot retrieve a hero unit, creating new unit"
)
return
CreateUnit
(owner, rawCode, x, y, facing)
endfunction
function
RecycleUnit
takes
unit
u
returns
boolean
local
integer
rawCode =
GetUnitTypeId
(u)
local
integer
uDex = GetUnitId(u)
local
integer
i
if
not
IsHeroUnitId
(rawCode)
and
not
stacked[uDex]
and
u !=
null
then
set
i = GetIndex(rawCode)
if
not
UnitAlive
(u)
and
not
ReviveUnit(u)
then
debug
call
Debug(ERROR_PREFIX +
"Unable to recycle unit: Unable to revive dead unit"
)
return
false
endif
set
stacked[uDex] =
true
call
PauseUnit
(u,
true
)
call
SetUnitOwner
(u, OWNER,
true
)
call
SetUnitX
(u, unitCampX)
call
SetUnitY
(u, unitCampY)
call
SetUnitFacing
(u, 270)
call
SetWidgetLife
(u,
GetUnitState
(u,
UNIT_STATE_MAX_LIFE
))
call
SetUnitState
(u,
UNIT_STATE_MANA
,
GetUnitState
(u,
UNIT_STATE_MAX_MANA
))
//! runtextmacro optional UNIT_RECYCLER_RESET()
set
stack[i] = stack[i] + 1
static
if
LIBRARY_Table
then
set
S.hash[i].
unit
[stack[i]] = u
else
call
SaveUnitHandle
(S.hash, i, stack[i], u)
endif
debug
call
Debug(
"Successfully recycled "
+
GetUnitName
(u))
return
true
debug
else
debug
if
stacked[uDex]
then
debug
call
Debug(ERROR_PREFIX +
"Attempt to recycle an already recycled unit"
)
debug
elseif
u ==
null
then
debug
call
Debug(ERROR_PREFIX +
"Attempt to recycle a null unit"
)
debug
else
debug
call
Debug(ERROR_PREFIX +
"Attempt to recycle a hero unit"
)
debug
endif
endif
return
false
endfunction
function
RecycleUnitEx
takes
unit
u
returns
boolean
if
not
RecycleUnit(u)
then
call
RemoveUnit
(u)
debug
call
Debug(
"Cannot recycle the specified unit, removing unit"
)
return
false
endif
return
true
endfunction
//! textmacro DELAYED_RECYCLE_TYPE takes EX
private
function
RecycleTimer$EX$
takes
nothing
returns
nothing
local
timer
t =
GetExpiredTimer
()
static
if
LIBRARY_TimerUtils
then
call
RecycleUnit$EX$(GetUnitById(GetTimerData(t)))
call
ReleaseTimer(t)
else
local
integer
key
=
GetHandleId
(t)
static
if
LIBRARY_Table
then
call
RecycleUnit$EX$(S.hash[0].
unit
[
key
])
call
S.hash[0].remove(
key
)
else
call
RecycleUnit$EX$(
LoadUnitHandle
(S.hash, 0,
key
))
call
RemoveSavedHandle
(S.hash, 0,
key
)
endif
call
DestroyTimer
(t)
endif
set
t =
null
endfunction
function
RecycleUnitDelayed$EX$
takes
unit
u,
real
delay
returns
nothing
static
if
LIBRARY_TimerUtils
then
call
TimerStart
(NewTimerEx(GetUnitId(u)), delay,
false
,
function
RecycleTimer$EX$)
else
local
timer
t =
CreateTimer
()
static
if
LIBRARY_Table
then
set
S.hash[0].
unit
[
GetHandleId
(t)] = u
else
call
SaveUnitHandle
(S.hash, 0,
GetHandleId
(t), u)
endif
call
TimerStart
(t, delay,
false
,
function
RecycleTimer$EX$)
set
t =
null
endif
endfunction
//! endtextmacro
//! runtextmacro DELAYED_RECYCLE_TYPE("")
//! runtextmacro DELAYED_RECYCLE_TYPE("Ex")
function
UnitAddToStock
takes
integer
rawCode
returns
boolean
local
unit
u
local
integer
i
if
not
IsHeroUnitId
(rawCode)
then
set
u =
CreateUnit
(OWNER, rawCode, unitCampX, unitCampY, 270)
if
u !=
null
then
set
i = GetIndex(rawCode)
call
SetUnitX
(u, unitCampX)
call
SetUnitY
(u, unitCampY)
call
PauseUnit
(u,
true
)
set
stacked[GetUnitId(u)] =
true
set
stack[i] = stack[i] + 1
static
if
LIBRARY_Table
then
set
S.hash[i].
unit
[stack[i]] = u
else
call
SaveUnitHandle
(S.hash, i, stack[i], u)
endif
debug
call
Debug(
"Adding "
+
GetUnitName
(u) +
" to stock"
)
return
true
debug
else
debug
call
Debug(ERROR_PREFIX +
"Attemp to stock a null unit"
)
endif
set
u =
null
debug
else
debug
call
Debug(ERROR_PREFIX +
"Attemp to stock a hero unit"
)
endif
return
false
endfunction
static
if
AUTO_RECYCLE_DEAD
then
private
function
OnDeath
takes
nothing
returns
nothing
local
unit
u =
GetTriggerUnit
()
if
not
IsUnitType
(u,
UNIT_TYPE_HERO
)
and
not
IsUnitType
(u,
UNIT_TYPE_STRUCTURE
)
then
call
RecycleUnitDelayed(u, DeathTime(u))
endif
set
u =
null
endfunction
endif
private
module
Init
static
if
LIBRARY_Table
then
static
TableArray hash
static
Table table
else
static
hashtable
hash =
InitHashtable
()
endif
private
static
method
onInit
takes
nothing
returns
nothing
local
rect
bounds =
GetWorldBounds
()
static
if
AUTO_RECYCLE_DEAD
then
static
if
LIBRARY_RegisterPlayerUnitEvent
then
static
if
RPUE_VERSION_NEW
then
call
RegisterAnyPlayerUnitEvent(
EVENT_PLAYER_UNIT_DEATH
,
function
OnDeath)
else
call
RegisterPlayerUnitEvent(
EVENT_PLAYER_UNIT_DEATH
,
function
OnDeath)
endif
else
local
trigger
t =
CreateTrigger
()
local
code
c =
function
OnDeath
local
integer
i = 16
loop
set
i = i - 1
call
TriggerRegisterPlayerUnitEvent
(t,
Player
(i),
EVENT_PLAYER_UNIT_DEATH
,
null
)
exitwhen
i == 0
endloop
call
TriggerAddCondition
(t,
Filter
(c))
endif
endif
static
if
LIBRARY_Table
then
set
hash = TableArray[0x2000]
set
table = Table.
create
()
endif
// Hides recycled units at the top of the map beyond reach of the camera
set
unitCampX = 0.00
set
unitCampY =
GetRectMaxY
(bounds) + 1000.00
call
RemoveRect
(bounds)
set
bounds =
null
endmethod
endmodule
private
struct
S
extends
array
implement
Init
endstruct
endlibrary
«
Last Edit: December 19, 2017, 11:32:05 PM by moyack
»
moyack
Site Owner
Administrator
Posts:
971
WC3 Models: 20
WC3 Tutorials: 17
WC3 Tools: 19
WC3 Maps: 12
WC3 Skins: 0
WC3 Icons: 1
WC3 Spells: 16
Reputation:
1153
Site Admin - I love fix things
Re: UnitRecycler
Reply #1 on:
November 02, 2016, 10:51:45 AM
Nice!!! a unit recycler system
This remembers an old one I did with Damage detection integrated. Here's the link:
https://wc3modding.info/4529/system-unit-recycler-simple-damage-detection-system/
One thing to know: is this system capable to manage buildings and summoned units?
WC3 Modding Information Center
AGD
Newbie - level 1
Posts:
14
WC3 Models: 0
WC3 Tutorials: 0
WC3 Tools: 0
WC3 Maps: 0
WC3 Skins: 0
WC3 Icons: 0
WC3 Spells: 0
Reputation:
0
Just a Man in the Back
Re: UnitRecycler
Reply #2 on:
November 05, 2016, 09:25:50 AM
Oh, nice to know that you already have conceived the concept a long time ago =D Though the two resources have a bit different approach.
Btw, mine does not account for summoned units and structures yet.
BillBurning
Lurker - level 2
Posts:
2
WC3 Models: 0
WC3 Tutorials: 0
WC3 Tools: 0
WC3 Maps: 0
WC3 Skins: 0
WC3 Icons: 0
WC3 Spells: 0
Reputation:
0
User
Re: UnitRecycler
Reply #3 on:
June 28, 2018, 03:46:18 AM
Great, really need a covered space for the equipment other
Print
Pages:
1
Go Up
« previous
next »
WC3 Modding Information Center
Forum
Warcraft (WC3) Modding
Warcraft III Resources
Warcraft III Spells and Systems
Codes & Snippets
UnitRecycler
PortaMx-SEF 1.54
|
PortaMx © 2008-2015
,
PortaMx corp.
Search
Username
Password
Always stay logged in
Forgot your password?