Registriert: Di Mai 18, 2004 16:45 Beiträge: 2623 Wohnort: Berlin
Programmiersprache: Go, C/C++
Zu Lua:
Mhh, also wenn du 20k Objekte im Speicher, für lua bereit hällst, dann hast definitiv was in deinem Konzept falsch gemacht.
Zum Projekt:
Ich hatte auch überlegt ne eigene Scriptsprache zu schreiben und hatte die auch schon ziemlich weit, Lexer,Parser,VM standen.
Allerdings bin ich dann wieder zu LUA zurück, da es einfach weniger Zeit braucht, schneller ist und ich mich dann auch nicht um die Pflege kümmern muss.
LUA hat z.B. Mechanismen, die zur laufzeit den ByteCode umstellen, damit wird mit jeder iteration der Code ein bischen schneller, da die Codes auf die Zugriffe hin optimiert wird.
RTTI ist ziemlich "lahm", entweder schreibst du ein eigenes RTTI, welches viel balast über Board wirft und durch Hashsysteme und Caching schneller ist oder machst es wie üblich über direktes mappen.
Hierbei gibt es 2 ansätze, der erste läuft über ein extra tool, welches den Code analysiert und den Interfacecode für die Scriptsprache generiert.
Dann kann man den generierten Code einfach compilieren und hat eine Klassenanbindung an die Scriptsprache.
So macht es Blender und für Lua gibt es ebenfalls solch ein Tool.
Die 2. Möglichkeit wäre simple funktionen zu schreiben, wo der Hardcoded Anteil geringer wird.
Noch ein kleiner Hinweis zu Lua und geschwindigkeit.
Unreal Engine 3 Scripte sind ~10x langsamer als LUA(mit metatables für OO) und trotzdem ist es immernoch schnell genug.
_________________ "Wer die Freiheit aufgibt um Sicherheit zu gewinnen, der wird am Ende beides verlieren" Benjamin Franklin
Registriert: Do Sep 02, 2004 19:42 Beiträge: 4158
Programmiersprache: FreePascal, C++
Es ist erstaunlich. Die 20k Objekte kamen übrigens weniger durch mich als durch Lua zustande, fürchte ich.
Die Situation war die folgende: Ich habe Lua über einen Parameter in einer Funktion ein Objekt mit Metatable zur verfügung gestellt. Diese Funktion wird bestimmt 100x pro Frame aufgerufen (ist ne Partikelfunktion) und mit jedem mal gab es also eine Tabelle mehr. Lua hat da anscheinend immernoch alle referenzen im Speicher gehalten, bis zu einer bestimmten grenze, wo es begonnen hat, die Garbage Collection zu starten und da hats dann angefangen zu ruckeln.
Was das RTTI betrifft: Die Properties werden nur zur Compiletime abgefragt, danach habe ich nurnoch Pointer auf die TTypeInfo-Records. Also muss er nicht bei jedem Zugriff die komplette Liste iterieren. Zumal die Namen, unter denen ich die Properties abrufe, zur Laufzeit auch garnicht mehr bekannt sind. Aber das ist ja auch nicht die einzige möglichkeit, Properties zu integrieren. Es soll später noch eine hinzukommen, wo man z.B. einen Pointer auf die Variable angeben kann, oder jeweils einen Pointer auf die Getter und Setter funktionen und sich auf diese weise sozusagen eine Pseudo-Klasse zusammenschustern kann.
Gruß Lord Horazont
_________________ If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung. current projects: ManiacLab; aioxmpp zombofant network • my photostream „Writing code is like writing poetry“ - source unknown
„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb
Registriert: Di Mai 18, 2004 16:45 Beiträge: 2623 Wohnort: Berlin
Programmiersprache: Go, C/C++
Das wichtigste beim Scripten ist erstmal, das Script darf keine Ressourcen erstellen.
Ein Script erstellt keine Ressourcen, das macht das System und dann benutzt man auch mehere Script Envoirments.
Z.B. bekommt jedes Material, jeder Bottyp nen eigenes Envoirment.
Damit bleiben die Scripte auch kurz und übersichtlich.
Du schreibst z.B. eine Klasse, dann hast du in deiner Scriptsprache eine bekannte Klasse z.B. CTextureManager.
Da ein Ressourcenmanager in der Regel ein Singleton ist, kannst du also TexMan=CTextureManager.GetInstance() machen.
Benutzt du Ressourcen, wie z.B. ein Partikelsystem, dann solltest du ein SceneGraph haben, zentrale Datenverwaltung lässt grüssen.
Dann kannst du in etwa folgendes abziehen.
SG=CSceneGraph.GetInstance()
ParticleSystem=SG.GetInstance("MyNewParticleSystem",CParticleSystem)
ParticleSystem.LoadConf("/media/particle/fire.cfg")
Der SceneGraph ist ein Singleton und du bekommst die Instance auf den SG(existiert er noch nicht legt GetInstance ihn an).
Dann forderst du den SG auf, ein Node zu suchen welches "MyNewParticleSystem" lautet, wenn es noch nicht existiert, dann füge es hinzu. Durch ein 2. Parameter kannst du den Typen festlegen, also über welche Nodetypen er suchen soll und wenn er es nicht findet, weiss welches Objekt er stellen soll.
Es ist empfehlenswert, Hashes zu verwenden und auch die Updateroutine im Script von Strings frei zu halten und die Hashes für die Strings vorher im init zu berechnen und nur noch den Zahlenwert in der Update funktion zu verwenden.
Das sind so meine Erfahrungen, die ich gemacht habe.
Lua Garbage Collection ist auch so eine Sache, wenn du funktionen in Lua verwendest, dann greift die GB nur, wenn du Variablen im Scope erstellst also "local bla=1" default(wenn du nichts vor die var schreibst) ist immer global und damit wird alles in der funktion weiter leben(ausser die funktionsparameter).
_________________ "Wer die Freiheit aufgibt um Sicherheit zu gewinnen, der wird am Ende beides verlieren" Benjamin Franklin
Registriert: Do Sep 02, 2004 19:42 Beiträge: 4158
Programmiersprache: FreePascal, C++
Nunja, dass ich nicht die gleiche Environment für Bots wie für Partikel nehme ist schon klar. Alle Scripts in eine Scriptengine zu laden würde wohl auch massiv übertrieben sein.
Ich habe gerade nochmal kurz mit Lua rumgespielt und es endete immernoch in einer Diashow nach einiger Zeit.
Meine Datenverwaltung sieht in meinem Hauptprojekt schon ganz ähnlich aus. Scripts dürfen natürlich nicht ohne weiteres Ressourcen erstellen (genau genommen sind keine Konstruktoren veröffentlicht). Dennoch bestehen andere Methoden, z.B. die Spawn-Methode eines Partikelsystems, mit der ein Script einen Partikel spawnen kann.
Gruß Lord Horazont
_________________ If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung. current projects: ManiacLab; aioxmpp zombofant network • my photostream „Writing code is like writing poetry“ - source unknown
„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb
Registriert: Di Mai 18, 2004 16:45 Beiträge: 2623 Wohnort: Berlin
Programmiersprache: Go, C/C++
Habe ich dich jetzt richtig verstanden und du nutzt Scriptzeilen für einzelne Partikel ?
Wenn ja, eine Regel sollte man sich, bei Scripten, stellen "kein Macromanagment".
Was bedeutet, man deligiert nur mit den Scripten, indem man prüfungen macht und dann dem system sagt, welche routinen er aufrufen soll. Das Script sollte im idealfall nur die Entscheidungen übernehmen und das System enthält dann die wirklichen routinen zur verarbeitung. Die nötige Flexibilität kann man durch Parameter und Konstanten/Variablen erreichen.
Welche Datentypen willst du überhaupt in den Support nehmen ?
Lua ist z.B. bei Number und String gelandet, also alle Zahlen sind Double werte oder float(kommt auf die compilierte dll an) und Strings sind halt pchar.
Float werden schneller verarbeitet als integer und seine verwandten, daher halte ich das als Zahlentyp sehr sinnvoll aber als string würde ich definitiv pascal Strings nehmen, die länge auf dem ersten Bytes haben und dann 255 chars vorreservieren.
Wenn man eine Farbe will, dann bekommt man halt ein 3 float array statt eines Color Datentyps.
Variablen sollten auchein festen Typ bekommen und nicht zur laufzeit veränderbar sein, weil man so schon zur compile time, des Scriptes, die korrektheit sichern kann. Wenn die Variable ein number ist und die funktion ein string will, dann compiliert er das script garnicht erst.
Ich hatte mal ne Idee zum besseren und sicheren Kapseln von Klassen und Scriptsprache.
Dabei wird für jeden Klassentyp eine Wrapperklasse bereit gestellt.
Die Wrapperklasse wird im init des Scriptes erstellt(wenn sie im script mal gebraucht wird) und ein Objekt in der Scriptsprache ist eine Tabelle aus Sender und Klassenwrapper. Sender ist ein Index, mit dem die Wrapperklasse auf das echte Objekt im System zugreiffen kann. Also die Wrapperklasse hat eine Liste, wo die Objekte von dem Typ registriert sind und über den Index/Sender kann er dann arbeiten.
Das ist eigentlich das Klassen/Objektprinzip wie man es auch Programmiersprachen kennt.
Man übergibt dann statt eines Pointers, der Wrapperklasse ein Index und intern kann er dann mit dem Objekt arbeiten.
Damit sieht die Scriptsprache nie die echten Objekte und kommt auch garnicht ran.
Man kann die Wrapperklasse sogar ohne Instanz verwenden, alle Methoden kann man mit class versehen.
Also keine Instanz von der Wrapperklasse, damit sind alle Sender wirklich unique, da alle Scriptenvoirements sich auf die Wrapperklasse beziehen.
Du benötigst auch die Information, welches Scriptenvoirement welche Sender zugreifen darf.
So kannst du dann z.B. in einer Scriptenvoirement ein Sender für anderen sichtbar machen und dann in anderen Scripten über extern auf diese zugreifen.
Label1.Text="ABC" wäre dann nichts anderes als Label[1].SetText(Label[0],"ABC") wobei 0 halt der Sender und 1 die Wrapperklasse ist.
_________________ "Wer die Freiheit aufgibt um Sicherheit zu gewinnen, der wird am Ende beides verlieren" Benjamin Franklin
Registriert: Do Sep 02, 2004 19:42 Beiträge: 4158
Programmiersprache: FreePascal, C++
Also ich hatte jetzt eine Testszene, in der ich bei jedem Partikeltod von einem Partikel einer Bestimmten Art (Flamme) einen neuen (Rauch) gespawnt habe.
Was die Datentypen betrifft: Ich habe drei feste Datentypen: String (AnsiStrings von Pascal), Integer (Int64) und Float (Double). Die Typprüfung mache ich schon zur Compiletime, ist erstens einfacher und zweitens muss dann die VM keine Prüfungen mehr machen, was einiges an Performance bringt.
Für alles andere habe ich erweiterte Datentypen, die vor dem Compilieren bekannt gegeben werden müssen. Über diese werden dann Arrays und alles verwaltet.
Sowas wie du es beschrieben hast, könnte man theoretisch implementieren, ist aber nicht das, was ich gerne verwenden wollte. Ich habe lieber den direkten Zugriff, ohne noch umwege über irgendwelche performancefressenden Weichen gehen zu müssen.
Gruß Lord Horazont
_________________ If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung. current projects: ManiacLab; aioxmpp zombofant network • my photostream „Writing code is like writing poetry“ - source unknown
„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb
Registriert: Di Mai 18, 2004 16:45 Beiträge: 2623 Wohnort: Berlin
Programmiersprache: Go, C/C++
Das wäre Micromanagment und ist echt der overkill für Scripte.
Du kannst z.B. per script die einzelnen Etappen festlegen, von 0-0.3 textur1, von 0.3-0.8 textur2 und 0.8-1.0 textur3.
0-1 wäre also ein komplettes interval und wird auf die Zeitdauer hochskaliert.
Dein system kann dann anhand dieser 3 eingaben intern die ganzen berechnungen, änderungen machen und dein Script wird entlastet.
Die Klassenwrapper wären nicht performance fressend sondern im gegenteil, schneller als rtti basierte systeme, da die Klasse fest verdrahtet ist und komplett auf der systemseite läuft und nicht auf der scriptseite.
_________________ "Wer die Freiheit aufgibt um Sicherheit zu gewinnen, der wird am Ende beides verlieren" Benjamin Franklin
Registriert: Do Sep 02, 2004 19:42 Beiträge: 4158
Programmiersprache: FreePascal, C++
Uhm, du hast da was falsch verstanden. Ich ändere nicht die Textur sondern ich erstelle einen ganz neuen Partikel. Und dieses Event wird auch nur aufgerufen, wenn ein Partikel seine Lebenszeit überschritten hat und demnach gekillt wird.
Für solche Übergänge habe ich schon diverse Funktionen (FadeIn/FadeOut, GrowIn/ShrinkOut) und für Texturen habe ich auch schon was geplant, aber das gehört nicht in diesen Thread
Ich werde ja dann sehen, welche Performance ich mit meiner Scriptsprache rausholen kann. Selbst wenns dann daneben geht, habe ich trotzdem einiges gelernt und für andere Zwecke (z.B. ein älteres Hotkey-Programm was ich noch irgendwo rumliegen habe) kann ich's auch noch gebrauchen.
Gruß Lord Horazont
_________________ If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung. current projects: ManiacLab; aioxmpp zombofant network • my photostream „Writing code is like writing poetry“ - source unknown
„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb
Registriert: Di Mai 18, 2004 16:45 Beiträge: 2623 Wohnort: Berlin
Programmiersprache: Go, C/C++
Lernen tust du aufjedenfall was dabei.
Ich hab ja auch die Scriptsprache vor kurzer zeit geschrieben und bin dann halt zu lua zurück, weil es für meine Zwecke viel mehr Vorteile hatte.
Mich interessiert deine Arbeit aufjedenfall und werde es gespannt verfolgen.
_________________ "Wer die Freiheit aufgibt um Sicherheit zu gewinnen, der wird am Ende beides verlieren" Benjamin Franklin
Du solltest dir auf jeden Fall die Designdokumente zu UnrealScript ansehen.
Statische typen bringen einiges an Performance. Beim meinem Proof of Concept war das glaube ich über faktor 20-50 gegenüber lua. Die Philosophie dass alles eine Tabelle ist, ist leider nicht übermäßig performant, und nur relativ umständlich an existierende Objekte zu binden.
Registriert: Do Sep 02, 2004 19:42 Beiträge: 4158
Programmiersprache: FreePascal, C++
Wenn man sich die Kommentare unten anschaut, erscheint mir der Test nicht sehr zuverlässig. Wie ich schon sagte, meine typen werden Statisch und schon zur Kompiletime geprüft. Das ist mir erstens sicherer und zweitens gehts dann schneller .
Gruß Lord Horazont
_________________ If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung. current projects: ManiacLab; aioxmpp zombofant network • my photostream „Writing code is like writing poetry“ - source unknown
„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb
Bei einfachem code der nur lokale variablen verwendet ist lua sehr schnell. Da stimmt dann der faktor 10 wahrscheinlich. Bei vielen Zugriffen auf objekteigenschaften geht dir die performance jedoch in die Knie. Es kommt halt sehr aufs Verwendungszenario an.
Lua ist eine sehr schöne und elegante general purpose Sprache, meines Erachtens jedoch nicht besonders gut auf das Spieleszenario ausgelegt.
Registriert: Di Mai 18, 2004 16:45 Beiträge: 2623 Wohnort: Berlin
Programmiersprache: Go, C/C++
Mein einziges Problem mit deiner Scriptsprache ist die verwendung von RTTI.
RTTI-Daten sind Platzfresser, da sie für jedes Objekt angelegt werden.
RTTI ist langsam, für einen RTTI zugriff muss über die Liste der Methoden oder Properties iteriert werden.
RTTI arbeitet auf String und Strings sind um ein vielfaches langsamer als pointer/indices.
RTTI sind furchtbar schlecht implementiert, so werden einige Typen nicht supportet z.B. record oder interface.
RTTI wird zur laufzeit verwendet und nicht zur compiletime(heisst ja nicht umsonnst runtime type information).
RTTI bringt abhängigkeiten, man muss alle Klassen von TPersistant ableiten oder mit {M+}{M-} flaggen.
RTTI ist wesentlich schlechter zu debuggen als Klassenwrapper.
RTTI bnötigt ne menge prüfungen, um die Daten zu verifizieren und zu konvertieren(string,short string,long string oder int,unsigned int,float).
Wenn es um geschwindigkeit geht, dann doch auch bitte richtig.
Mitlerweile kenne ich 3 Ansätze für compiletime generierung, von wrapperklassen.
1.) code build tool, welches beim projekt als precommando durchlaufen tut und dann beim compilieren die generierten codes mit compiliert.
2.) hardcoded Wrapperklassen, dabei werden im Constructor die Methoden und Properties registriert, mit Scriptnamen und referenz.
3.) Macro basierte Wrapperklassen, dabei werden über Macros, die gewünschten Klassen, methoden und properties für den compiler passend verarbeitet und es Kommen dann die normalen Klassen und Wrapperklassen aus dem gleichen Klassencode raus.
Lösung 1 ist meine lieblingslösung, da diese nicht den Code beeinflusst, wie Lösung 2 und 3.
Ausserdem kann im Tool noch ne menge gemacht werden, wie z.B. optimierung.
edit:
Wenn du diesen Punkt änderst, würde ich sogar meine Hilfe beim programmieren anbieten.
Denn ich verwendet C++ und ein Buildtool kann über jede Sprache analysieren und wrappercode generieren aber rtti ist sprachabhängig.
_________________ "Wer die Freiheit aufgibt um Sicherheit zu gewinnen, der wird am Ende beides verlieren" Benjamin Franklin
Registriert: Do Sep 02, 2004 19:42 Beiträge: 4158
Programmiersprache: FreePascal, C++
TAK2004 hat geschrieben:
RTTI-Daten sind Platzfresser, da sie für jedes Objekt angelegt werden. RTTI ist langsam, für einen RTTI zugriff muss über die Liste der Methoden oder Properties iteriert werden. RTTI arbeitet auf String und Strings sind um ein vielfaches langsamer als pointer/indices. RTTI sind furchtbar schlecht implementiert, so werden einige Typen nicht supportet z.B. record oder interface. RTTI wird zur laufzeit verwendet und nicht zur compiletime(heisst ja nicht umsonnst runtime type information). RTTI bringt abhängigkeiten, man muss alle Klassen von TPersistant ableiten oder mit {M+}{M-} flaggen. RTTI ist wesentlich schlechter zu debuggen als Klassenwrapper. RTTI bnötigt ne menge prüfungen, um die Daten zu verifizieren und zu konvertieren(string,short string,long string oder int,unsigned int,float).
Ad 1: Ja, stimmt leider, es nimmt eine menge platz weg. Ad 2: Das stimmt in meinem Falle nicht. Ich lade die Pointer auf die Informationsrecords schon beim Compilieren, daher verlangsamt es zwar dieses, aber die Laufzeit bleibt fix. Ad 3: Records können sowieso nicht im Script verwendet werden, zumindest nicht ohne Wrapper. Ad 4: Stimmt bedingt. Aber das ist ja unter anderem Sinn der Sache. Ad 5: Auch das ist richtig. Aber das Flaggen ist ja wohl das geringere Problem, oder? Ad 6: Hmm... Dazu weiss ich jetzt nichts. Ad 7: Also zumindest in meinem Codeanteil stehen sehr wenige abzweigungen. Eine für Ordinaltypen, eine für Stringtypen, eine für Floattypen und eine für Objekttypen. Den Rest erledigt die Get*Prop-Funktion. Ich habe mir deren Code auch mal angeschaut, so schlecht ist der garnicht implementiert.
TAK2004 hat geschrieben:
Wenn es um geschwindigkeit geht, dann doch auch bitte richtig. Mitlerweile kenne ich 3 Ansätze für compiletime generierung, von wrapperklassen. 1.) code build tool, welches beim projekt als precommando durchlaufen tut und dann beim compilieren die generierten codes mit compiliert. 2.) hardcoded Wrapperklassen, dabei werden im Constructor die Methoden und Properties registriert, mit Scriptnamen und referenz. 3.) Macro basierte Wrapperklassen, dabei werden über Macros, die gewünschten Klassen, methoden und properties für den compiler passend verarbeitet und es Kommen dann die normalen Klassen und Wrapperklassen aus dem gleichen Klassencode raus.
Ad 1: Nein, definitiv dagegen. Der Aufwand für ein solches tool ist riesig, weil man im prinzip die komplette Pascal-Syntax implementieren muss. Ad 2: Wie vorhin schon gesagt: Das bleibt immer die zweite Variante. Auch plane ich eine Schnittstelle über Interfaces. Ad 3: Das habe ich jetzt nicht verstanden. Was meinst du damit?
TAK2004 hat geschrieben:
Wenn du diesen Punkt änderst, würde ich sogar meine Hilfe beim programmieren anbieten. Denn ich verwendet C++ und ein Buildtool kann über jede Sprache analysieren und wrappercode generieren aber rtti ist sprachabhängig.
Ein nettes Angebot. Wie ich sagte, die Schnittstelle zu den Host-Klassen ist sehr flexibel. Über eine möglichkeit, C++ anzubinden wäre ich nicht unerfreut. Ich kann dir den aktuellen Code ja mal schicken, wenn du's dir mal anschauen willst.
Gruß Lord Horazont
_________________ If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung. current projects: ManiacLab; aioxmpp zombofant network • my photostream „Writing code is like writing poetry“ - source unknown
„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb
Mitglieder in diesem Forum: 0 Mitglieder und 6 Gäste
Du darfst keine neuen Themen in diesem Forum erstellen. Du darfst keine Antworten zu Themen in diesem Forum erstellen. Du darfst deine Beiträge in diesem Forum nicht ändern. Du darfst deine Beiträge in diesem Forum nicht löschen. Du darfst keine Dateianhänge in diesem Forum erstellen.