Angepinnt Code Optimierung

    Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

    Es gibt Neuigkeiten! Ab sofort könnt ihr dem Donators Club auf Lebenszeit beitreten.
    Weitere Infos im Thema Donator's Club ab heute wieder verfügbar!

    • Nja da sollte ja jeder draufkommen sobald

      PAWN-Quellcode

      1. public function lacks forward declaration (symbol "StartTimer_2")


      kommt :>
      Für PlayerOnServer müsste man eben nochmal ein extra public anlegen, damit er Beispielsweise unter
      OnPlayerConnect/OnPlayerDisconnect Spieler hinzufügt/entfernt.
      Aber was soll ich sagen, ist halt die Trägheit im Alter :sleeping:

      Mta Script Editor - Work in Progress
    • Gott, warum liest sich das keiner durch?

      Naja egal, ich grab das ganze mal wieder aus.

      Logische Optimierungen

      Tja, da haben wir sie, die Logik. Viele hinterfragen überhaupt nicht was genau da eigentlich in ihrem Script passiert - aber wundern sich dann wenn es zu Server-Abstürzen, Laggs uvm. kommt. Am Ende geben sie natürlich nicht sich selbst die Schuld, sondern, wem sonst auch, der Sprache Pawn.

      Nun, fangen wir einfach an:

      PAWN-Quellcode

      1. for(new i = 0; i < MAX_PLAYERS; i++)
      2. {
      3. if(IsPlayerConnected(i)) {
      4. new string[128], name[MAX_PLAYER_NAME];
      5. GetPlayerName(i, name, sizeof(name));
      6. format(string, sizeof(string), "Name: %s ID: %d", name, i);
      7. SendClientMessageToAll(0xFF0000FF, string);
      8. }
      9. }


      Ganz einfacher Code, nicht?
      Die Schleife geht alle player IDs von 0 bis 199 durch (playerid 200 gibt es btw nicht), überprüft ob die player ID vorhanden ist, erstellt anschließend einen zwei Strings, einen mit 128 Charakteren, einen mit der Größe von MAX_PLAYER_NAME (theoretisch 24, praktisch 16). Dann wird der Name von "i" herausgefunden und der String "name" damit überschrieben. Zu guter letzt wird das ganze per printf formatiert und in der Console angezeigt.

      Dumm gecodet.

      Zum einen natürlich der viel zu große String, zum anderen aber auch der Punkt, dass wir 200 Mal zwei Variablen erstellen. Wenn ihr sowas im Script habt, tut mir euer Server jetzt schon leid.

      Die richtige Variante wäre in diesem Fall wohl eher in dieser Form:

      PAWN-Quellcode

      1. new string[32]/* don't need more */, name[MAX_PLAYER_NAME];
      2. for(new i = 0; i < MAX_PLAYERS; i++)
      3. {
      4. if(GetPlayerName(i, name, sizeof(name))) {
      5. /* Solltet ihr das nicht ganz kapieren, schaut euch die Posts auf der ersten Seite nochmal an,
      6. dann wisst ihr was ich damit bewirke */
      7. printf("Name: %s ID: %d", name, i);
      8. }
      9. }


      Andere Beispiele von vollkommen abstrakter, unverständlicher Logik sind beispielsweise solche Sachen:

      PAWN-Quellcode

      1. GetPlayerID(playerid)
      2. {
      3. return playerid;
      4. }


      Ok, ok, dieses Beispiel war vielleicht doch etwas zu fiktiv xD

      Aber so etwas kommt oft vor:

      PAWN-Quellcode

      1. stock ReturnName(playerid)
      2. {
      3. new name[MAX_PLAYER_NAME];
      4. GetPlayerName(playerid, name, sizeof(name));
      5. return name;
      6. }


      Ok, ich weiß: Viele nutzen so eine Funktion, ist ja immerhin ganz einfach damit den Spielernamen zu bekommen usw... Aber: Sie ist langsam.
      Besser wäre einfach so etwas:

      PAWN-Quellcode

      1. /* Globale Variable */
      2. new gPlayerName[MAX_PLAYERS][MAX_PLAYER_NAME]; // Neuer Array, 2-dimensional.
      3. /* Laden des Namens der playerid in den Array: */
      4. public OnPlayerConnect(playerid)
      5. {
      6. GetPlayerName(playerid, gPlayerName[playerid], MAX_PLAYER_NAME);
      7. return 1;
      8. }
      9. /* Anwendungsbeispiel */
      10. public OnPlayerCommandText(playerid, cmdtext[])
      11. {
      12. if(!strcmp(cmdtext,"/name")) {
      13. printf("%s", gPlayerName[playerid]);
      14. return 1;
      15. }
      16. return 0;
      17. }
      Alles anzeigen


      [ende]Ich hoffe ihr könnt das was ich euch gerade gezeigt habe in dieser und/oder anderer Form hernehmen. Solltet ihr keine Ahnung von dem Code hier drin haben: Scripting Basics

      Und kommt mir jetzt nicht damit dass ihr schon alles wisst. Tut ihr nicht. Ich genauso wenig. Keiner weiß alles.[/ende]

      Solltet ihr noch Ideen haben was genau ich noch hinzufügen sollte schreibt mich per PM an.

      MfG,
      Br1ght]NSG a.k.a. Bright[NSG]
    • Was den String betrifft: Wer den ersten Post von BlackFoX gelesen hat, sollte mittlerweile alles dazu wissen.

      Übrigens würde ich raten euch mit dem Lesen Zeit zu lassen. Lieber 1 Woche brauchen und dann alles wissen, anstatt 3 Stunden knallhart anschaun und am nächsten Tag alles vergessen zu haben.
    • Muss ich jetzt grad überlegen.
      Du könntest beispielsweise so etwas machen:

      PAWN-Quellcode

      1. enum e_Tor_Names {
      2. LSPD_Tor,
      3. SFPD_Tor,
      4. LVPD_Tor
      5. }
      6. new Tore[e_Tor_Names];
      7. /* Object erstellen, am besten unter OnGameModeInit() : */
      8. Tore[LSPD_Tor] = CreateObject(...);
      9. /* Command zum Bewegen : */
      10. if(!strcmp(cmdtext,"/lspd")) {
      11. MoveObject(Tore[LSPD_Tor], ...);
      12. return 1;
      13. }
      Alles anzeigen


      THEORETISCH funktioniert es so, weiß nicht ob es praktisch auch funktioniert, dürfte aber in dieser Form stimmen.

      // Was ganz wichtig ist:
      Eine enum-Struktur darf NICHT so heißen wie eine Variable, führt zu Errors.
      Der "Header" der Enumeration (enum blabla) sollte IMMER einen anderen Namen haben als die dazu gehörige Variable/Array.

      Falsch:

      PAWN-Quellcode

      1. enum Everything
      2. CallCost
      3. }
      4. new Everything[Everything];


      Richtig:

      PAWN-Quellcode

      1. enum _Everything
      2. CallCost
      3. }
      4. new Everything[_Everything];
    • [NSG]Bright schrieb:



      Andere Beispiele von vollkommen abstrakter, unverständlicher Logik sind beispielsweise solche Sachen:

      PAWN-Quellcode

      1. GetPlayerID(playerid)
      2. {
      3. return playerid;
      4. }


      Ok, ok, dieses Beispiel war vielleicht doch etwas zu fiktiv xD


      Nicht so fiktiv wie man vllt. denkt, es hat wirklich mal jemand im SA-MP Forum diese Funktion im "Useful Functions" Fred gepostet
      Ihr könnt euch sicherlich vorstellen, wie Y_Less danach explodiert ist... :D

      Achja übrigends zur ersten Seite, dass dcmd langsamer sei, als strcmp etc. stimmt natürlich, weils eine neue Funktion aufruft ABER
      in Verbindung mit strcmp wird dann meist strtok verwendet und das ist wiederum der CPU Killer schlecht hin und wenn man beachtet, wieviel übersichtlich dcmd das ganze Skript macht, dann kann man diesen wirklich sehr kleinen Leistungsunterschied ruhig ignorieren...

      So und damit mein Post auch noch etwas Konstruktives an Funktionen hat:

      Sparen von Zeit in Positionsvergleichen

      Eine ziemlich nützliche Funktion, die sehr oft auch von Streamern benutzt wird ist:

      Quellcode

      1. bool: isInReach(Float: x1, Float: y1, Float: z1, Float: x2, Float: y2, Float: z2, Float: reach)
      2. {
      3. return (getDistanceBetweenPoints(x1, y1, z1, x2, y2, z3) <= reach);
      4. }
      5. Float: getDistanceBetweenPoints(Float: x1, Float: y1, Float: z1, Float: x2, Float: y2, Float: z2)
      6. {
      7. return floatsqroot(floatpower(floatabs(floatsub(x1, x2)),2) + floatpower(floatabs(floatsub(y1, y2)),2) + floatpower(floatabs(floatsub(z1, z2)),2));
      8. }


      Sieht ziemlich professionell und optimiert aus, ist es aber definitiv NICHT.

      Was macht getDistanceBetweenPoints?
      Es rechnet den drei dimensionalen Pythagoras aus, also es zieht die Positionen von einander ab und berechnet den absoluten Wert um die Länge der Strecken zu erhalten, dann werden die Seiten alle mit 2 potenziert und anschließend die Wurzel draus gezogen. Klingt logisch. Ist es auch. Aber nicht effektiv.
      Zuerst einmal könnte man

      Quellcode

      1. floatpower(floatabs(floatsub(x1, x2)),2)

      durch

      Quellcode

      1. floatsub(x1, x2)*floatsub(x1, x2)

      ersetzen womit man einen Funktionsaufruf sparen würde. Der wahre Leistungsausbremser ist aber floatsqroot welche in dieser Form sehr ineffektiv ist.
      Natürlich ist diese Funktion von den Entwicklern von Pawn sehr effektiv programmiert worden, jedoch rechnet sie nunmal die Wurzel auf glaub ich 20 Stellen genau aus und das ist halt selbst mit der besten Engine leistungsfordernd.
      Zumal wir ja nichtmal die wirkliche Distanz brauchen, wir brauchen ja lediglich wissen ob die Koordinaten in Reichweite der anderen liegen.
      Durch simple mathematische Termumformungen kann man dann folgendes machen:

      Quellcode

      1. (getDistanceBetweenPoints(x1, y1, z1, x2, y2, z3)*getDistanceBetweenPoints(x1, y1, z1, x2, y2, z3) <= reach*reach)

      ist exakt das gleiche, beide Seiten wurden mit 2 potenziert, jedoch wird dadurch die Wurzel welche in getDistanceBetweenPoints steckt aufgehoben und wenn man die Funktion nun intern schreibt und weitere Kürzungen von floatpower und floatabs vornimmt die auch überflüssig werden hat man also:

      Quellcode

      1. bool: isInReach(Float: x1, Float: y1, Float: z1, Float: x2, Float: y2, Float: z2, Float: reach)
      2. {
      3. return (floatsub(x1, x2)*floatsub(x1, x2) + floatsub(y1, y2)*floatsub(y1, y2) + floatsub(z1, z2)*floatsub(z1, z2) <= reach*reach)
      4. }

      Das ist nun schon um einiges optimierter als am Anfang.
      Aber es geht noch um einiges besser, wir erinnern uns, dass Funktionsaufrufe Zeit kosten also werden auch die floatsubs alle durch ein "-" ersetzt somit haben wir:

      Quellcode

      1. bool: isInReach(Float: x1, Float: y1, Float: z1, Float: x2, Float: y2, Float: z2, Float: reach)
      2. {
      3. return ((x1- x2)*(x1-x2) + (y1-y2)*(y1- y2) + (z1-z2)*(z1- z2) <= reach*reach)
      4. }

      Nah dran am Perfekten ABER es geht natürlich immernoch besser und zwar können wir noch einen Funktionsaufruf sparen. Welchen? Richtig "isInReach"
      Also weiter optimiert:

      Quellcode

      1. #define isInReach(%0,%1,%2,%3,%4,%5,%6) \
      2. (((%0 - %3) * (%0 - %3)) + ((%1 - %4) * (%1 - %4)) + ((%2 - %5) * (%2 - %5)) <= %6 * %6)

      So und weiter gehts nicht, dieser Code ist jetzt so weit optimiert, dass er 40 mal schneller ist als der ursprüngliche Code und somit vor allem in Streamern, wo diese Funktion sehr oft aufgerufen wird, einiges an wichtiger Rechenzeit spart
      Ist übrigends nichts was ich rausgefunden habe ._. Sondern Y_Less wie auch fast alle anderen Sachen die mit SA-MP Scripting zu tun haben :D
      Naja ich hoffe mal ich konnt auch mal ein bisschen helfen
      /me legt die wunden Finger in ein Erholungsbad :D

    • Um ehrlich zu sein:

      Wenn du den Code optimierst brauchst du auch nicht länger.

      Am besten du machst es so:
      Du schreibst ein Script auf deine Art.

      Dann schreibst du ein Script auf optimierte Art und Weise, also so, dass es möglichst ressourcenschonend gecodet ist.

      Danach kannst vergleichen was 1. schneller war und 2. einfacher war.

      // Ich persönlich bin mit ressourcenschonenderen Methoden schneller.
    • Achso wenn du "länger" auf die Zeit beziehst, die es zur Entwicklung braucht dann muss ich dir zustimmen, wenn man an jeder Ecke nur rumoptimieren würde, würden sich Entwicklungszeiten mit der Zeilenanzahl expotential erhöhen. Aber so ein paar simple Sachen gehen ja schon, vor allem wenn sie schon so wie hier bereitgestellt werden und nicht selber entwickelt werden müssen. Und länger macht ja mein Beitrag dein Skript nicht, es sspart ja sogar nen paar Zeilen weils aus 2 Funktionen nen theoretischen Einzeiler macht, wobei die Anwendung die gleiche ist...
    • [NSG]Bright schrieb:

      Muss ich jetzt grad überlegen.
      Du könntest beispielsweise so etwas machen:

      PAWN-Quellcode

      1. enum e_Tor_Names {
      2. LSPD_Tor,
      3. SFPD_Tor,
      4. LVPD_Tor
      5. }
      6. new Tore[e_Tor_Names];
      7. /* Object erstellen, am besten unter OnGameModeInit() : */
      8. Tore[LSPD_Tor] = CreateObject(...);
      9. /* Command zum Bewegen : */
      10. if(!strcmp(cmdtext,"/lspd")) {
      11. MoveObject(Tore[LSPD_Tor], ...);
      12. return 1;
      13. }
      Alles anzeigen


      THEORETISCH funktioniert es so, weiß nicht ob es praktisch auch funktioniert, dürfte aber in dieser Form stimmen.

      // Was ganz wichtig ist:
      Eine enum-Struktur darf NICHT so heißen wie eine Variable, führt zu Errors.
      Der "Header" der Enumeration (enum blabla) sollte IMMER einen anderen Namen haben als die dazu gehörige Variable/Array.

      Falsch:

      PAWN-Quellcode

      1. enum Everything
      2. CallCost
      3. }
      4. new Everything[Everything];


      Richtig:

      PAWN-Quellcode

      1. enum _Everything
      2. CallCost
      3. }
      4. new Everything[_Everything];


      jo wenn man das so macht Bringt das auch was ? :D ^^
      Lust auf russisch roulette ?
      Okay...
      ... Ich hol mal meine Automatik ;D

    • Das bringt soviel, das die Übersicht vorhanden ist wie Tjong schon erwähnte und du dir Linien Sparst was wieder zum anderen Punkt führt,
      ausserdem tragen enum klassen dazu bei das weniger Resourcen verbraucht werden, das kann man auch daran merken wenn
      1000 Variablen erstellst die alle Indexiert sind und eine enum erstellst die das enthält und dies einmal verknüpfst, die Datei größe steigern
      sich bei dieser ausrichtung der 1000 Index Variablen
      Mfg. BlackFoX_UD_ alias [BFX]Explosion

    • Technisch gesehen wenig bis gar nix, jedoch ist es meiner Meinung nach viel übersichtlicher wenn man es so macht.

      Ich empfehle es dir aufjedenfall:

      //

      So, ich hab jetzt selbst eine kleine Frage.
      Und zwar habe ich mir eine Alternative zur ganzen Sache mit IsPlayerConnected usw. ausgedacht.

      Ich zeigs am besten einfach:

      PAWN-Quellcode

      1. new bool:SlotActive[200] = false;
      2. #define IsConnected(%1) SlotActive[%1] == true
      3. #define foreach(%1,%2) new %1 = 0; \
      4. for(; %1 < %2; %1++) if(IsConnected(%1))
      5. public OnPlayerConnect(playerid) {
      6. SlotActive[playerid] = true;
      7. foreach(players,MAX_PLAYERS) {
      8. SendClientMessage(players,COLOR_RED,"Test");
      9. printf("%d", players);
      10. return 1;
      11. }
      Alles anzeigen


      Nun frage ich mich aber, ob das ganze auch schneller ist.

      Theoretisch dürfte es ja schneller sein, immerhin sind defines und variablen laut Speed Liste schneller als native Funktionen wie z.B. IsPlayerConnected.

      Leider kann ich es aber nicht mit genug Leuten testen um zu einem schlüssigen Ergebnis zu kommen. Daher frage ich euch ob ihr wisst ob die Standart Variante:

      PAWN-Quellcode

      1. for(new i = 0; i < MAX_PLAYERS; i++) if(IsPlayerConnected(i))

      oder meine:

      PAWN-Quellcode

      1. foreach(p2, MAX_PLAYERS)

      schneller ist.
    • Für alle die ihren AMX Code per DisAMX (nicht zu verwechseln mit DeAMX) optimieren wollen:

      Addition
      Beispiel: a = b + 2

      PAWN-Quellcode

      1. load.pri %[b] // primary register
      2. const.alt 2 // alternate
      3. add // primary = primary + alternate
      4. stor.pri %[a]


      Läßt sich optimieren durch:

      PAWN-Quellcode

      1. load.pri %[b]
      2. add.c 2
      3. stor.pri %[a]


      Vergleich: 8 Calls gegen 6 Calls.
      Die zweite Register-Variante ist um einiges schneller. (Nachzulesen Pawn Impl.)

      Auch Dec (In jeglicher Form) ist schneller als Sub (In jeglicher Form)
      Wobei dieses Defiziet zumindest auf Intel Prozessoren weniger gewichtig ist.

      Außerdem, wenn genug Dynamic Memory noch frei ist, ruhig diesen niedriger setzen.

      PAWN-Quellcode

      1. #pragma dynamic 4096

      Genügt für viele Filterscripte vollkommen.
      DMA @ Twitter: hier
      C & JAVA Videotutorials auf DevCornerNow

      Programmieraufträge & kalkulationen per PN.
      SA:MP Egal ob Fehlerreparatur oder Scriptteile, beides wird erstellt. (Auch Nischen wie SQLite können bedient werden. ;-))
      sonstige Sprachen:
      • C
      • C++
      • C#
      • D
      • PAWN
      • JavaScript (HTML5)
      • PHP
      • Perl
      • SQL
      Assembler:
      • 6502
      • x86
      • IA64
      • PowerPC

      Momentan
      • Z-C (programming language)
      • CGI-PAWN (pawn for webprogramming)


    • Hm naja zB. in nem Checkpoint Streamer:

      Quellcode

      1. #define CHECKPOINT_AMOUNT 1
      2. #define CP_UPDATE_INTERVALL 500
      3. #define STREAM_DISTANCE 50.0
      4. #define isCheckpointActive(%1) (playerData[%1][playerCheckpoint] != -1)
      5. enum ePData
      6. {
      7. playerCheckpoint
      8. }
      9. new playerData[MAX_PLAYERS][ePData];
      10. new CPcoords[CHECKPOINT_AMOUNT][4] = {
      11. {1.0, 2.0, 3.0, 4.0}
      12. };
      13. public OnGameModeInit()
      14. {
      15. SetTimer("CheckpointStreamer", CP_UPDATE_INTERVALL, true);
      16. return 1;
      17. }
      18. public OnPlayerConnect(playerid)
      19. {
      20. playerData[playerid][playerCheckpoint] = -1;
      21. return 1;
      22. }
      23. public OnPlayerDisconnect(playerid, reason)
      24. {
      25. if(isCheckpointActive(playerid))
      26. DisablePlayerCheckpoint(playerid);
      27. return 1;
      28. }
      29. public CheckpointStreamer()
      30. {
      31. for(new playerid = 0; playerid < MAX_PLAYERS; playerid++)
      32. {
      33. if(IsPlayerConnected(playerid))
      34. {
      35. new
      36. Float: px,
      37. Float: py,
      38. Float: pz;
      39. GetPlayerPos(playerid, px, py, pz);
      40. for(new checkid = 0, checkid < CHECKPOINT_AMOUNT, checkid++)
      41. {
      42. if(isInReach(px, py, pz, CPcoords[checkid][0], CPcoords[checkid][1], CPcoords[checkid][2], STREAM_DISTANCE))
      43. {
      44. if(isCheckpointActive(playerid))
      45. DisablePlayerCheckpoint(playerid);
      46. SetPlayerCheckpoint(playerid, CPcoords[checkid][0], CPcoords[checkid][1], CPcoords[checkid][2], CPcoords[checkid][3]);
      47. playerData[playerid][playerCheckpoint] = checkid;
      48. break;
      49. } else if(iplayerData[playerid][playerCheckpoint] == checkid) {
      50. DisablePlayerCheckpoint(playerid);
      51. playerData[playerid][playerCheckpoint] = -1;
      52. }
      53. }
      54. }
      55. }
      56. }
      Alles anzeigen


      kA ob der funktioniert hab ich jetzt grad mal so hier im Forum hingeskriptet, aber für so welche Sachen halt, wenn halt teilweise mehrere 1000 Aufrufe pro Sekunde stattfinden, bringt das wirklich viel.
      Im Vergleich zB. zu Commands die werden wesentlich seltener aufgerufen

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von Tjong ()