Programmieren in der EGM Community

Aktuell werden noch Arbeiten am Forum durchgeführt, dies kann sich auf die Optik und Performance des Forums auswirken.
  • Moin!

    Ich habe mir gedacht, um LUA einsteigern ein bisschen die Arbeit auf EGM:RP Servern zu zeigen, werde ich eine kleine Erklärung und Anleitung zum Programmieren bei EGM geben.


    Hierbei werde ich folgende Punkte erklären

    • Unterschiede EGM:RP zu anderen Gamemodes
    • Wie erstellt man ein Modul und nutzt es richtig?
    • Warum lohnt es sich LUA bei EGM zu lernen?
    • Wie fügt man NPC's und Entitys hinzu?
    • Performance des Server erhalten
    • UI Ansatzweise Responsive gestalten
    • Der Vorteil vom Modularen Programmieren


    Unterschiede EGM:RP zu anderen Gamemodes

    Wer schonmal für DarkRP, TTT oder andere Gamemodes programmiert hat, wird bei EGM:RP eine ziemliche umstellungen bemerken. Mithilfe von EGM:RP ist es möglich, wesentlich weniger Redundanten (Doppelten) Code zu schreiben und viel effizienter zu arbeiten.

    Während in den meisten anderen Gamemodes die interne SQLite Datenbank von Garrys Mod oder eine externe MySQL Datenbank verwendet wird, ist das bei EGM:RP etwas anders.

    Bei EGM:RP wird zwar eine externe Datenbank verwendet, jedoch ist man nicht darauf angewiesen, diese selbst mit seinem Code anzusprechen.

    EGM:RP hat ein einzigartiges “Property” System, welches die gesamte SQL Arbeit für einen übernimmt.

    Wenn man Beispielsweise ein Geld-System in EGM:RP implementieren möchte, dann muss man nicht eine SQL Query anhand von Steam-ID usw. schreiben, sondern nutzt dieses Property-System. Man fügt dem Charakter einfach eine Property hinzu, in welcher man Charakter spezifische Daten speichern kann. Das sieht etwa so aus:


    Hierbei wird dann ein Identifier für diese Property festgelegt.

    Danach kommen einige Argumente AddProperty Funktion:

    “money” - Der Identifier über welchen wir den Wert abrufen und setzen können

    “number” - Der Typ der Property. Kann “number” “string” “table” usw. sein

    0 - Der Standardwert, wenn kein anderer gesetzt ist.


    Dann gibt es noch 2 Funktionen:

    Die erste Funktion Validiert quasi die Eingabe (per Code oder per F6 Menü)

    In diesem Beispiel wird nur geschaut, ob der zu speichernde Wert auch wirklich eine Zahl ist.

    Die zweite Funktion gibt an, an wen der Wert genetworked werden soll.



    Ist eine Property ersteinmal hinzugefügt, dann kann sie überall abgerufen und gesetzt werden:

    Lua
    local money = character:GetProperty(“money”, 0)

    Das zweite Argument gibt an, welcher Wert genutzt werden soll, sollte money nil sein.

    In unserem Fall ebenfalls die 0.

    Das setzen ist ebenso einfach:

    Lua
    character:SetProperty(“money”, 1000)

    Mit diesem System spart man sich sowohl das erstellen, von neuen SQL Tabellen sondern auch das Schreiben der SQL Querys, überall wo das Geld gesetzt werden soll.



    Wie erstellt man ein Modul und nutzt es richtig?

    Eine zweite Besonderheit in EGM:RP ist der Modulare Aufbau.

    Jedes Feature liegt in einem einzelnen Modul, welches aktiviert oder deaktiviert werden kann.

    Solch ein Modul kann man mit einem selbst geschriebenen Addon vergleichen.

    Es kann dabei dann eine oder mehrere Client, Shared und Server Dateien geben.

    Normalerweise sieht ein Modul wiefolgt aus:

    Modul.png



    In der cl_advancedinventory, sh_advancedinventory, sv_advancedinventory ist der jeweilige Code drin.

    Die sh_index.lua und die sh_config.lua sind etwas besonders. Die sh_index.lua ist Standardmäßig die einzige Datei in dem Modul, welche bei Aktivierung automatisch ausgeführt wird. Deshalb werden in dieser sh_index.lua die anderen Dateien hinzugefügt.

    Das sieht dann in der einfachsten Variante wie folgt aus:


    Hier ist ein Leeres Modul, welches den Aufbau Symbolisiert: https://www.dropbox.com/s/lplqk4v0cpj3…module.rar?dl=0



    Warum lohnt es sich LUA bei EGM zu lernen?

    EGM:RP nimmt dir viel Arbeit beim Programmieren ab.

    Sobald man dieses Property und dieses Modul System verstanden hat, ist man in der Lage mit wenig Programmierkenntnisse viele und relativ große Features zu schreiben.

    EGM:RP bietet ebenfalls eine vielzahl von nützlichen Funktionen, welche vor allem für den Anfang zum lernen hilfreich sein können.

    Ebenfalls hat man, wenn man es ernst meint mit dem LUA lernen einige direkte Ansprechpartner, welche einem auch bei simpleren Problemen hilfestellung Leisten können (dafür biete ich mich jederzeit an)

    Wie fügt man NPC's und Entitys hinzu?

    Hier nun noch einmal die Erklärung, wie man denn seine NPC’s und Entitys mit seinen Modulen verknüpfen kann.

    Das werde ich etwas mehr am Code zeigen. Wir packen in unser Plain Modul eine Server Side Funktion, welche die HP auffüllt. Das sieht dann wiefolgt aus:



    Code: sv_plainmodule.lua
    PlainModule = PlainModule or {} --Sicher gehen, dass der PlainModule Table existiert
    
    function PlainModule:RestoreHP(ply)
        ply:SetHealth(ply:GetMaxHealth())
        ply:ChatPrint(“Du wurdest geheilt.”)
    end

    Danach muss der NPC im folgenden Ordner erstellt werden:

    /garrysmod/gamemodes/hdrrp/entities/entities/healer/

    (In meinem Fall ist das Beispiel von HDR:RP)

    Im Healer Ordner kommen dann folgende Dateien:


    Code: cl_init.lua
    include("shared.lua")
    
    function ENT:Draw()
        self:DrawModel()
    end



    Lua: shared.lua
    ENT.Type = "ai"
    ENT.Base = "base_ai"
    
    
    ENT.PrintName = "Heiler"
    ENT.Category = "EGM:RP"
    
    
    ENT.Spawnable = true
    ENT.AdminSpawnable = true


    Über PlainModule:RestoreHP(Caller) in der init.lua (Server-Seitig) rufen wir dann die Methode auf.

    Ebenfalls kann hier ein net.Start gemacht werden, um ein UI aus eurer cl_plainmodule.lua aufzurufen.


    Performance auf dem Server erhalten

    Wenn wir früher oder später möchten, dass unser Server mehr als 10-20 Spieler hat, lohnt es sich, hier und dort über die Performance nachzudenken. Mir geht es hier Hauptsächlich darum, Tick und Think Hooks zu vermeiden.

    Die Tick und Think Hook wird jeden Frame auf dem Client und jeden Tick auf dem Server aufgerufen. Das ist je nach Tickrate bis zu 66 mal pro Sekunde auf dem Server und je nach Client bis zu ca. 200 mal pro Sekunde auf dem Client.

    Ich habe bisher in meiner gesamten Zeit als LUA Entwickler (inzwischen über 2 Jahre) keinen einzigen Anwendungsfall gehabt, wo ich eine dieser Hooks wirklich brauchte. Es gibt nahezu immer eine Lösung, welche etwas Performanter ist (und wenn es am Ende ein Timer ist, der 1x in der Sekunde auslöst und nicht 200x)

    Man darf das auch nicht überdramatisieren, denn nur mit einer einfachen if Abfrage wird man in einer Think hook keinen großen Unterschied merken. Man sollte jedoch wirklich vermeiden, große Code-Blöcke dort auszuführen.

    Ein absolutes NO-GO ist, in einer dieser Hooks Networking zu machen (Also einer der :SetNW Funktionien oder ein net.Start) Damit wird euer Server extremst an Performance verlieren.


    UI Ansatzweise Responsive gestalten

    Hier möchte ich noch einen kleinen Tipp beim erstellen eines UI (User Interface) geben.

    Wir haben einige wenige Spieler in EGM, welche nicht mit Full-HD auflösung Spielen (zb. 1280x 1024)

    Bei solchen Spielern das UI komplett gleich aussehen zu lassen, habe ich selbst auch noch nicht geschafft, da meine Funktion (die gleich folgt) noch keine Seitenverhältnisse beachtet. Trotzdem werdet ihr mit Nutzung dieser Funktionen solchen Spielern zumindest einen kleinen gefallen tun.

    Lua: Alle Client Dateien
    function RWidth(pixel)
        return ScrW() / (1920 / pixel)
    end
    
    
    function RHeight(pixel)
        return ScrH() / (1080 / pixel)
    end

    In der Funktion wird davon ausgegangen, dass der PC auf dem das UI getestet wird Full-HD ist. Da ihr in Garrys-Mod Positions und Größenwerte in Pixel angibt, solltet ihr diese Funktionen benutzen, um die Pixel für niedrigere Auflösungen jeweils runter zu rechnen.

    Das sieht dann in der Anwendung so aus:


    Lua: Client
    local button = vgui.Create(“EGMButton”)
    imageButton:SetPos(RWidth(50), RHeight(100))
    imageButton:SetSize(RWidth(150), RHeight(200))

    Hier nochmal der Vergleich ohne diese Funktion:

    Lua: Client
    local button = vgui.Create(“EGMButton”)
    imageButton:SetPos(50),100)
    imageButton:SetSize(150,200)

    Für euch wird das dann im ersten Moment nichts verändern, eben nur für Spieler mit niedrigerer Auflösung


    Der Vorteil vom Modularen Programmieren

    Wer eine Ausbildung zum Programmierer macht, sollte das bereits verinnerlicht haben.

    Versuche dein Programm so erweiterbar wie möglich zu machen.

    Anfangs ist es oft etwas mehr aufwand, ein Modul erweiterbar zu schreiben, es zahlt sich auf Lange-Zeit jedoch fast immer aus.

    Ich gebe mal ein Beispiel, was ich meine:

    Am besten lässt sich das mit einem Koch-System veranschaulichen.

    Es gibt aktuell 2 Rezepte.

    Wenn man es nicht modular macht, könnte das so aussehen:


    Man stelle sich nun vor, es gäbe 20 Rezepte und es kommen nach und nach kommen Rezepte dazu. Für jedes Rezept bräuchte man ca. 7 Zeilen Code die man jedes mal selbst eintippen muss.

    So würde das ganze Modular aussehen:


    Das wäre dann die erste Stufe des Modularen Programmierens. Das heißt du hast nicht für jede möglichkeit eine eigene Funktion, sondern eine Config-Datei und du nutzt diese dann in einer einzelnen modularen Funktion.



    Eine nächste Stufe wäre noch, diese Config-Datei mithilfe von einer Tool-Gun oder einem Command und einem User-Interface Ingame erweiterbar zu machen.



    Damit hätte man sich die gesamte Zukünftige Arbeit, für jedes neue Rezept eine neue Funktion zu schreiben gespart und kann das normale Team diese Aufgaben übernehmen lassen. (Ebenfalls mit deutlich weniger Aufwand.)

    Ein weiterer Vorteil ist, dass das Modul auch auf anderen Server verwendet werden kann.


    hi.

    Einmal editiert, zuletzt von Mekphen (3. August 2019 um 13:25)

  • Ich werde später noch ergänzen, wie man Beispielsweise NPC's oder Entitys in EGM:RP einbindet, da dass bei mir zumindest bei fast jedem Modul vorkommt und doch noch etwas anders ist.

    Auch wie man die Propertys zum Bearbeiten im F6 Menü hinzugefügt wäre noch ganz spannend (das passiert nämlich nicht automatisch)

    hi.

  • Nicht schlecht! Schöne Übersicht. :)

    GOTT

    Source Map Creator, Lua-, Java-, C#-, Unity, Unreal- und Web-Developer!

    Founder of Alphavex.com

    Ehemalige Posten:


    TWD:RP Senior-Moderator

    CW:RP Admin

    TTT Admin

    Teamspeak Admin

    Military:RP Admin

    SWTOR:RP Developer
    TWD:RP Developer
    Einfach Minecraft Developer

    Prison:RP Serverleiter