Szene News Strategien Aktuelle Replays inWarcraft.de Foren Warcraft-Mapping inDota.de
 


Sicherer und effizienter Jass Code

zum Anfang Einleitung

Folgendes Tutorial basiert auf dem bereits auf englisch existierendem Tutorial von Themerion auf wc3c.net. Es ist großteils nur eine Übersetzung mit ein paar Ergänzungen. Es dient hauptsächlich den Usern untern euch, die das Tutorial noch nicht kennen oder der englischen Sprache nicht mächtig sind.

zum Anfang Allgmeine Sicherheitsaspekte

  • Die Funktionen UnitDamagePoint bzw. UnitDamagePointLoc verursachen eine Desynchronisation auf Mac Computern.
  • Der 8192te Index eines Arrays wird vergessen, wenn das Spiel gespeichert und geladen wird.
  • TriggerSleepAction ignoriert den „Warten auf Spieler...“ Dialog in Multiplayer Spielen.
  • Das Zerstören eines Timers und das darauffolgende Nullen der Variable kann das Spiel zum Absturz bringen.
  • Funktionen, die Nichts zurückgeben, sollten nicht an Filter oder Conditions übergeben werden.
  • Das Zerstören von Triggern sollte vermieden werden (v.a. wenn im auszuführendem Code Waits vorkommen. Dies kann dazu führen, dass zwei Handles die gleiche ID bekommen und das Spiel somit abstürzt).
  • GetWidgetLife(UNIT) <= 0.405 
    ist keine sichere Variante um zu überprüfen, ob eine Einheit tot ist. Die sicheren Varianten sind:
    GetUnitTypeId(UNIT) == 0 or IsUnitType(UNIT, UNIT_TYPE_DEAD)
    
    bzw.
    UNIT == null or IsUnitType(UNIT, UNIT_TYPE_DEAD)
    
  • Weiterhin sollte man noch die Liste bekannter Fehler beachten.

zum Anfang Allgmeine Effizienzaspekte

  • TriggerConditions sind schneller als TriggerActions, dürfen jedoch keine Waits beinhalten.
  • JassHelper kann Funktionen inlinen, was sie wesentlich schneller macht, als einen normalen Funktionsaufruf. Dabei darf die Funktion nur aus der return Anweisung bestehen und ihre Parameter müssen in der Reihenfolge verwendet werden, wie sie deklariert wurden. Bsp.:
    function GetAllowedTarget takes unit u returns boolean
        return not IsUnitType( u, UNIT_TYPE_DEAD )
    endfunction
    
  • Wenn man triggerspezifische Variablen mehr als zweimal in einer Funktion benützt, sollte man sie in einer lokalen Variable abspeichern, als dauernd ihren Wert abzufragen. Bsp.:
    // schlecht
    function actions takes nothing returns nothing
        if( IsUnitType( GetTriggerUnit(), UNIT_TYPE_HERO ) and GetWidgetLife( GetTriggerUnit() ) > 1000.00 and GetUnitAbilityLevel( GetTriggerUnit(), ‚Avul‘ ) > 0 ) then
        // ...
    endfunction
     
    // besser
    function actions takes nothing returns nothing
        local unit u = GetTriggerUnit()
    if( IsUnitType( u, UNIT_TYPE_HERO ) and GetWidgetLife( u ) > 1000.00 and GetUnitAbilityLevel( u, ‚Avul‘ ) > 0 ) then
        // ...
        set u = null
    endfunction
    

zum Anfang Einheitengruppen (group)

Wie einige von euch vermutlich bereits wissen, verursachen Einheitengruppen Memory Leaks, wenn sie nicht zerstört werden( DestroyGroup ). Jedoch muss man dadurch immer wieder eine neue Gruppe erstellen – was ein wenig Zeit benötigt – und unter gewissen Umständen können auch durch das Zerstören Memory Leaks übrig bleiben. Die Lösung dafür ist eine globale Gruppe (wie man sie z.B. in GroupUtils zur Verfügung gestellt wird -> ENUM_GROUP ), die wir dann nur leeren müssen ( ClearGroup ) und uns somit das dauernde Erstellen/Zerstören, was v.a. bei periodischen Dingen vorkommen kann, ersparen. Beispiel von Themerion:
scope GroupEx
 
globals
    private group tempGroup
endglobals
 
function DoSomething takes nothing returns nothing
// Empty group before usage
    call ClearGroup(tempGroup)
 
// Use tempGroup for whatever you need!
// *** EXAMPLE ***
    call GroupEnumUnitsInRange(tempGroup,X,Y,500,null)
    call GroupIssuePointOrder(tempGroup,0,0,"attack")
endfunction
 
public function InitTrig takes nothing returns nothing
    //....
    set tempGroup=CreateGroup()
endfunction
 
endscope
Manchmal hat man mit nur einer Gruppe natürlich nicht genug, jedoch kann man sich einfach einen eigenen GroupStack basteln. Beispiel von Themereion:
// Instead of destroying the group,
// just empty it, and leave it for the next struct.
 
