Zeige Ergebnis 1 bis 3 von 3
  1. #1
    Sektionsleiter Maps Benutzerbild von WaterKnight
    Registriert seit
    Aug 2003
    BNet Account
    WaterKnight
    Beiträge
    4.420

    [vJass] Shared Memory

    Da vielleicht nicht jeder den Adventskalender verfolgt und dort mein Tutorial vernommen hat und es da auch nicht so toll einsichtlich ist, poste ich es nochmal hier. Es ging um zwei Triggersysteme und eines davon ist Shared Memory.

    Der Code ist exemplarisch, das Prinzip von Relevanz. Behaupte aber, leserlich genug zu schreiben, dass man durchsteigen kann.

    Man kann nur eine bestimmte Anzahl an HashTables nutzen[1]. Ein HashTable reicht für die meisten Sachen, deswegen möchte ich den lieber schön aufteilen, statt mehrere zu benutzen. Nun bietet vJass die key-Funktion an, mit der man jeweils einen neuen Integer bekommt, damit man ihn dann als Schlüssel für den HashTable benutzen kann. Allerdings bekommt man mit key nur eine eindimensionale Reihe an Zahlen, man bekommt nicht nochmal eine andere Reihe, wo abermals alle Zahlen drin wären. Deshalb sollte die Funktion doch imho für den Haupt-Table eingesetzt werden, spezielle Tables haben dann wohl sowieso ihre eigene Art, an Schlüssel zu kommen[2]. Außerdem fängt die key-Funktion bei 0 oder 1 mit der Vergabe von Schlüsseln an anstatt beim Integerminimum[3], damit sind schonmal die Hälfte der rund 4 Milliarden Slots verschossen. Das gefällt mir nicht - ich versuchs zu ändern. Des Weiteren braucht man oft noch eine dritte Dimension im Table, weil man beispielsweise einer Einheit eine unbestimmt große Reihe an Fähigkeiten zuordnen möchte und für diese Einheit selbst schon einen der beiden Schlüssel benötigt[4]. Also zerhacke ich die verfügbaren keys Portionen, um eine dritte Dimension reinzubekommen, so dass jede Einheit dann nicht nur über einen key für Fähigkeiten verfügt sondern eine ganze Reihe von diesen. Damit das noch effektiv ist, mache ich das nicht wie bei Defragmentierung dynamisch, dass ich die Größe dieser Reihe nach Bedarf immer neu setzen und mir dann einen neuen Ort suchen würde, wo es hinpässe, sondern ich mach' es einfach statisch mit einer Maximalgröße. Entscheidend ist also, dass wenn ich Reihen von Werten einem Objekt zuordnen möchte, ich nur den ersten key übergebe und alle anderen werden aus dem Positionsindex in der Reihe berechnet, sind somit für diese eine Reihe (Array) reserviert.

    1. (auch wenn man die schlecht sprengen wird, falls man nicht gerade ein System hat, dass die dynamisch alloziert oder ein arithmetisches Array davon hat)
    2. (zum Beispiel durch Multiplikation und Potenzen)
    3. -(28)4/2 = -231 = -2147483648
    4. (oder sie zumindest in einen einbindet)

    Benötigt:
    • Structfollowers
    • Ein paar Basis-Globals

      //! runtextmacro Folder("BasicConstants")
      globals
      constant integer STRUCT_MAX = 8190
      constant integer STRUCT_MIN = 1

      constant integer STRUCT_BASE = STRUCT_MAX + 1
      constant integer STRUCT_EMPTY = STRUCT_MIN - 1

      constant integer NULL = STRUCT_EMPTY
      endglobals
      endscope

    • wenig Mathe

      //! runtextmacro Folder("Math")
      //! runtextmacro Struct("Integer")
      static integer MIN = -2147483645
      endstruct
      endscope

      //! runtextmacro StaticStruct("Math")
      //! runtextmacro LinkToStaticStruct("Math", "Integer")

      static method RandomI takes integer lowBound, integer highBound returns integer
      return GetRandomInt(lowBound, highBound)
      endmethod
      endstruct

    • CreateSimpleAddState (ist so mein Standard-Textmacro, um einfache abstrakte, numerische Werte als Structmembers zu erstellen)

      //! textmacro CreateSimpleAddState takes type, defaultValue
      $type$ value

      method Get takes nothing returns $type$
      return this.value
      endmethod

      method Set takes $type$ value returns nothing
      set this.value = value
      endmethod

      method Add takes $type$ value returns nothing
      call this.Set(this.Get() + value)
      endmethod

      method Start takes nothing returns nothing
      call this.Set($defaultValue$)
      endmethod

      method Subtract takes $type$ value returns nothing
      call this.Set(this.Get() - value)
      endmethod
      //! endtextmacro

    • GameCache und HashTable (muss ich hier nicht unbedingt aufführen, ist ersichtlich)


    Code:

    //! runtextmacro Folder("Memory")
    //! runtextmacro Folder("IntegerKeys")
    //! runtextmacro Struct("Array")
    static constant integer EMPTY = -1
    static constant integer OFFSET = 8192
    static constant integer SIZE = 8192 //das heißt, dass man in einem Array maximal 8192 Werte speichern kann, die Zahl macht Sinn wegen dem Arraysize-Limit, von Structs kann man ja auch nur etwa so viele Instanzen haben
    static constant integer STARTED = 0 //im ersten Index wird die Anzahl der Elemente im Array gekennzeichnet

    //! textmacro Memory_IntegerKeys_Array_CreateType takes name, type, bugConverter
    static method Count$name$s takes integer parentKey, integer key returns integer
    return (thistype.EMPTY + Memory.IntegerKeys.GetInteger(parentKey, key))
    endmethod

    static method Count$name$sByHandle takes handle handleSource, integer key returns integer
    return Count$name$s(GetHandleId(handleSource), key)
    endmethod

    static method Get$name$ takes integer parentKey, integer key, integer index returns $type$
    return Memory.IntegerKeys.Get$name$(parentKey, key + thistype.EMPTY + index + 2)
    endmethod

    static method Get$name$ByHandle takes handle handleSource, integer key, integer index returns $type$
    return Get$name$(GetHandleId(handleSource), key, index)
    endmethod

    static method Contains$name$ takes integer parentKey, integer key, $type$ value returns boolean
    local integer iteration = Count$name$s(parentKey, key)

    loop
    exitwhen (iteration < thistype.STARTED)

    exitwhen (Get$name$(parentKey, key, iteration) == value)

    set iteration = iteration - 1
    endloop

    if (iteration < thistype.STARTED) then
    return false
    endif

    return true
    endmethod

    static method Add$name$ takes integer parentKey, integer key, $type$ value returns boolean
    local integer count = Count$name$s(parentKey, key) + 1

    call Memory.IntegerKeys.SetInteger(parentKey, key, count - thistype.EMPTY)

    call Memory.IntegerKeys.Set$name$(parentKey, key + thistype.EMPTY + count + 2, value)

    return (count == thistype.STARTED)
    endmethod

    static method Add$name$ByHandle takes handle handleSource, integer key, $type$ value returns boolean
    return Add$name$(GetHandleId(handleSource), key, value)
    endmethod

    static method Remove$name$ takes integer parentKey, integer key, $type$ value returns boolean
    local integer count = Count$name$s(parentKey, key)

    local integer iteration = count

    loop
    debug exitwhen (iteration < thistype.STARTED)

    exitwhen (Get$name$(parentKey, key, iteration) == value)

    set iteration = iteration - 1
    endloop

    debug if (iteration < thistype.STARTED) then

    debug call BJDebugMsg("Failed to remove "+$BugConverter$(value)+" from array "+I2S(key)+" of parentKey "+I2S(parentKey)+" ("+I2S(count)+")")

    debug else
    call Memory.IntegerKeys.Set$name$(parentKey, key + thistype.EMPTY + iteration + 2, Get$name$(parentKey, key, count))

    set count = count - 1

    call Memory.IntegerKeys.SetInteger(parentKey, key, count - thistype.EMPTY)
    debug endif

    return (count == thistype.EMPTY)
    endmethod

    static method Remove$name$ByHandle takes handle handleSource, integer key, $type$ value returns boolean
    return Remove$name$(GetHandleId(handleSource), key, value)
    endmethod

    static method Random$name$ takes integer parentKey, integer key, integer lowerBound, integer higherBound returns $type$
    return Get$name$(parentKey, key, Math.RandomI(lowerBound, higherBound))
    endmethod

    static method Random$name$ByHandle takes handle handleSource, integer key, integer lowerBound, integer higherBound returns $type$
    return Random$name$(GetHandleId(handleSource), key, lowerBound, higherBound)
    endmethod

    static method Random$name$All takes integer parentKey, integer key returns $type$
    return Random$name$(parentKey, key, thistype.STARTED, Count$name$s(parentKey, key))
    endmethod
    //! endtextmacro

    //! runtextmacro Memory_IntegerKeys_Array_CreateType("Boolean", "boolean", "B2S")
    //! runtextmacro Memory_IntegerKeys_Array_CreateType("Integer", "integer", "I2S")
    //! runtextmacro Memory_IntegerKeys_Array_CreateType("Real", "real", "R2S")
    //! runtextmacro Memory_IntegerKeys_Array_CreateType("String", "string", "")
    endstruct
    endscope

    //! runtextmacro Struct("IntegerKeys")
    static HashTable CACHE

    //! runtextmacro LinkToStruct("IntegerKeys", "Array")

    //! runtextmacro InitLinksToStruct_Start()
    //! runtextmacro InitLinksToStruct_NewMember("Array")
    //! runtextmacro InitLinksToStruct_Ending()

    static method RemoveChild takes integer parentKey returns nothing
    call CACHE.RemoveMission(parentKey)
    endmethod

    //! textmacro Memory_IntegerKeys_CreateType takes name, type
    static method Set$name$ takes integer parentKey, integer key, $type$ value returns nothing
    call CACHE.$name$.Set(parentKey, key, value)
    endmethod

    static method Set$name$ByHandle takes handle handleSource, integer key, $type$ value returns nothing
    call Set$name$(GetHandleId(handleSource), key, value)
    endmethod

    static method Remove$name$ takes integer parentKey, integer key returns nothing
    call CACHE.$name$.Remove(parentKey, key)
    endmethod

    static method Remove$name$ByHandle takes handle handleSource, integer key returns nothing
    call Remove$name$(GetHandleId(handleSource), key)
    endmethod

    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    static method Get$name$ takes integer handleSource, integer key returns $type$
    return CACHE.$name$.Get(handleSource, key)
    endmethod

    static method Get$name$ByHandle takes handle handleSource, integer key returns $type$
    return Get$name$(GetHandleId(handleSource), key)
    endmethod
    //! endtextmacro

    //! runtextmacro Memory_IntegerKeys_CreateType("Boolean", "boolean")
    //! runtextmacro Memory_IntegerKeys_CreateType("Integer", "integer")
    //! runtextmacro Memory_IntegerKeys_CreateType("Real", "real")
    //! runtextmacro Memory_IntegerKeys_CreateType("String", "string")

    static method Init takes nothing returns nothing
    set CACHE = HashTable.Create()
    endmethod
    endstruct

    //! runtextmacro Folder("StringKeys")
    //! runtextmacro Struct("Array")
    static constant integer EMPTY = -1
    static constant integer STARTED = 0

    //! textmacro Memory_StringKeys_Array_CreateType takes name, type, bugConverter
    static method Count$name$s takes string parentKey, string key returns integer
    return (thistype.EMPTY + Memory.StringKeys.GetInteger(parentKey, key))
    endmethod

    static method Get$name$ takes string parentKey, string key, integer index returns $type$
    return Memory.StringKeys.Get$name$(parentKey, key + I2S(thistype.EMPTY + index + 2))
    endmethod

    static method Contains$name$ takes string parentKey, string key, $type$ value returns boolean
    local integer iteration = Count$name$s(parentKey, key)

    loop
    exitwhen (iteration < thistype.STARTED)

    exitwhen (Get$name$(parentKey, key, iteration) == value)

    set iteration = iteration - 1
    endloop

    if (iteration < thistype.STARTED) then
    return false
    endif

    return true
    endmethod

    static method Add$name$ takes string parentKey, string key, $type$ value returns boolean
    local integer count = Count$name$s(parentKey, key) + 1

    call Memory.StringKeys.SetInteger(parentKey, key, count - thistype.EMPTY)

    call Memory.StringKeys.Set$name$(parentKey, key + I2S(thistype.EMPTY + count + 2), value)

    return (count == thistype.STARTED)
    endmethod

    static method Remove$name$ takes string parentKey, string key, $type$ value returns boolean
    local integer count = Count$name$s(parentKey, key)

    local integer iteration = count

    loop
    debug exitwhen (iteration < thistype.STARTED)

    exitwhen (Get$name$(parentKey, key, iteration) == value)

    set iteration = iteration - 1
    endloop

    debug if (iteration < thistype.STARTED) then

    debug call BJDebugMsg("Failed to remove "+$BugConverter$(value)+" from array "+key+" of parentKey "+parentKey+" ("+I2S(count)+")")

    debug else
    call Memory.StringKeys.Set$name$(parentKey, key + I2S(thistype.EMPTY + iteration + 2), Get$name$(parentKey, key, count))

    set count = count - 1

    call Memory.StringKeys.SetInteger(parentKey, key, count)
    debug endif

    return (count == thistype.EMPTY)
    endmethod

    static method Random$name$ takes string parentKey, string key returns $type$
    return Get$name$(parentKey, key, Math.RandomI(thistype.STARTED, Count$name$s(parentKey, key)))
    endmethod
    //! endtextmacro

    //! runtextmacro Memory_StringKeys_Array_CreateType("Boolean", "boolean", "B2S")
    //! runtextmacro Memory_StringKeys_Array_CreateType("Integer", "integer", "I2S")
    //! runtextmacro Memory_StringKeys_Array_CreateType("Real", "real", "R2S")
    //! runtextmacro Memory_StringKeys_Array_CreateType("String", "string", "")
    endstruct
    endscope

    //! runtextmacro Struct("StringKeys")
    static GameCache CACHE

    //! runtextmacro LinkToStruct("StringKeys", "Array")

    //! runtextmacro InitLinksToStruct_Start()
    //! runtextmacro InitLinksToStruct_NewMember("Array")
    //! runtextmacro InitLinksToStruct_Ending()

    static method RemoveChild takes string parentKey returns nothing
    call CACHE.RemoveMission(parentKey)
    endmethod

    //! textmacro Memory_StringKeys_CreateType takes name, type
    static method Set$name$ takes string parentKey, string key, $type$ value returns nothing
    call CACHE.$name$.Set(parentKey, key, value)
    endmethod

    static method Remove$name$ takes string parentKey, string key returns nothing
    call CACHE.$name$.Remove(parentKey, key)
    endmethod

    static method Get$name$ takes string parentKey, string key returns $type$
    return CACHE.$name$.Get(parentKey, key)
    endmethod
    //! endtextmacro

    //! runtextmacro Memory_StringKeys_CreateType("Boolean", "boolean")
    //! runtextmacro Memory_StringKeys_CreateType("Integer", "integer")
    //! runtextmacro Memory_StringKeys_CreateType("Real", "real")
    //! runtextmacro Memory_StringKeys_CreateType("String", "string")

    static method Init takes nothing returns nothing
    set CACHE = GameCache.Create("blub")
    endmethod
    endstruct
    endscope

    //! runtextmacro StaticStruct("Memory")
    //! runtextmacro LinkToStaticStruct("Memory", "IntegerKeys")
    //! runtextmacro LinkToStaticStruct("Memory", "StringKeys")

    static method Init takes nothing returns nothing
    call IntegerKeys.Init()
    call StringKeys.Init()
    endmethod
    endstruct


    Damit bekommt man dann einen neuen Key oder ein Array von Keys für den Shared Memory:

    //! textmacro GetKey takes name
    static key $name$_BASE

    static constant integer $name$ = Math.Integer.MIN + $name$_BASE
    //! endtextmacro

    //! textmacro GetKeyArray takes name
    static key $name$_BASE

    static constant integer $name$ = Math.Integer.MIN + Memory.IntegerKeys.Array.OFFSET + $name$_BASE * Memory.IntegerKeys.Array.SIZE
    //! endtextmacro


    Eigentlich könnte man sich GetKey sparen und stattdessen immer GetKeyArray nehmen, weil der key so und so verpulvert wird, finds aber semantisch ordentlicher.

    Implementierung:

    Und so kann mans noch in ein Struct implementieren, damit es automatisch als Parentkey verwendet wird (also man der Structinstanz Werte zuordnen kann) und man ihn nicht jedesmal selbst hinschreiben muss:

    Makros dafür:

    //! textmacro Data_Create takes baseType
    method Destroy takes nothing returns nothing
    call Memory.IntegerKeys.RemoveChild($baseType$(this).Id.Get())
    endmethod
    //! endtextmacro

    //! textmacro Data_Type_Create takes baseType, whichTypeName, whichType
    method Remove takes integer key returns nothing
    call Memory.IntegerKeys.Remove$whichTypeName$($baseType$(this).Id.Get(), key)
    endmethod

    method Get takes integer key returns $whichType$
    return Memory.IntegerKeys.Get$whichTypeName$($baseType$(this).Id.Get(), key)
    endmethod

    method Set takes integer key, $whichType$ value returns nothing
    call Memory.IntegerKeys.Set$whichTypeName$($baseType$(this).Id.Get(), key, value)
    endmethod
    //! endtextmacro

    //! textmacro Data_Array_Create takes baseType, whichTypeName, whichType
    method Count takes integer key returns integer
    return Memory.IntegerKeys.Array.Count$whichTypeName$s($baseType$(this).Id.Get(), key)
    endmethod

    method Remove takes integer key, $whichType$ value returns boolean
    return Memory.IntegerKeys.Array.Remove$whichTypeName$($baseType$(this).Id.Get(), key, value)
    endmethod

    method Get takes integer key, integer index returns $whichType$
    return Memory.IntegerKeys.Array.Get$whichTypeName$($baseType$(this).Id.Get(), key, index)
    endmethod

    method Add takes integer key, $whichType$ value returns boolean
    return Memory.IntegerKeys.Array.Add$whichTypeName$($baseType$(this).Id.Get(), key, value)
    endmethod

    method Random takes integer key, integer lowerBound, integer higherBound returns $whichType$
    return Memory.IntegerKeys.Array.Random$whichTypeName$($baseType$(this).Id.Get(), key, lowerBound, higherBound)
    endmethod

    method RandomAll takes integer key returns $whichType$
    return this.Random(key, Memory.IntegerKeys.Array.STARTED, this.Count(key))
    endmethod
    //! endtextmacro


    Beispiel an Unit:

    //! runtextmacro Folder("Unit")
    //! runtextmacro Folder("Data")
    //! runtextmacro Folder("Integer")
    //! runtextmacro Struct("Array")
    //! runtextmacro Data_Array_Create("Unit", "Integer", "integer")
    endstruct
    endscope

    //! runtextmacro Struct("Boolean")
    //! runtextmacro Data_Type_Create("Unit", "Boolean", "boolean")
    endstruct

    //! runtextmacro Struct("Integer")
    //! runtextmacro LinkToStruct("Integer", "Array")

    //! runtextmacro InitLinksToStruct_Start()
    //! runtextmacro InitLinksToStruct_NewMember("Array")
    //! runtextmacro InitLinksToStruct_Ending()

    //! runtextmacro Data_Type_Create("Unit", "Integer", "integer")
    endstruct
    endscope

    //! runtextmacro Struct("Data")
    //! runtextmacro LinkToStruct("Data", "Boolean")
    //! runtextmacro LinkToStruct("Data", "Integer")

    //! runtextmacro InitLinksToStruct_Start()
    //! runtextmacro InitLinksToStruct_NewMember("Boolean")
    //! runtextmacro InitLinksToStruct_NewMember("Integer")
    //! runtextmacro InitLinksToStruct_Ending()

    //! runtextmacro Data_Create("Unit")
    endstruct

    //! runtextmacro Struct("Id")
    //! runtextmacro GetKeyArray("KEY_ARRAY")

    //! runtextmacro CreateSimpleAddState("integer", "KEY_ARRAY + this")
    endstruct
    endscope

    //! runtextmacro BaseStruct("Unit", "UNIT")
    //! runtextmacro LinkToStruct("Unit", "Data")
    //! runtextmacro LinkToStruct("Unit", "Id")

    static method Create takes <params> returns thistype
    local unit self = <unit>
    local thistype this = thistype.allocate()

    set this.self = self

    call this.Id.Start() //muss aufgerufen werden, damit die Einheit ihren Parentkey im Memory bekommt und man dann weitere Daten daran festhalten kann

    return this
    endmethod
    endstruct


    Aufruf:

    Tjo, und wenn man es nun also benutzen möchte:

    struct Eis
    //! runtextmacro GetKey("KEY")
    //! runtextmacro GetKeyArray("KUGELN_KEY_ARRAY")

    Waffle base

    method AddToUnit takes Unit whichUnit returns nothing
    call whichUnit.Data.Integer.Set(KEY, this)
    endmethod

    method AddKugel takes Eissorte whichType returns nothing
    call this.Data.Integer.Array.Add(KUGELN_KEY_ARRAY, whichType)
    endmethod

    static method Create takes nothing returns thistype
    local thistype this = thistype.allocate()

    set this.base = Waffle.Create()

    return this
    endmethod
    endstruct
    Geändert von WaterKnight (26. Dezember 2010 um 17:56 Uhr)
    Water's Footmen Wars
    Defend Wintercastle
    Mana
    God's Ascension (coming soon)
    Dark Colony (coming soon)

    Versunkene Zeiten - Vortex - Wild Scope - Hells Edge -
    Prison Break

  2. #2
    Staff Maps
    Map-Contests
    Benutzerbild von muzzel
    Registriert seit
    Sep 2008
    Ort
    BaWü
    BNet Account
    muzzel
    Beiträge
    3.229
    Coole Idee, man sollte es jedoch nicht übertreiben da Hashtables mit zunehmender Zahl von Einträgen langsamer werden.

    <Argon]> in der zeit, in der ich das mit tikz gebastelt hab, hätt ich das als 2m^2 holzskulptur schnitzen können
    <Argon]> mit nem Skalpell
    Penguin World Domination - be part of it!
    » LaTeX2png Converter | Gaias Retaliation ORPG | Ulumulu Entertainment | AAT

  3. #3
    Sektionsleiter Maps Benutzerbild von WaterKnight
    Registriert seit
    Aug 2003
    BNet Account
    WaterKnight
    Beiträge
    4.420
    Splitten könnte man schon noch, aber dann sollte man wie gesagt auf das Max von 255 HashTables achten. Man könnte diese HashTables sogar in einem Array nutzen, um dynamisch auf einen zuzugreifen und somit eine neue Dimension von genannter Größe hinzufügen.

    Also

    Code:
    static method SetInteger takes integer key, integer key2, integer key3, boolean value returns nothing
        call SaveBoolean(HashTables[key], key2, key3, value)
    endmethod
    Da hätte man allein so schon 3 Keys.
    Water's Footmen Wars
    Defend Wintercastle
    Mana
    God's Ascension (coming soon)
    Dark Colony (coming soon)

    Versunkene Zeiten - Vortex - Wild Scope - Hells Edge -
    Prison Break

Ähnliche Themen

  1. UD necropolis shared acc.
    Von PoWerJin im Forum Undead Necropolis
    Antworten: 26
    Letzter Beitrag: 18. Oktober 2008, 11:46
  2. Shared-Acc Reloaded!
    Von kOaLa4 im Forum Community Forum
    Antworten: 128
    Letzter Beitrag: 10. Januar 2006, 21:56
  3. Shared-Acc Replays!
    Von DarknessAtNoon im Forum Replay Forum
    Antworten: 8
    Letzter Beitrag: 10. Januar 2006, 15:25
  4. Shared acc HF
    Von ThaReaL im Forum Community Forum
    Antworten: 192
    Letzter Beitrag: 10. Mai 2005, 23:19

Forumregeln

  • Es ist dir nicht erlaubt, neue Themen zu verfassen.
  • Es ist dir nicht erlaubt, auf Beiträge zu antworten.
  • Es ist dir nicht erlaubt, Anhänge hochzuladen.
  • Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.
  •