Banner image

BuildIT - Tagebuch meines Logik-Gatter Simulations Spiels

Published on 21.10.2025, 02:33:00


Hallo Freunde des Internets!

Seit einigen Monaten arbeite ich nun an meinem Spiel rund um die Simulation von Logik-Gattern und noch vielem mehr. Nun möchte ich euch mit auf meine Reise nehmen. Ich werde versuchen, nach jedem Entwicklungstag ein kleines Update hier zu hinterlassen - für meine Nachwelt!

02. Juni 2025

Die Überlegungen zur Software Architektur sind immernoch in vollem Gange. Nachdem ich mal wieder ein bisschen an meiner Entscheidung, dynamic Libraries als Plugins zu verwenden, gezweifelt habe, habe ich dann doch ein bisschen an der Registrierung von Komponenten und Leiterplatten weiterentwickelt. Ich habe gelernt, dass dynamic Libraries gar nicht so trivial sind - wegen ABI problemen - und erneut wurde mir gezeigt, warum ich Apple hasse. (Lasst mich doch bitte einfach dynamic libraries für MacOS auf Linux kompilieren!) So langsam habe ich eine Idee wie die ganzen einzelnen Code-Module (ECS, Serialisierung, Event-Management, History, Vulkan, Plugins, Network) zusammenspielen könnten. Meine Ziel ist es ja, die drei folgenden "Modi" zu unterstützen

  • Singleplayer (Alles läuft lokal) Dabei soll aber nicht - wie zum Beispiel in Minecraft - ein lokaler Server gestartet werden. Der Grafik-Layer soll direkt auf das ECS (den Core) zugreifen - im selber Prozess.
  • Local gehosteter Server-Layer Ein Spieler spielt wie im Singleplayer Modus, zusätzlich wird allerdings ein Server-Layer gestartet. Andere Clients starten wie immer den Core zusätzlich allerdings noch den Client-Layer um mit dem Server zu kommunizieren und Änderungen am lokalen Core vorzunehmen.
  • Server / Client Headless Server, welcher nur den sogenannten Core und den Server-Layer startet. Die Clients benutzen wie im vorherigen Modus den Core und den Client-Layer.

Das würde mir erlauben, z.B. eine Headless-Binary zu kompilieren, die dann auch wirklich nur den Core und Server-Layer enthält :).

Nun ja, soweit so gut. Ich werde jetzt noch ein bisschen an den einzelnen Layern tüfteln!

Update 04:15

GRRR. Morgen um 09:00 ist Uni. Eigentlich wollte ich nur bis um vielleicht 1 Uhr programmieren. Leider musste ich jetzt erstmal die gesamte Blog-Seite umprogrammieren wegen NodeJS Problemen... Irgendwann programmier ich die mal in Go oder so neu -.-.

03. Juni 2025

Nach guten drei Stunden Schlaf und ein bisschen Uni habe ich mich weiter mit Vulkan auseinander gesetzt. Alles sieht dannach aus die Plugins mit C-Interface zu schreiben und da es Plugins ja möglich sein muss, mit Vulkan zu interagieren, muss ich ja erstmal wissen wie Vulkan funktioniert!

Dabei bin ich über einen überaus spannenden Artikel gestoßen:

Ist sehr lesenswert.

Recht viel weiter als ein laufendes GLFW und die Anfänge von Vulkan (Debug Extension und Validation Layer) bin ich bisher nicht gekommen, aber schließlich will ich das ja auch alles wirklich verstehen und nicht nur benutzen. Ich glaube das macht die spätere Verwendung von Vulkan bedeutend einfacher.

04. Juni 2025

Eine Nachricht an mich selbst und Andere: Was ich mir da zur Aufgabe gemacht habe, ist sicher nicht einfach. C++ als Sprache birgt viele Schwierigkeiten. Plugins müssen für alle Betriebsysteme extra kompalliert werden. C als Schnittstelle zu den Plugins machen Dinge nicht einfacher. Die Nutzung von Vulkan ist sehr komplex und wird viel Aufwand benötigen, um Vulkan-Funktionalität in den Plugins bereit zu stellen. Für Nutzer soll es einfach sein Plugins zu installieren. Sicherheitstechnisch sind jetzt dynamic libraries auch nicht unbedingt das wahre. Aber ich mache das aus Gründen. Theoretisch wäre es möglich OpenGL zu verwenden, aber ich will kennenlernen, wie die Grafikkarte wirklich funktioniert. Will die Features von Vulkan nutzen können, selbst wenn es komplexität mit bringt. Ich will kein Java verwenden. Ich will, dass das gebaute Programm ein paar Megabyte an größe hat und keine 5 Gigabyte Ram benötigt. Ich will, dass Menschen Plugins schreiben können die komplexe Dinge machen. Einer meiner Ideen ist ein Musik-Plugin, welches eigene UDP Verbindungen aufbaut und mit Supercollider coole Synthesizer Dinge macht! Mein Ziel für dieses Spiel ist ein Sandkasten für große Kinder. Dabei will ich Dinge lernen. Deshalb mache ich Dinge so, wie ich sie mache. Das sollte ich mir vielleicht öfters mal selbst ins Gedächtnis rufen, wenn ich mal wieder daran zweifle ob das alles so eine gute Idee ist.

