Beiträge von Lead0b110010100

    P.S: Hab folgendes gefunden:


    Code
    1. That being said, if you'd like to iterate over the list multiple times, it's probably better to use range. This is because xrange has to generate an integer object every time you access an index, whereas range is a static list and the integers are already "there" to use.


    Jetzt ist die Frage was bei "for i in range(100000000)" perfomanter ist. Das Generieren der Zahlen wenn man sie benötigt oder das einmalige Generieren der großen Liste?


    P.P.S: Interessant ist auch:


    Bitte melden Sie sich an, um dieses Bild zu sehen.

    Frage an die Entwickler:


    Wann kann es problematisch werden, wenn man irgendwo die Funktion 'xrange' benutzt? Habt ihr ein Beispiel mit Erklärung?

    Soweit ich das beurteilen kann, tuen sie das Selbe aber zu unterschiedlichen Zeiten.


    'for i in range(100000)' erstellt eben eine Liste die genauso groß ist wie die range und speichert das direkt im Speicher.

    'for i in xrange(100000)' erstellt einen Generator, der die Werte erst erstellt, wenn man sie benötigt und ist damit minimal schneller.


    Soweit ich das verstanden hab, hat sich diese Unterscheidung in Python3 sowieso erledigt, weil die 'range' Funktion IMMER die xrange Funktionalität bietet.

    Will man eine Liste muss man dort explizit casten. xrange als Funktion gibt es da nicht.

    Ich sollte dies hier auch erwähnen, damit sich keiner wundert: Ich bin bis voraussichtlich Donnerstag (exklusive) aus persönlichen Gründen verhindert und kann nicht arbeiten. Davon sind alle Gruppen, die in vorherigen Beiträgen erwähnt worden sind, betroffen ohne Ausnahmen.


    Sollte es zum noch längeren Ausfall kommen, gebe ich es rechtzeitig Bescheid. Ansonsten streiche ich einfach den Text oben durch am Freitag den 22.01.2021. Macht's gut! :)

    Bin wieder da und nehme den Service weiter auf!

    DE:

    Ich schreibe es Mal bewusst auf Deutsch, damit die meisten hier das verstehen. Ich hab ihm für 100€ ein System anfertigen lassen und bin mit dem Endresultat sehr glücklich.

    Man bekommt genau das wofür man bei ihm bezahlt, der Code lässt sich auch sehen, ist also kein Hingekrakel.


    Kann nichts bemängeln, Top Developer - Ich werde mir wahrscheinlich desöfteren von ihm helfen lassen bei den günstigen Preisen!


    EN:

    I will write that in German, so that more people can understand this text. He created a system for 100€ for me and I am really happy with the results.

    You get what you pay for, the code looks fine. Not the usual garbage you see.


    I can't really criticize anything, Top Developer - I probably will work with him in furter future again regarding the cheap prices!

    Bitte melden Sie sich an, um diesen Link zu sehen.

    Inwiefern hilft ihm Google dabei Dienstleister in der M2 Szene zu finden, die Runs bearbeiten können?

    Diese URL wird echt heftig missbraucht, Google hilft viel. Aber Google liest und versteht nicht für dich, das solltest du noch Mal tun.


    :)

    Vielen lieben Dank, hab den Bachelor aber bereits bestanden seitdem mein Thread wieder aktiv ist. :)

    Schickst du mir deinen Github Namen? Würde dir dann den Access für das Repo vergeben.

    Ich dachte ich fang direkt mal mit dem Setup an. Die aktuellste Version ist nun immer erreichbar durch folgende URL: Bitte melden Sie sich an, um diesen Link zu sehen.

    Gehostet wird das Ganze aktuell auf Github Pages, kostet nichts und funktioniert recht schnell.


    Ich habe dich in Discord hinzugefügt, können ja dann ab Mai den Rest besprechen. Womöglich arbeiten Dex und Ich bis dahin schon daran und fügen ein paar mehr Elemente hinzu.

    Also hier eine kurze Zusammenfassung:


    .epk und .eix Dateien sind zwei unterschiedliche Dinge. .eix Dateien sind sogenannte Index-Dateien, je nach Verschlüsselungstyp beinhalten sie Metadaten darüber, wie die .epk (also die eigentlich "verschlüsselte") Datei verschlüsselt und komprimiert und wie die Dateien zusammengefügt wurden. Stark vereinfacht natürlich.


    Diese Dateien kannst du nicht mit einem Texteditor öffnen, die Dateiendung kann jeder Server selbst festlegen. Häufig nutzen Server bekannte Datentypen wie .txt und .rar um unerfahrene Nutzer wie dich zusätzlich zu verwirren und das Gefühl von einer 'unknackbaren Verschlüsselung' zu suggerieren, weil sind ja neue Datentypen und so.


    Diese Verschlüsselung findet nicht zufällig statt, es gibt einen sogenannten INDEX-Schlüssel und einen PACK-Schlüssel, welche Respektive zur Ver und Entschlüsselung genutzt werden. Diese sind in Programmen wie dem Etermanager standartmäßig vorkunfiguriert. Deshalb kann man mit diesen beiden Tools z.B: in das Dateisystem eines Clienten hineinsehen und kopieren, verändern usw.


    Server wie Rubinum nutzen fortschrittlichere Methoden der Verschlüsselung und setzen nicht auf ein 'Zwei-Wege-Verfahren', ergo bei ihnen wird NUR verschlüsselt. Sie ändern bei sich lokal die Daten und verschlüsseln diese. Die .exe im Ordner erkennt dies und 'entschlüsselt' lokal die Ressourcen die er benötigt. Ich gehe jetzt nicht noch tiefer darauf ein wie und wo, das war genug Verwirrung für einen Beitrag denke ich.


    Wenn jetzt ein Angreifer an diese lokal entschlüsselten Ressourcen will, muss er sie (relativ) mühseelig durch Reverse-Engineering aus dem Speicher 'laden'. Penger aus einem anderen Forum macht dies häufig zum Beispiel mit dem Clienten des offiziellen Metin2 Spieles, weil die auch nicht mehr so einfach durch den EterManager / EterNexus entpackbar sind.


    Ich hoffe damit sind deine Fragen geklärt, wenn nicht - Frag einfach. Ich werd dich nicht allzu doll schlagen, nurn bisschen. ;)

    mir wurd gesagt es ist nicht zu fixen..

    Die Aussage ist Müll. Jeder Bug ist zu fixen, mal dauert es länger mal geht es schneller.

    Packet Errors können sehr nervig sein zu fixen, wenn man kein Plan von packets hat. Wende dich an einen Dev hier im Forum. Leute wie Señor iPeri /.. oder Lead0b110010100 oder jemand anders kann das sicher fixen. Nur muss dir da klar sein das sie es ggf nicht for Free machen.


    Aber abgesehen davon, rein mit dem Thema und Infos die du gerade gibst. KANN dir keiner im Forum helfen.

    Es ist sehr schwierig zu fixxen, finde ich zumindestens. Wenn nicht offensichtlich die "packet.h" auf Server und Clientseite asynchron ist.

    Als Beispiel:


    Client

    Code
    1. typedef struct TPacketBlaBla
    2. {
    3. BYTE header;
    4. int a;
    5. long b;
    6. long long c;
    7. } SPacketBlaBla;


    Server

    Code
    1. typedef struct TPacketBlaBla
    2. {
    3. BYTE header;
    4. int a;
    5. long b;
    6. long long c;
    7. char d[1024];
    8. long double e;
    9. int x, y, z;
    10. } SPacketBlaBla;


    Ansonsten ist noch drauf zu achten, dass nur Datentypen verwendet werden bei denen genau klar ist wie groß sie sind. std::string und std::vector funktionieren nicht, weil sie dynamische Größen annehmen können.


    Also was auch definitiv falsch ist:


    Code
    1. typedef struct TPacketBlaBla
    2. {
    3. BYTE header;
    4. std::string s;
    5. std::vector sv;
    6. std::optional<std::map<std::string, int64_t>> svo;
    7. } SPacketBlaBla;


    Dagegen funktionieren:

    - int (int8_t <-> int64_t)

    - uint (...)

    - long

    - double

    - bool (<- Ja, kaum verwendet - Aber geht selbstverständlich auch. Kp warum die Entwickler da lieber Integer nehmen.)

    - char x[512] <- Größe muss zur Compilezeit klar sein, kann also danach nicht mehr einfach erweitert werden. Ist ja auch kein dynamischer Datentyp.


    Ansonsten vertröste ich Kunden / Leute auf Discord meistens mit einem "hättest du mal git benutzt", weil solche Fehler viel Verständnis über das aktuelle System und den aktuellen Code erfordern. Und ich ehrlich gesagt nicht die Zeit habe, bei jedem Kunden erst ein Mal jedes System nachzuvollziehen und in Gänze zu verstehen.


    Hoffe das hilft dir trotzdem irgendwie :)

    Zunächst ein Mal: Vielen Dank!


    Dann möchte ich grundsätzliche Dinge ansprechen, der Code ist an sich aber recht schlüssig und das Wichtigste: Er erklärt sich selbst, deshalb..


    1.) Unnötige Kommentare weglassen

    Code
    1. p.lValue = 0; //The value can be given as a parameter if you dont want to set the value to 0


    ist das Selbe wie:


    Code
    1. int costs = ...; // This variable contains the costs for ... in an ... bla bla bla


    Offensichtliche Dinge nicht kommentieren, Kommentare nur dann wenn wirklich der Code zu komplex wird und du das Gefühl hast, dass du nach etwa 6 Monaten nicht mehr weißt wie und was da stehen könnte.


    2.) using namespace std;


    Code
    1. void ResetDungeonsOnReboot(const string& name)


    Durch diesen Funktionsheader schließe ich darauf, dass du irgendwo im Code (wahrscheinlich in der stl.h oder typedef.h / stdafx.h) folgendes stehen hast:


    Code
    1. using namespace std;


    Zu diesem Codeschnipsel gibt es ganz viele Videos die es verteufeln aber ich versuche mal ein simples Beispiel zu machen wo es eben problematisch wird:



    Das ist eig. selbsterklärend, dadurch dass die STL so groß ist (Etwa 300.000 Zeilen hat alleine der iostream Header), gibt es sehr viele Funktions und Variablendeklarationen. Benennst du deine Variablen / Funktionen auch so, dann gibt es Kompilierprobleme und so wie du Visual Studio kennst sind diese Fehler nicht lesbar und absolut unübersichtlich. Bei diesen 12 Zeilen ist das vllt. unproblematisch, aber bei einem Projekt mit > 1.000.000 Zeilen Code wirds schwierig mit der Fehlersuche.


    Deshalb ist empfohlen überall "using namespace std;" zu löschen und folgendes überall zu tun (explizit statt implizit):


    Code
    1. void ResetDungeonsOnReboot(const std::string& name)


    3.) Über C-Style Listen iterieren mit Auto keyword:


    Statt

    Code
    1. int dungeonCount = sizeof(dungeons)/sizeof(dungeons[0]);
    2. for(int i = 0; i < dungeonCount; i++) {
    3. ResetDungeonsOnReboot(dungeons[i]);
    4. }


    kannst du:


    Code
    1. std::string dungeonFlags[2] = { "BT_group_inside", "d_run_group_inside" }; //replace size of array and elements to your needs
    2. for (const auto& flag : dungeonFlags)
    3. {
    4. // flag ist dein std::string z.B: BT_group_inside, dann d_run_group_inside ...
    5. }


    machen, sieht schöner aus und ist unter umständen auch schneller. Bei 2 Elementen macht das aber keinen Unterschied, du sparst dir aber aufjedenfall die temporäre Variable 'i' im Stack. Kann schon mal StackOverflow's geben, wenn du sone Variable ungehindert inkrementierst in einer Render oder Update Funktion.


    4.) ++i statt i++ In For-Loops


    Sagen wir du MUSST eine temporäre Variable i nutzen zum Durchitterrieren über custom Datentypen, die nur so funktionieren. Dann immer ++i statt i++, warum erkläre ich dir jetzt. Erst Mal der Fehler:


    Code
    1. for(int i = 0; i < dungeonCount; i++) {...}


    Rein von der Logik her, was muss C++ bei i++ machen? Er muss i inkrementieren aber den alten Wert zurückgeben vor der Inkrement-Operation also:


    Code
    1. // Pseudocode, kompiliert so nicht
    2. HEADER(int& val) {
    3. int old = val;
    4. val = val + 1;
    5. return old;
    6. }


    Jetzt schauen wir uns mal ++i an, hier muss er i inkrementieren und den neuen Wert zurückgeben:


    Code
    1. HEADER(int& val) {
    2. val = val + 1;
    3. return val;
    4. }


    Das ist eine Operation weniger und macht höchstwahrscheinlich auch keinen Unterschied weil alle gängigen Compiler extrem schlau sind und dein "i++" als "++i" lesen. Aber besser selbst drauf achten und dem Compiler diese Denkarbeit abnehmen. Jetzt weißt dus ja besser.


    5) Schlusswort.


    Den Rest möchte ich gar nicht so deep kommentieren, denn das ist mehr Codestil und persönliche Entscheidung. Ich persönlich finde alle Fileoperationen von C einfach nur hässlich und buganfällig und würde für jede davon eine C++ Alternative Library nutzen. Dazu gabs von Marty seine eigenst angefertigte, ansonsten kann ich dir auch die STL von EA Sports Entertainment empfehlen, die haben eine performantere Version davon veröffentlicht. Schaus dir mal an.

    Kann man so machen. Schöner wär aber dieser "when boot begin" trigger, den Marty in seiner neuesten Source implementiert hat.

    Wenn man also in einer Quest z.B: solche Dinge steuern könnte und relativ leicht auch verändern / verschiedene Werte setzen usw.

    Was man natürlich noch erweitern kann ist ein config File, wie bei den Berechtigungssätzen für GM Befehle, welches beim Start eingelesen und verarbeitet wird. Darin wird dann Flag-Name und Default Wert für den Serverstart angegeben.

    Wenn ich nachher Zuhause bin editiere ich das hier rein.

    Oder so ja. Find quest trigger in metin2 aber extrem nützlich und viel zu selten genutzt.

    Man kann so viel schönes machen mit einem "when enter begin" oder "when boot begin" oder "when pick_item" begin usw.

    Also eigene Trigger schreiben ist glaub nie verkehrt, erhöht nur die Möglichkeiten an schönen Quests!


    Danke nochmal, ich brauchs zwar nicht - Aber ist ein schöner Release :)