private unit u
private effect fx
private integer id
private integer ci
private timer t
private integer userData
private static method Timer takes nothing returns nothing
local thistype this = GetTimerData(GetExpiredTimer())
call this.destroy()
endmethod
static method remove takes unit u, integer id returns nothing
local thistype this
local integer i = GetUnitUserData(u)
set id = id + 8191
if HaveSavedInteger(table, id, i) then
set this = LoadInteger(table, id, i)
call this.destroy()
endif
endmethod
static method addLoc takes string fx, real x, real y, real dur returns thistype
local thistype this
if dur > 0 then
set this = thistype.allocate()
set this.fx = AddSpecialEffect(fx, x, y)
set this.id = -1
set this.t = NewTimer()
call SetTimerData(this.t, this)
call TimerStart(this.t, dur, false, function Effect.Timer)
return this
endif
return 0
endmethod
static method addStack takes unit u, string fx, string attach, real dur returns thistype
local thistype this
local integer i = GetUnitUserData40;u)
local integer j
if GetUnitTypeId40;u) != 0 and not IsUnitType40;u, UNIT_TYPE_DEAD) and dur > 0 then
set this = thistype.allocate40;)
set j = LoadInteger40;table, 0, i) + 1
call SaveInteger40;table, 0, i, j)
call SaveInteger40;table, j, i, this)
set this.u = u
set this.fx = AddSpecialEffectTarget40;fx, u, attach)
set this.id = 0
set this.t = NewTimer40;)
set this.ci = j
set this.userData = i
call SetTimerData40;this.t, this)
call TimerStart40;this.t, dur, false, function Effect.Timer)
return this
endif
return 0
endmethod
static method add takes unit u, string fx, string attach, real dur, integer id returns thistype
local thistype this
local integer i = GetUnitUserData40;u)
local integer j
if GetUnitTypeId40;u41; != 0 and not IsUnitType40;u, UNIT_TYPE_DEAD41; and dur > 0 then
set id = id + 8191
if HaveSavedInteger40;table, id, i41; then
set this = LoadInteger40;table, id, i41;
if dur > TimerGetRemaining40;this.t41; then
call TimerStart40;this.t, dur, false, function Effect.Timer41;
endif
else
set this = thistype.allocate40;41;
set j = LoadInteger40;table, 0, i41; + 1
call SaveInteger40;table, 0, i, j41;
call SaveInteger40;table, j, i, this41;
set this.u = u
set this.fx = AddSpecialEffectTarget40;fx, u, attach41;
set this.id = id
set this.t = NewTimer40;41;
set this.ci = j
set this.userData = i
call SetTimerData40;this.t, this41;
call TimerStart40;this.t, dur, false, function Effect.Timer41;
call SaveInteger40;table, id, i, this41;
endif
return this
endif
return 0
endmethod
private static method deindex takes nothing returns boolean
local thistype this
local integer i = GetUnitUserData40;GetFilterUnit40;41;41;
local integer j = 1
local integer k = LoadInteger40;table, 0, i41;
loop
exitwhen j > k
set this = LoadInteger40;table, 1, i41;
call this.destroy40;41;
set j = j + 1
endloop
return true
endmethod
private static method death takes nothing returns nothing
local thistype this
local integer i = GetUnitUserData40;GetTriggerUnit40;41;41;
local integer j = 1
local integer k = LoadInteger40;table, 0, i41;
loop
exitwhen j > k
set this = LoadInteger40;table, 1, i41;
call this.destroy40;41;
set j = j + 1
endloop
endmethod
private method destroy takes nothing returns nothing
local integer i = this.userData
local integer j = LoadInteger40;table, 0, i41;
if this.id != -1 then
call RemoveSavedInteger40;table, 0, i41;
call RemoveSavedInteger40;table, this.id, i41;
call SaveInteger40;table, this.ci, i, LoadInteger40;table, j, i41;41;
call RemoveSavedInteger40;table, j, i41;
call SaveInteger40;table, 0, i, j - 141;
set this.u = null
endif
call DestroyEffect40;this.fx41;
set this.fx = null
call ReleaseTimer40;this.t41;
set this.t = null
call this.deallocate40;41;
endmethod
private static method onInit takes nothing returns nothing
local integer index
set index = 0
loop
call TriggerRegisterPlayerUnitEvent40;trig, Player40;index41;, EVENT_PLAYER_UNIT_DEATH, null41;
set index = index + 1
exitwhen index == bj_MAX_PLAYER_SLOTS
endloop
call TriggerAddAction40;trig, function Effect.death41;
set func = Condition40;function Effect.deindex41;
call RegisterUnitIndexEvent40;func, UnitIndexer.DEINDEX41;
endmethod
endstruct
endlibrary
Utilisation : Permet de créer des effets sur une unité pendant x secondes et de les ranger en catégorie, sachant que les effets d'une même catégorie ne se stackent pas sur une même unité (l'effet spécial en lui même ne sera pas créé, mais la durée se stack).
Ajouter un effet avec catégorie :
Jass:
call Effect.add(unit u, string fx, string attachement, real duration, integer id)
Ajouter un effet sans catégorie (donc stackable) :
Jass:
call Effect.addStack(unit u, string fx, string attachment, real duration)
Ajouter un effet à un point :
Jass:
call Effect.addLoc(string fx, real x, real y, real duration)
Enlever un effet par catégorie :
Jass:
call Effect.remove(unit u, integer id)
Si vous voulez enlever un effet sans préciser la catégorie, vous avez toujours le bon vieux call Effect.destroy().
Copyright : Libre
Remarques : Ne mettez pas des effets spéciaux et des attachements différents pour une même catégorie . _________________
Dernière édition par Sapeur-Goblin le 10/04/12 17:00; édité 5 fois
Inscrit le: 23 Aoû 2007 Messages: 7143 Sujets: 147 Spécialité en worldedit: le troll, le flood, la vulgarité, mon coeur balance Médailles: 2 (En savoir plus...)
Posté le: 09/03/12 21:53 Sujet du message:
Mêmes remarques qu'ailleurs pour les noms de variables, pas de vérification de sécurité et l'utilisation de strings en argument de fonction (hormis bien entendu pour les effets en eux même)
Honnêtement c'est plutôt inutile, bien souvent on doit quand même exécuter du code quand on supprime l'effet.
Je veux dire que ça fait partie intégrante du code.
Pour ton code en lui même utiliser un seul timer pour cela est une terrible idée, c'est overkilled et imprécis, autant utiliser X timers avec un système d'attachement de donnée, tel que TimerUtils. _________________
Inscrit le: 14 Oct 2009 Messages: 719 Sujets: 40 Spécialité en worldedit: Les bugs Médailles: 1 (En savoir plus...)
Posté le: 03/04/12 17:24 Sujet du message:
Puisque je trouve cette fonction plutôt utile, surtout avec AddUnitRegeneration, ça facilite beaucoup les chose, je l'ai refaite. Sauf qu'en utilisant x timers, on peut pas détecter quand l'unité meurt, et c'est très moche d'avoir un effet qui flotte au-dessus d'une unité morte . Donc je suis sensé ajouter un trigger qui détecte la mort d'une unité pour enlever les effets ou il y a une autre solution?
Voici le code :
Secret:
Jass:
library AddUnitEffect uses TimerUtils
private struct Effect
unit u
effect fx
integer id
boolean cumul
timer t
integer i
endstruct
globals
private Effect array Ar
private integer Total = 0
endglobals
function RemoveUnitEffect takes unit u, integer id returns nothing
local Effect this
local integer i = 0
loop
exitwhen i >= Total
set this = Ar[i]
if u == this.u and id == this.id then
set this.u = null
call DestroyEffect(this.fx)
set this.fx = null
call ReleaseTimer(this.t)
set this.t = null
call this.destroy()
set Total = Total - 1
set Ar[i] = this
set i = i - 1
endif
set i = i + 1
endloop
endfunction
private function Timer takes nothing returns nothing
local Effect this = GetTimerData(GetExpiredTimer())
set this.u = null
call DestroyEffect(this.fx)
set this.fx = null
set this.t = null
call ReleaseTimer(GetExpiredTimer())
call this.destroy()
set Total = Total - 1
set Ar[this.i] = Ar[Total]
endfunction
function AddUnitEffect takes unit u, string fx, string at, real t, integer id, boolean cumul returns nothing
local Effect this
local timer Tim = NewTimer()
local boolean b = true
local integer i = 0
if GetUnitTypeId(u) != 0 and t > 0 then
loop
exitwhen i >= Total
set this = Ar[i]
if this.u == u and this.id == id and not this.cumul then
set i = Total
set b = false
if t > TimerGetRemaining(this.t) then
call TimerStart(this.t, t, false, function Timer)
endif
endif
set i = i + 1
endloop
if b then
set this = Effect.create()
set this.u = u
set this.fx = AddSpecialEffectTarget(fx, u, at)
set this.id = id
set this.cumul = cumul
set this.t = Tim
set this.i = Total
call SetTimerData(Tim, this)
call TimerStart(Tim, t, false, function Timer)
set Ar[Total] = this
set Total = Total + 1
endif
endif
endfunction
Inscrit le: 23 Aoû 2007 Messages: 7143 Sujets: 147 Spécialité en worldedit: le troll, le flood, la vulgarité, mon coeur balance Médailles: 2 (En savoir plus...)
Posté le: 03/04/12 20:12 Sujet du message:
Tes noms de variables sont toujours aussi explicites qu'un bègue ayant la maladie d'Alzheimer.
Loop, loop et encore loops :p
Y'a vraiment moyen de s'en passer dans ce cas ci ...
Détecter la mort serait en effet la chose à faire, les remove seront tout de même détectés car GetUnitTypeId renverra 0.
Mais y'a pas l'intérêt d'un code périodique, autant remove l'effet uniquement quand le temps est écoulé (ou si l'unité meurt auparavant).
C'est cela qui m'a fait dire d'utiliser X timers plutôt, parce que l'aspect cyclique n'a aucun intérêt ici.
Evidemment tu ne pourras plus détecter aussi vite les remove d'unités avec le code actuel, mais tu peux soit :
- préciser qu'il faut tuer une unité avant de la remove avec KillUnit (lame)
- détecter les remove en temps réel avec un unit indexer "moderne" tel que UnitIndexer
Sinon, encore une fois, aucune vérification de sécurité.
PS : Utilise le tag [vJass] pour tes ressources.
Ah, tu as oublié de copier le "l" de library. _________________
Inscrit le: 14 Oct 2009 Messages: 719 Sujets: 40 Spécialité en worldedit: Les bugs Médailles: 1 (En savoir plus...)
Posté le: 04/04/12 15:04 Sujet du message:
Bon, j'ai essayé de comprendre comment marchait UnitIndexer, mais franchement, ça dépasse mon niveau de jasseur du dimanche .
Si j'ai bien compris, ça attribue une valeur à chaque unité de la map, mais quelle est l'utilité si on a déjà GetHandleId(u)? C'est pour avoir des nombres moins grands et pouvoir les utiliser dans les variables arrays? Et sinon je vois pas trop comment ça permet de détecter la mort d'une unité.
*Se dit qu'il a vraiment rien compris parce que toutes les libraries que je vois sur hiveworkshop l'utilisent...*
Inscrit le: 21 Fév 2010 Messages: 1785 Sujets: 22 Spécialité en worldedit: La modestie Médailles: 1 (En savoir plus...)
Posté le: 04/04/12 19:21 Sujet du message:
Sisi, c'est pour pouvoir utiliser les arrays à la place des hashtable. La plupart des gens n'aiment pas les hashtables et d'ailleurs, c'est moins performant qu'un array.
J'ai renommé le sujet par ajouter le tag. _________________
Inscrit le: 23 Aoû 2007 Messages: 7143 Sujets: 147 Spécialité en worldedit: le troll, le flood, la vulgarité, mon coeur balance Médailles: 2 (En savoir plus...)
Posté le: 04/04/12 22:27 Sujet du message:
L'intérêt est comme tu l'as dis doit même, d'avoir un entier unique qui peut être utilisé comme un index de variable array par ex, ou de struct, etc.
De plus utiliser GetHandleId, ne garantie pas que cet id sera de nouveau utilisé, à moins que tu recycles toutes tes unités, et donc potentiellement cela peut créér des leak, ce qui est moins le cas avec un unit indexer, les id étant recyclés.
Je n'ai pas dit que l'on pouvait détecter la mort avec UnitIndexer, mais son remove (suppression de la partie sur toutes les formes, aussi bien a fin de sa décomposition que sa suppression par trigger).
La mort est facilement détectable avec l'event de mort (bien que ca ne détecte pas les résurrections, mais là aussi il me semble qu'un tel event custom est possible).
En fait c'est l'utilisation d'un bug, avec les capacités qui se basent sur "défendre" ou "défense magique", une unité reçoit l'ordre de la compétence en diverses occasions, même si celle ci est désactivée, et donc invisible. _________________
Inscrit le: 14 Oct 2009 Messages: 719 Sujets: 40 Spécialité en worldedit: Les bugs Médailles: 1 (En savoir plus...)
Posté le: 07/04/12 17:00 Sujet du message:
Mis à jour. Toutes les fonctions ont une complexité O(1), sauf pour enlever tous les effets d'une unité, mais ça, ça va être dur de faire mieux.
Sinon il y a un petit problème pour les remove d'unité : la custom value de l'unité est mise à 0 avant d'exécuter le code. Et comme je m'en sert pour enlever les effets... _________________
Inscrit le: 21 Fév 2010 Messages: 1785 Sujets: 22 Spécialité en worldedit: La modestie Médailles: 1 (En savoir plus...)
Posté le: 07/04/12 17:43 Sujet du message:
T'as un problème de copier/coller.
Pour le remove d'unité, soit tu utilises un UnitIndexer, soit tu utilises un hook (Cf. doc de jasshelper - ça doit quand même avoir des inconvénients, en plus d'être relativement lourde). _________________
Inscrit le: 23 Aoû 2007 Messages: 7143 Sujets: 147 Spécialité en worldedit: le troll, le flood, la vulgarité, mon coeur balance Médailles: 2 (En savoir plus...)
Posté le: 07/04/12 23:07 Sujet du message:
Tirlititi a écrit:
ça doit quand même avoir des inconvénients, en plus d'être relativement lourde).
Oh trois fois rien, tu détectes simplement les remove d'unité par trigger mais pas quand elle sont supprimées "naturellement" par le jeu :p
Puis franchement les hook c'est de la daube, je comprends bien l'utilité du TriggerEvaluate, mais on devrait pouvoir utiliser le hook avant ou après la fonction native et utiliser les arguments et le return de la fonction "hooké".
Autant utiliser une function custom _________________
Inscrit le: 14 Oct 2009 Messages: 719 Sujets: 40 Spécialité en worldedit: Les bugs Médailles: 1 (En savoir plus...)
Posté le: 08/04/12 10:02 Sujet du message:
Je viens de me rendre compte que ma fonction bouffe à elle seule toutes les instances de table . Bon, je crois que la seule solution est d'utiliser une hashtable :/. Je corrigerais dans la journée.
Edit : Bon, comme j'avais la flemme d'utiliser une hashtable, j'utilise une TableArray[8191]. Pour la détection des removes j'utilise UnitIndexer, mais comme je l'ai dit, je me sert de la custom value pour détruire les instances de struct, or elle est remise à 0 avant d'exécuter le code qu'on lui a donné (la suppression de la struct). Donc pour l'instant voilà ce que ça donne :
Secret:
Jass:
library Effect uses UnitIndexer, Table, TimerUtils/*
****************************************************
*
* Fonctions
* ---------
*
* - call Effect.add(unit u, string fx, string attachment, real duration, integer id)
* - call Effect.remove(unit u, integer id)
* - call Effect.addStack(unit u, string fx, string attachment, real duration)
*
****************************************************/
private unit u
private effect fx
private integer id
private timer t
private integer ci
private integer userData
private static method deindex takes nothing returns boolean
//Ne sert à rien puisque la custom value de l'unité est remise à 0
return true
endmethod
private static method Timer takes nothing returns nothing
local thistype this = GetTimerData(GetExpiredTimer())
call this.destroy()
endmethod
private static method death takes nothing returns nothing
local thistype this
local integer i = GetUnitUserData(GetTriggerUnit())
local integer j = 1
local integer k = table[0][i]
loop
exitwhen j > k
set this = table[j][i]
call this.destroy()
set j = j + 1
endloop
endmethod
static method remove takes unit u, integer id returns nothing
local thistype this
local integer i = GetUnitUserData40;u)
set id = id + 8191
set this = table[id][i]
call this.destroy40;)
endmethod
static method add takes unit u, string fx, string attach, real dur, integer id returns thistype
local thistype this
local integer i = GetUnitUserData40;u)
local integer j
if GetUnitTypeId40;u41; != 0 and not IsUnitType40;u, UNIT_TYPE_DEAD41; and dur > 0 then
set id = id + 8191
if table[id].has40;i41; then
set this = table[id][i]
if dur > TimerGetRemaining40;this.t41; then
call TimerStart40;this.t, dur, false, function Effect.Timer41;
endif
else
if recycle == 0 then
set instanceCount = instanceCount + 1
set this = instanceCount
else
set this = recycle
set recycle = recycle.recycleNext
endif
set j = table[0][i] + 1
set table[0][i] = j
set table[j][i] = this
set this.u = u
set this.fx = AddSpecialEffectTarget40;fx, u, attach41;
set this.id = id
set this.t = NewTimer40;41;
set this.ci = j
set this.userData = i
call SetTimerData40;this.t, this41;
call TimerStart40;this.t, dur, false, function Effect.Timer41;
set table[id][i] = this
endif
return this
endif
return 0
endmethod
static method addStack takes unit u, string fx, string attach, real dur returns thistype
local thistype this
if GetUnitTypeId40;u41; != 0 and not IsUnitType40;u, UNIT_TYPE_DEAD41; and dur > 0 then
if recycle == 0 then
set instanceCount = instanceCount + 1
set this = instanceCount
else
set this = recycle
set recycle = recycle.recycleNext
endif
set this.u = u
set this.fx = AddSpecialEffectTarget40;fx, u, attach41;
set this.id = 0
set this.t = NewTimer40;41;
call SetTimerData40;this.t, this41;
call TimerStart40;this.t, dur, false, function Effect.Timer41;
return this
endif
return 0
endmethod
private method destroy takes nothing returns nothing
local integer j = table[this.userData][0]
if this.id != 0 then
call table[this.id].remove40;this.userData41;
set table[this.ci][this.userData] = table[j][this.userData]
call table[j].remove40;this.userData41;
set table[0][this.userData] = j - 1
endif
call DestroyEffect40;this.fx41;
call ReleaseTimer40;this.t41;
set this.u = null
set this.fx = null
set this.t = null
set recycleNext = recycle
set recycle = this
endmethod
private static method onInit takes nothing returns nothing
local integer index
set index = 0
loop
call TriggerRegisterPlayerUnitEvent40;trig, Player40;index41;, EVENT_PLAYER_UNIT_DEATH, null41;
set index = index + 1
exitwhen index == bj_MAX_PLAYER_SLOTS
endloop
call TriggerAddAction40;trig, function Effect.death41;
set func = Condition40;function Effect.deindex41;
call RegisterUnitIndexEvent40;func, UnitIndexer.DEINDEX41;
set table = TableArray[8191]
endmethod
endstruct
endlibrary
Par contre les effets seront détruits quand le timer atteint 0 même si l'unité a été remove, puisque j'enregistre sa custom value dans la struct au moment de la création, mais en écrivant ça, je viens de me rendre compte que c'est totalement stupide puisque les index sont réutilisés, donc ça détruira aussi les effets sur une autre unité...
Edit #2 :
Bribe a écrit:
You can have up to 2 ^ 31 - 1 Table instances.
J'ai changé le code pour avoir une TableArray à la place de Table array pour rien ?
Edit #3 : Je raconte vraiment n'importe quoi, après un second test, la custom value de l'unit n'est pas remise à 0... _________________
Inscrit le: 14 Oct 2009 Messages: 719 Sujets: 40 Spécialité en worldedit: Les bugs Médailles: 1 (En savoir plus...)
Posté le: 08/04/12 19:07 Sujet du message:
Bah, j'avoue que je trouve ça plutôt inutile, mais comme c'est sensé être un peu plus optimisé... D'autant plus que ça complique pas mal la struct, mais bon.
Tu recommandes de ne pas le faire? _________________
Inscrit le: 23 Aoû 2007 Messages: 7143 Sujets: 147 Spécialité en worldedit: le troll, le flood, la vulgarité, mon coeur balance Médailles: 2 (En savoir plus...)
Posté le: 08/04/12 20:15 Sujet du message:
Il y a un monde entre choisir un algorithme approprié et utiliser de telles "optimisations".
Ça me semble évident qu'il faut éviter de faire une loop quand ce n'est pas nécessaire.
Par contre utiliser des struct extends array juste pour se passer d'appels de fonctions, je dis non.
D'une part l'api est plus moche, "static" à tout bout de champ.
D'autre part, en utilisant tes propres allocator, tu augmentes forcément le risque de bug, pour un gain en performance négligeable. _________________
Inscrit le: 14 Oct 2009 Messages: 719 Sujets: 40 Spécialité en worldedit: Les bugs Médailles: 1 (En savoir plus...)
Posté le: 10/04/12 16:16 Sujet du message:
Bon, j'ai enlevé les les customs allocators, corrigé certains "bugs", et ajouté une fonction pour créer des effets spéciaux sur des points (la base quand même...).
Secret:
Toujours un problème de copier/coller, je vois pas où est le problème
Vous ne pouvez pas poster de nouveaux sujets dans ce forum Vous ne pouvez pas répondre aux sujets dans ce forum Vous ne pouvez pas éditer vos messages dans ce forum Vous ne pouvez pas supprimer vos messages dans ce forum Vous ne pouvez pas voter dans les sondages de ce forum