Jetzt habe ich noch ein wenig weiter mit Vulkan experimentiert. Zäh, aber es wird, immerhin habe ich jetzt schonmal ein Device und eine Graphics Queue!

16. Juni 2025

We've got a triangle! Nach einer entspannten Woche außerhalb der Hochschule habe ich mich wieder weiter mit BuildIT beschäftigt und wir haben nun endlich ein Dreieck auf dem Bildschirm! Ein zwar Validation-Layer Errors bekommen wir zwar noch, aber ansonsten ist das ein großer Schritt in die richtige Richtung :). Jetzt kann ich mir mal überlegen wie ich das mit Vulkan alles mache :)

Beim Lesen über Vulkan Synchronization bin ich über folgenden sehr hilfreichen Blogpost gestolpert:

Sehr interessant.

18. Juni 2025

Nach dem funktionierenden Dreieck habe ich mich nochmal intensiv mit den Synchronizationsmechanismen auseinandergesetzt um einen Fehler zu beheben. Tatsächlich habe ich dann erfahren, dass meine Referenz wohl veraltet ist und man Dinge eigentlich anders machen sollte. Dann habe ich mir die Dinge so überlegt, wie ich es für richtig halte und tatsächlich hat sich dass dann mehr oder weniger später auch durch einen passenden Github Issue bestätigt. Auf meinem Laptop mit Integrierter Grafikkarte haben wir außerdem die 10000 FPS Grenze erreicht! What a time to be alive!

28. Juni 2025

Da wir in wenigen Wochen Klausuren-Phase haben, habe ich leider viel für die Uni zu lernen. Ich habe heute das Shader laden deutlich vereinfacht. Vorher wurden die Shader als glsl geladen und zur Laufzeit zu SPIR-V kompilliert. Jetzt kompillier ich die beim Bauen des Projektes und lade die kompillierten SPIR-V Shader direkt. Das ist deutlich schöner. Außerdem habe ich die alten Grid-Shader rüber kopiert und die alte Leiterplatte zu sehen hat mir schon einen Nostalgie-Schub verpasst ;). Mal sehen, dass ich vielleicht eine einfache Steuerung mit Uniforms mal zum Laufen bekomme und vielleicht ein paar gemalte Logik-Gatter!

14. Juli 2025

Mitten in der Klausuren-Phase ein bisschen am Projekt weiter arbeiten? Klingt nach etwas, was ich definitiv tun würde! Ich habe heute nämlich Dear ImGUI zum laufen bekommen! War ein bisschen Arbeit, aber eigentlich sogar leichter als gedacht. Jetzt kann ich damit mal ein wenig rum experimentieren. Irgendwie muss ich aber jetzt wohl mal noch meine 800 Zeilen Vulkan Klasse aufräumen. Nächste Woche sind Prüfungen und dann schaffe ich hoffentlich wieder mehr :)

24. Juli 2025

Ich berichte hier gerade live und exklusiv aus der Klausurenwoche. Nur noch eine Klausur wartet morgen auf mich und auf die bin ich gut vorbereitet, der Rest lief auch gut. Die letzten Tage habe ich immer mal wieder am Programm weiter entwickelt! Jetzt funktioniert nicht nur das Dear ImGui, sondern wir haben auch schon einzelne Circuitboards in den Gui Fenstern drinnen! Das klingt jetzt nach wenig - ist es aber ganz und gar nicht. Da muss man sich nämlich um Images, Image Views, Device Memory, Framebuffers, Descriptor Sets, Command Buffers, Render Passes, Pipelines, Shader, Samplers, und und und kümmern. Ich habe auf jeden Fall viel gelernt. In den letzten Tagen hatte ich mit der Synchronisierung für diese Off-Screen Framebuffer (besonders beim Ändern der Größe) noch so meine Probleme, mitlerweile habe ich das aber - meiner Meinung nach - sehr elegant gelößt. Jetzt beschäftige ich als nächstes mal mit - achtung - Instanced Indrect Rendering mit Compute Shader Culling! Klingt kompliziert - ist es auch. Aber wer wäre ich denn wenn mich komplizierte Sachen nicht reizen würden. Man muss ja schließlich immer was dazu lernen, nicht war?