struct Data
    group g
 
    method create takes nothing returns Data
        local Data d=Data.allocate()
        if d.g==null then
            set d.g=CreateGroup()
        endif
        return d
    endmethod
 
    method onDestroy takes nothing returns nothing
        call GroupClear(.g)
    endmethod
endstruct
oder mittels GroupUtils:
struct Data
    group g
 
    method create takes nothing returns Data
        local Data d=Data.allocate()
        set d.g=NewGroup()
        return d
    endmethod
 
    method onDestroy takes nothing returns nothing
        call ReleaseGroup(.g)
    endmethod
endstruct
Eine auch sehr häufig benutzte Funktion ist das Durchgehen aller Einheiten in einer Einheitengruppe und dementsprechende Aktionen mit der betroffenen Einheit anstellen. Dabei gibt es grundsätzlich zwei Möglichkeiten:
function foo takes group g returns nothing
    local unit u = null
 
    loop
        set u = FirstOfGroup( g )
        exitwhen u == null
        call GroupRemoveUnit( g, u )
        // tue dinge mit u
    endloop
endfunction
oder:
function actions takes nothing returns nothing
    // tue dinge mit GetEnumUnit()
endfunction
 
 
function foo takes group g returns nothing
    call ForGroup( g, function actions )
endfunction
Dabei stellt die zweite Möglichkeit nicht nur eine sicherere Variante dar (NULL-Lücken bringen das Durchlaufen der Gruppe nicht frühzeitig zum Beenden), sondern auch eine schnellere Variante. Um auch auf externe Dinge in der group_callback Funktion Zugriff zu haben, können wir einfach temporäre globale Variablen verwenden. Eine weitere, sehr praktische Möglichkeit schnell und effizient Aktionen an einer Gruppe von Einheiten auszuüben ist es, den BoolExpr Parameter zu „missbrauchen“. Diese Möglichkeit bietet sich aber nur an, wenn man nur einmal über eine Gruppe iterieren will und sie nicht auf Dauer speichern will. Ein Beispiel an Hand GroupUtils, vJass structs und der neuesten JassHelper Version:
struct spell
    unit caster
    static spell tempthis
 
    static method group_filter takes nothing returns boolean
        local spell this = spell.tempthis
 
        call UnitDamageTarget( this.caster, GetFilterUnit(), 800, false, false, null, null, null )
        return false
    endmethod
 
    static method create takes unit c, real tx, real ty returns spell
        local spell this = spell.allocate()
 
        set this.caster = c
        set spell.tempthis = this
        call GroupEnumUnitsInRange( ENUM_GROUP, tx, ty, 800, function spell.group_filter )
 
        return this
    endmethod
endstruct

zum Anfang Schlusswort

Das war nun eine kleine Einführung der wichtigsten Dinge, die man bezüglich triggern beachten sollte, wenn man effizient und sicher bleiben will. Natürlich gäbe es noch viele andere Themen, die man hier erwähnen könnte, aber das würde den Rahmen eines kleinen Tutorials bei weitem sprengen und ich denke, dass die angeführten Dinge, vor allem für "Neueinsteiger", am Interessantestem sein dürften.
zum Anfang



1: computerfuzzi (Gastuser) 21.03.2010 - 23:57
Gast
Gast
ich frag mich immer warum jeder units = null macht obwohl sie keinen leak hinterlassen :)

2: Kueken  22.03.2010 - 14:07
11 Kommentare
Registriert: 24.07.2007
Soweit ich weiss haben Einheiten auch das Problem, dass die HandleId nicht freigegeben wird, wenn noch lokale Variablen auf die Einheit verweisen, genau wie alle anderen handles auch.

Kommentar abgeben

Du solltest dich vor dem Kommentieren einloggen.



Grafischer Code zur Spamvermeidung


 
Keine Matches.
Stream-Name Zuschauer
Back2Warcraft156
Kalipso9
PraDo8
» Livestream Übersicht

Welche Warcraft Script-Sprache gefällt euch am besten?

   GUI (57)
(48%)
   ich benutze keine Trigger/Scripts (25)
(21%)
   vJass (13)
(11%)
   Jass (7)
(6%)
   cJass (6)
(5%)
   eine andere (4)
(3%)
   ZinC (3)
(3%)
   Boa (3)
(3%)
   Total: 118

Archiv
 


Counter-Strike: Global Offensive

ingame Netzwerk
Counter-Strike: Global Offensive | Diablo 3 | Dota 2 | League of Legends | Quake 3 | Starcraft 2 | Torchlight 2 | Warcraft 3 | World of Warcraft | Hearthstone | Heroes of the Storm | Kino, TV, Film und Promis | Diablo 3 Items und Gegenstände | Call of Duty | Automaten-Kaffee Shop

Support | AGB | Probleme mit der Werbung melden
Online Werbung | Mediadaten | Unternehmen | Karriere | Impressum

© ingame GmbH, ingame™, in™ und incup™ sind eingetragene Markenzeichen der ingame GmbH. Verwendung von Inhalten nur mit schriftlicher Genehmigung.