1. Oktober 2025

Long time no see! Wärend meiner Praxisphase habe ich wenig am Projekt weiter gearbeitet - gestärkt bin ich jetzt zurück. Das Instanced Indirect Rendering mit Compute Shader Culling macht gute Fortschritte. Ich habe viel über Vulkan gelernt, besonders über die Architektur eines solchen Spiels. Ich bin mitlerweile auf den VMA (Vulkan Memory Allocator) umgestiegen und auch die ersten Klassen zur Pipeline-Erstellung und anderen Resourcen existieren mitlerweile. Synchronisierung ist immer noch komplex, durch die Helfer-Klassen geht im eigentlichen Code aber viel komplexität verloren. Dadurch sollte die Synchronisierung einfacher handhabbar sein. Hoffentlich brauche ich also keinen Render-Graph. Vielleicht habe ich in der nächsten Woche aber schon mal Logik-Gatter (Aka Vierecke) auf dem Bildschirm!

21. Oktober 2025

Es geht voran! Am Samstag hatte ich um 3 Uhr Nachts DIE Eingebung meines Lebens. Alle Gedanken der letzten 12 Monate sind zusammen geflossen. In 40 Zeilen habe ich meine Gedanken heruntergeschrieben und grob zusammen-gefasst, wie die interne Struktur aussehen soll!

40 Zeilen

Das Plugin registriert einen Chip mit Namen. Außerdem werden Funktionen zum (de-)serialisieren der Simulations und Graphic Komponenten bereitgestellt. Wenn der Host einen Chip instantiiert, geht er zum Plugin und instanziert die Simulations-Klasse. (Die Instanz der Simulation wird als SimulationComponent im Entity mit named storage gespeichert.) Ein Mapping von Simulationsinstanz -> Entity wird verwaltet. Jede Simulationsnode besitzt eine Funktion für das erhalten der grafischen Daten. Also alle Daten die übers netz synchronisiert werden sollen. Diese wird initial aufgerufen und das ergebnis in einer übers netz synchronisierten GraphicComponent gespeichert. Über die Simulations instanz werden alle input und output pins geholt. Für die Pins werden jeweils Entitäten erzeugt mit einem Pin Component, der den Pin referenziert. Ein Mapping von Pin -> Entity wird verwaltet. Wenn die Simulationsinstanz updated holen wir uns über das Mapping die Entität, berechnen den GraphicComponent neu und setzen die GraphicComponent was zum Netzwerk sync führt. Dieses graphic-component berechnen kann im Batch laufen. Die simulation schreibt alle berechneten Instanzen in eine QUeue. Alle berechneten Output Pins werden ebenfalls in eine queue gesteckt. Beim abarbeiten der Output Pin queue holen wir uns über das Mapping die Entität und triggern ein onupdate was zum Netzwerk sync führt. Zu einem Output Pin kann immer nur ein Netzwerk gehören. Dafür wird ggf. irgendwo ein Mapping existieren. So kann das Netzwerk geupdated werden wenn der Pin sich ändert. Zum Rendern kann der GraphicComponent über das named storage performant abgefragt werden. Beim Reindern sollen auch andere Komponenten wie z.B. Settings abgefragt werden können.

Kopieren von Chips? -> Entscheidung des Spielers ob mit Daten oder ohne kopiert werden soll -> Simulations-Klasse muss mit oder ohne daten kopierbar sein (vom plugin implementiert was das bedeutet) -> Andere dem Entity angehängte Komponenten müssen ebenfalls kopiert werden (Rotation, Settings, etc.) -> Erstmal alle Komponenten Kopieren, dann Simulations Instanz kopieren mit regeln. -> Beim kopieren mehrer Chips:

  • Ausgewählte Chips kopieren. Temporäres Mapping von alten Chips zu neuen Chips verwalten
  • Verbindungen durch gehen und herstellen, falls ziel und ursprung in dend kopierten Chips sind Chip-Makros?
  • Ausgewählte Chips kopieren
  • Falls Verbindungen zu außenstehenden Chips bestehen abbrechen.
  • Input und Output Chips suchen und pins erzeugen. -> Infinite Rekursion Chips:
    Settings - Component: Wie funktioniert die Netzwerk synchronisation? -> Settings Änderung führt zu Event zum Server: Ändert die Settings Komponente. -> Bei dem Client mit Simulation muss das Plugin die Settings-Änderung mitbekommen können und ggf. die Simulationsinstanz anpassen können History? -> Alter State der Komponenten speichern & ggf. wiederherstellen

Diese 40 Zeilen sind teilweise stark vereinfacht und sind nicht gedacht von anderen gelesen zu werden ;). Über die Monate hinweg hat sich ja auch folgendes DrawIO-Diagram entwickelt, welches auch in GitHub zu finden ist:

image

Jetzt habe ich bereits die Plugin-Schnittstelle geschrieben - zumindest zum Chip-Registrieren sollts erstmal reichen. Als nächstes will ich die ECS-Logik einbauen, so sollte dann alles zusammen finden! What a time to be alive ;)

23. Oktober 2025

Ich bin begeistert liebe Menschen und ich hoffe ihr seid es auch, denn ich darf euch präsentieren:

Loaded plugin de.codelix:default with version 0
Hello World! From Plugin de.codelix:default
Plugin API Version: 0
Registering chip de.codelix:and
Creating not gate
Created chip
2230246 updates/s
2243317 updates/s
2241035 updates/s
2240869 updates/s

Cool, nicht? Hier könnt ihr eine erfolgreiche Simulation sehen :) Und nicht nur das, der simulierte Chip wird von einem Plugin bereitgestellt, welches zur Laufzeit geladen wurde! Ja das ist auf jeden Fall die Errungenschaft des Tages, byee!

07. Januar 2026

Hallo liebe Leser und willkommen in 2026! :)

In der Zwischenzeit ist viel passiert! Das ECS ist endlich synchronisiert und verbindet eine beliebige Anzahl an clients in echtzeit! Darüber könnte ich und werde ich hoffentlich auch noch einen ganzen langen Artikel schreiben, denn das System ist echt spannend. Jetzt will ich mit Vulkan das ECS endlich auf den Bildschirm bringen, dann wäre eine 1. Version von BuildIT funktionsfähig.

Hinter diesen paar Sätzen stecken sehr, sehr, sehr viele Gedanken. Manchmal denke ich noch darüber nach wieso ich dafür eigentlich so lange brauche. Auf der einen Seite habe ich natürlich noch viel Anderes zu tun als hier 24/7 zu programmieren. Auf der anderen Seite musste ich mir auch erstmal das Datenorientierte Programmieren etwas beibringen, aber es wird!

Bis zum nächsten Mal, Felix

17. Januar 2026

"Yabadabadu" würde jetzt Fred Flintstone wohl sagen ;).

Heute wurde großartiges geschaffen! Die letzte Woche habe ich das ECS inklusive Networking mit Vulkan verbunden. Dabei habe ich noch einige wertvolle Stunden verloren CMake mit CPack richtig zu konfigurieren und zufrieden bin ich auch immer noch nicht, aber hey: Wir haben nun eine Modulare Anwendung, die eine ECS Registry synchronisiert und den Inhalt über Vulkan darstellen kann! Zum testen werden jetzt also ein paar Vierecke hin und her synchronisiert. (Viele). Das ganze ist alles noch etwas provisorisch, aber schaut schon richtig gut aus.

Ich war etwas erstaunt als ich mir Spaßeshalber die Zeilen an Code ausgegeben habe. Im aktuellen Codestand sind das nämlich "nur" 4128. Aber da zeigt sich wohl, dass viel Code nicht immer besserer Code ist ;) Bis vor 2 Minuten endete der Satz so: "und ich will gar nicht wissen, wie viele hundert Tausend Zeilen ich schon verändert habe ^^". Dann habe ich mir gedacht, dass ich das doch mal nachsehen könnte. Dafür habe ich einen kleinen git command verwendet und es stellt sich heraus, dass ich am Projekt insgesammt schon über 300 Tausend Zeilen hinzugefügt oder entfert habe, das ist ganzschön viel :). Jetzt werde ich versuchen das System auszubauen, mit echten Logikgattern und einer ersten Simulation (auch nur ein weiteres Modul, das ja schon prinzipiell funktioniert).

Bis Bald :)

Felix


This post on GitHub

Written and developed with ♥ by Felix