This commit is contained in:
Torsten 2026-02-14 14:22:00 +01:00
parent 8f6e50f3d8
commit 30b6ade7c4
38 changed files with 1059 additions and 0 deletions

82
prompts/main.txt Normal file
View file

@ -0,0 +1,82 @@
Für mein NWN/Godot Projekt brauche ich eine Referenzimplementierung für die Client/Server Logik.
Client und Server sind in der gleichen Codebase/Projekt. Normal aufgerufen, kann der Anwender
Join und Host auswählen. Stellt das Programm fest, dass es headless läuft, wird automatisch als Host gestartet.
Die Szenen(Areas) in denen die Spieler laden, werden nach bedarf geladen. Wenn Spieler A in Area 1 ist, hat sein
Client nur Area 1 geladen. Wenn Spieler B in Area 2 ist, hat sein Client nur Area 2 geladen. Nur
Host hat beide Areas geladen, und synchronisiert seine Area 1 mit Area 1 des Clients von Spieler A und
seine Area 2 mit der Area 2 des Clients von Spieler B. Ein Übergang zu einer anderen Area kann vom Host veranlasst
werden . Er lädt die neue Area(Szene) und erzeugt den Avatar des Spielers. Der Client des betroffenen Spielers
muss die neue Area(Szene) auf seiner Seite ebenfalls laden, damit die Szenenobjekte synchronisiert werden können.
Sorge dafür, dass die Areas auf dem Server sich nicht überlagern. Jeder MultiPlayerSynchronizer sollte nur
position der Spieler synchronisieren, aber nicht global_position.
Jede Area soll auf dem Server einen eigenen SubViewport haben. (Godot Multi-World Physics)
Sorge mit Visibility Filtering dafür, dass die MultiplayerSynchronizer nur die Objekte in ihrer jeweiligen Area synchronisieren.
Aus Performancegründen soll die Click-to-Move Funktionalität über AStar implementiert werden.
Das Spielermodell liegt unter res://systems/player/player.tres
Area 1 liegt unter res://maps/outdoor/grass/keuwin_grasland.tscn
Area 2 liegt unter res://maps/planes/fugue/halle_der_ahnen.tscn
Alle Scripte müssen in einem thematisch passenden Subfolder unterhalb res://systems/ abgelegt werden.
Dies ist die Struktur des Projektes:
/assets/ # REINE ROHDATEN (Dumm, keine Spiellogik)
/characters/
/humanoid/
/base_meshes/ # .glb Dateien und .tres (Mesh-Resources)
/materials/ # .tres (Material-Resources)
/environment/
/dungeon/ # Tileset-Modelle
/nature/ # Bäume, Steine
/items/
/armor/
/weapons/
/consumables/
/systems/ # DAS GEHIRN (Logik, muss auf dem Server laufen)
/core/ # Game-Loop, Signale, State-Machine
/network/ # Multiplayer, Peer-Handling, Headless-Logik
/player/ # Player-Controller (ohne Kamera/UI)
/ai/ # NPC-Verhalten, Monster-Logik
/combat/ # Regelwerk, Würfelwürfe, Stats
/dialogue/ # Gesprächs-Logik, Quests
/inventory/ # Item-Management, Container
/interaction/ # Türen, Hebel, Portale
/navigation/ # AStar-Management, Pathfinder
/simulation/ # Tag-Nacht-Zyklus, Fraktionen
/data/ # Speicher-Logik, DB-Anbindung
/fx/ # Wetter-Logik, Sound-Trigger
/ui/ # DAS GESICHT (Nur für den Client)
/hud/ # Permanente Anzeigen (HP, Chat)
/menus/ # Startmenü, Optionen
/windows/ # Inventar-Fenster, Charakterbogen
/components/ # Buttons, Slots, wiederverwendbare Teile
/themes/ # Schriften, Styles, Visual Design
/maps/ # DIE WELT (Szenen, in denen man spielt)
/templates/ # Basis-Setups für neue Karten
/outdoor/ # Wald, Wüste, Gebirge
/indoor/ # Häuser, Burgen
/dungeons/ # Krypten, Höhlen
/planes/ # Andere Existenzebenen
/audio/ # KLANGWELT
/music/ # Hintergrundmusik (.ogg)
/sfx/ # Geräusche (Schwert, Schritte)
/ambience/ # Atmosphäre-Loops (Wind, Feuer)
/data/ # DIE DEFINITIONEN (Inhaltliche Datenkarten)
/items/ # .tres Dateien für jedes Schwert/Schild
/tables/ # SQLite .db oder JSON-Tabellen
/licencing/ # Rechtliches (Asset-Lizenzen)
Erstelle bitte eine Referenzimplementierung, die folgende Funktionen abdeckt: Host Game, Join Game, Scenenwechsel, Server-Authority
Erzeuge so wenige Dateien wie möglich.

3
tools/start_server.sh Executable file
View file

@ -0,0 +1,3 @@
#/opt/godot/Godot_v4.6-stable_linux.x86_64 --path /home/torsten/repos/weltenauge/weltenauge --headless -- --server
#/opt/godot/Godot_v4.6-stable_linux.x86_64 --path /home/torsten/Dokumente/Gamedev/Projekt_Weltenauge/Projekt_Weltenauge --headless -- --server
/opt/godot/Godot_v4.6-stable_linux.x86_64 --path /home/tschneider/Dokumente/GameDev/Projekt_Weltenauge/Projekt_Weltenauge --headless -- --server

1
weltenauge/.cursorrules Normal file
View file

@ -0,0 +1 @@
Always use Godot 4.x GDScript syntax. Prefer static typing (e.g., var x: int = 5) and use the @onready annotation for nodes.

4
weltenauge/.editorconfig Normal file
View file

@ -0,0 +1,4 @@
root = true
[*]
charset = utf-8

3
weltenauge/.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,3 @@
{
"godotTools.editorPath.godot4": "/opt/godot/godot_v4.6-stable_linux.x86_64"
}

Binary file not shown.

View file

@ -0,0 +1,54 @@
[remap]
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://do451iws7munv"
path="res://.godot/imported/dude.glb-2cdcb6b05658711e71be066b772220a0.scn"
[deps]
source_file="res://assets/characters/humanoid/dude.glb"
dest_files=["res://.godot/imported/dude.glb-2cdcb6b05658711e71be066b772220a0.scn"]
[params]
nodes/root_type=""
nodes/root_name=""
nodes/root_script=null
nodes/apply_root_scale=true
nodes/root_scale=1.0
nodes/import_as_skeleton_bones=false
nodes/use_name_suffixes=true
nodes/use_node_type_suffixes=true
meshes/ensure_tangents=true
meshes/generate_lods=true
meshes/create_shadow_meshes=true
meshes/light_baking=1
meshes/lightmap_texel_size=0.2
meshes/force_disable_compression=false
skins/use_named_skins=true
animation/import=true
animation/fps=30
animation/trimming=false
animation/remove_immutable_tracks=true
animation/import_rest_as_RESET=false
import_script/path=""
materials/extract=0
materials/extract_format=0
materials/extract_path=""
_subresources={
"meshes": {
"Dude_Cube_002": {
"generate/lightmap_uv": 0,
"generate/lods": 0,
"generate/shadow_meshes": 0,
"lods/normal_merge_angle": 20.0,
"save_to_file/enabled": true,
"save_to_file/fallback_path": "res://assets/characters/humanoid/Dude.tres",
"save_to_file/path": "uid://c6h0s0by6gg3n"
}
}
}
gltf/naming_version=2
gltf/embedded_image_handling=1

View file

@ -0,0 +1,99 @@
[gd_resource type="ArrayMesh" format=4 uid="uid://bi22s15yeh6mw"]
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_h8qyk"]
resource_name = "pink.002"
cull_mode = 2
albedo_color = Color(0.8201731, 0.17311497, 0.9063355, 1)
roughness = 0.5
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_c6dnh"]
resource_name = "schwarz"
cull_mode = 2
albedo_color = Color(0, 0, 0, 1)
roughness = 0.5
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_i8imj"]
resource_name = "weiss"
cull_mode = 2
albedo_color = Color(0.9063318, 0.9063318, 0.9063318, 1)
roughness = 0.5
[sub_resource type="ArrayMesh" id="ArrayMesh_wt8sa"]
_surfaces = [{
"aabb": AABB(-0.28403106, 0.008408189, -0.083770275, 0.6, 0.6000001, 0.60000014),
"format": 34896613377,
"index_count": 582,
"index_data": PackedByteArray("PQAGAD4APQAEAAYAPwAGAAQAQAAEAD0APwAEAEAAHAAGAD8AHAA+AAYAQQA/AEAAQgA9AD4AQAA9AEMAQwA9AEIARABAAEMAQQBAAEQAGAA/AEEAGAAcAD8ANABBAEQAHAAYABoAHAAaAB0AGAAZABoAHgAcAB0AHgA+ABwAHgAdABsAFgAbABkAGAAWABkAFgAeABsAEQAYAEEAEQBBADQARQAWABgARQAYABEARQARABIAEQANABIARQASABMAEQBGAA0ARgARADQARgALAA0ARwBFABMARwAWAEUARwATABUARwAfABYAHwAeABYAFABHABUAFAAfAEcAFAAVABAARgAIAAsACAAKAAsARgA0AEgACABGAEgASAA0AEkANABEAEkASQBEAEoARABDAEoASABJAEsASgBDAEwAQwBCAEwASQBKAE0ASwBJAE0ASgBMADUATQBKADUATgBIAEsACABIAE4ASwBNAE8ATQA1AFAATwBNAFAAUQBLAE8ATgBLAFEABwBOAFEAUgAIAE4AUgBOAAcABwBRAAAAAABSAAcAUQBPAFMAAABRAFMAUwBPAFQATwBQAFQAAABTAFUAAABVAFIAUwBUAFYAVQBTAFYAVABQAFcAVQBYAFIAWAAIAFIAVQBWAFkAVQBZAFgAVgBUAFoAVABXAFoAWQBWAFsAVgBaAFsAWABcAAgACABcAAoAXAAMAAoAXQBcAFgAWQBdAFgAXABeAAwAXQBeAFwAXgAOAAwAWQBfAF0AWQBbAF8AYABeAF0AXwBgAF0AXgAJAA4AYAAJAF4ACQAPAA4AXwBhAGAACQBiAA8AYgAQAA8AAgAJAGAAYQACAGAAYgAUABAAYQABAAIAAgAwAAkAMABiAAkAAQAwAAIAMgAUAGIAMAAyAGIAAQAxADAAMQAyADAAYQAxAAEAXwBjAGEAYQBjADEAXwBbAGMAMQAzADIAYwAzADEAWwBkAGMAYwBkADMAWwBaAGQAMwA8ADIAMgA8ABQAZABlADMAMwBlADwAWgBmAGQAZABmAGUAWgBXAGYAPAAXABQAZQA7ADwAPAA7ABcAZgBnAGUAZQBnADsAVwBoAGYAZgBoAGcAFAAXAB8AVwBpAGgAUABpAFcAUAA1AGkANQBqAGkANQBMAGoAaQBrAGgAaQBqAGsAaABrADgAaAA4AGcATAA2AGoATABCADYAagBsAGsAagA2AGwAawADADgAawBsAAMAOAADAAUAZwA4ADoAOAAFADoAZwA6ADsAAwA5AAUAAwBsADkAOgAFADkAOwA6ACEAOgA5ACEAbAA3ADkAbAA2ADcAIQA5ADcAOwAhABcANgBtADcANgBCAG0AQgA+AG0AHgBtAD4AIAA3AG0AIABtAB4AIQA3ACAAHwAgAB4AKgAhACsAKwAhACwAIQAqACkAIAAsACEAIQApABcAIAAtACwAIAAuAC0ALgAgAC8ALwAgACYAHwAmACAAHwAkACYAJAAfACMAIwAfACIAFwAiAB8AFwAlACIAFwAnACUAJwAXACgAKAAXACkA"),
"lods": [0.00012957268, PackedByteArray("AAABAAIAAQAwAAIAAQAxADAAAAAxAAEAAgAwAAkAMQAyADAAMAAyAAkAMQAzADIAAAAzADEAAAACAAcAAgAIAAcAAgAJAAgABwAEAAAACAA0AAcABwA0AAQAAAAEADUAAAA1ADMANAAGAAQANQAEADYANgAEAAYANgADADUAEQAGADQACAARADQANgAGADcAAwA2ADcANQADADgANQA4ADMAOAADAAUAAwA3ADkAAwA5AAUAOAAFADoAOgAFADkAMwA4ADoAIQA5ADcAOgA5ACEAMwA6ADsAOwA6ACEAMwA7ADwAMwA8ADIAPAA7ABcAOwAhABcAMgA8ABQAPAAXABQAMgAUAAkAJwAXACgAFwAnACUAKAAXACkAIQApABcAFwAlACIAIQAqACkAKgAhACsAKwAhACwAFwAiAB8AFAAXAB8AIwAfACIAJAAfACMAIAAsACEAHwAkACYAHwAmACAALwAgACYAIQA3ACAALgAgAC8AIAAtACwAIAAuAC0AIAA3AAYAHwAgAB4AIAAGAB4AHwAeABYAFAAfABYAHgAGABwAHgAcAB0AHgAdABsAFgAeABsAHAAaAB0AFgAbABkAGAAcAAYAHAAYABoAGAAZABoAGAAWABkAEQAYAAYAEQAWABgAFAAWABEAFAARABMAEQASABMAFAATABUAEQANABIAFAAVABAAEQAIAA0ACAALAA0ACAAKAAsACAAMAAoACQAUABAACAAJAAwACQAQAA8ACQAOAAwACQAPAA4A"), 0.00025139967, PackedByteArray("AAABAAIAAAADAAEAAAAEAAMAAQADAAUAAQAFAAIAAwAEAAYAAwAGAAUABwAEAAAAAAACAAcABwAGAAQAAgAIAAcACAAGAAcAAgAJAAgAAgAFAAkACAAKAAsACAAMAAoACAALAA0ACAAJAAwACQAOAAwACQAPAA4ACQAQAA8AEQAIAA0AEQANABIACAARAAYAEQASABMACQAUABAAFAARABMAFAAVABAAFAATABUABQAUAAkAFAAWABEABQAXABQAEQAWABgAEQAYAAYAGAAWABkAGAAZABoAFgAbABkAHAAYABoAGAAcAAYAHAAaAB0AHgAdABsAHgAcAB0AFgAeABsAHgAGABwAFAAfABYAHwAeABYAFAAXAB8AIAAGAB4AIAAFAAYAHwAgAB4ABQAhABcAIQAFACAAFwAiAB8AIwAfACIAJAAfACMAFwAlACIAHwAkACYAHwAmACAAFwAnACUAJwAXACgAKAAXACkAIQApABcAIQAqACkAKgAhACsAKwAhACwAIAAsACEAIAAtACwAIAAuAC0ALgAgAC8ALwAgACYA")],
"name": "pink.002",
"primitive": 3,
"uv_scale": Vector4(0, 0, 0, 0),
"vertex_count": 110,
"vertex_data": PackedByteArray("AAAAAAAAAAD//wAAAAAAAP//AAD//wAA/////wAAAAAAAP//AAAAAP///////wAAAAD/////AAAAAAAA//8AADIzqir//wAAzMyqKv//AABlZqoqefAAADIzqip58AAAmZmqKnnwAAAyM1RVefAAAMzMqip58AAAzMxUVXnwAADMzP9/efAAADIz/3///wAAMjP/f3nwAABlZv9/efAAAMzM/3///wAAmZn/f3nwAABlZqqq//8AAMzMqqr//wAAMjOqqv//AABlZqqq+PMAADIzqqr48wAAZWZU1fjzAAAyM1TV//8AADIzVNX48wAAZWZU1f//AACZmaqq//8AAJmZVNX//wAAzMxU1f//AACZmaqqKOwAAJmZ/78o7AAAmZmpyijsAAAhoqqqKOwAAJmZVNUo7AAAqaqqqijsAAAys6qqKOwAAMzMqqoo7AAAzMz/vyjsAADMzKnKKOwAAMzMVNUo7AAAMrNU1SjsAACpqlTVKOwAACGiVNUo7AAA//+qKv//AAD//6oqAAAAAP//VFX//wAA//9UVQAAAAAAAP9///8AAGVmqqoAAAAAmZn//wAAAACZmf////8AAP//VNUAAAAAzMz/////AAD//1TV//8AAP//qqr//wAA////f///AAAyM///AAAAADIz/////wAAAABU1f//AAAAAFTVAAAAAAAAqqr//wAAZWb//wAAAAAyM1TVAAAAAAAAqqoAAAAAZWb/f///AAAyM1RV//8AAJmZ/3///wAAAABVVf//AAAAAP9/AAAAADIzqqoAAAAAAABUVQAAAABlZlTVAAAAADIz/38AAAAAAACqKv//AAAyM1RVAAAAAGVm/38AAAAAAACqKgAAAAAyMwAA//8AADIzqioAAAAAZWZUVQAAAAAyMwAAAAAAAGVmqioAAAAAmZn/fwAAAABlZgAA//8AAGVmAAAAAAAAmZlUVQAAAACZmaoqAAAAAGVmqir//wAAmZkAAP//AACZmaoq//8AAJmZAAAAAAAAzMwAAP//AADMzAAAAAAAAMzMVFX//wAAzMyqKgAAAADMzFRVAAAAAP///38AAAAAzMz/fwAAAAD//6qqAAAAAMzMqqoAAAAAmZmqqgAAAACZmVTVAAAAAMzMVNUAAAAAzMz//wAAAABlZv////8AAA==")
}, {
"aabb": AABB(-0.16403107, 0.10840821, 0.46973133, 0.36, 0.39999998, 0.03833282),
"format": 34896613377,
"index_count": 174,
"index_data": PackedByteArray("CgALAAwACgANAAsACgAOAA0ADwAMAAsADQAOABAAEAAMAA8ADQARAAsACwARABIACwASAA8ADQATABEADwASABQAEAAVAA0AEAAPABUAFQATAA0ADwAUABUAFQAUABMAFgAXABgAFgAZABcAGgAWABgAGgAYABsAHAAZABYAHAAdABkAHgAbAB8AHgAaABsAIAAaAB4AGgAhABYAFgAhACIAFgAiABwAGgAjACEAIAAkABoAJAAjABoAJQAkACAAJAAmACMAHAAiACYAHAAmACQAJQAnACQAJwAcACQAKAAnACUAKAApACcAJwAqABwAKQAqACcAKgAdABwAKQArACoAKgAsAB0AKwAsACoAKwAtACwAAAABAAIAAAAuAAEAAwABAC4ABQAuAAAAAwAuAAQABQAvAC4ALwAEAC4ACQAvAAUALwAGAAQACQAHAC8ABwAGAC8ABwAIAAYA"),
"lods": [0.1056379, PackedByteArray("AAABAAIAAwABAAAAAwAAAAQABQAEAAAABQAGAAQABwAGAAUABwAIAAYACQAHAAUA")],
"name": "schwarz",
"primitive": 3,
"uv_scale": Vector4(0, 0, 0, 0),
"vertex_count": 48,
"vertex_data": PackedByteArray("VFUAAJdDAAAAAP8/l0MAAAAAAACXQwAAAAD/f5dDAABUVf9/l0MAAKqqAACXQwAAqqr/f5dDAAD///8/l0MAAP///3+XQwAA//8AAJdDAAAAAP+/THoAAK8MKORMegAAAAD//0x6AABtIrbkTHoAAFRV/79MegAA0gzr8kx6AABUVf//THoAAK8MKOT//wAA0gzr8v//AABtIrbk//8AAOUgD/P//wAA5SAP80x6AADiuP/vAAAAAKqq//8AAAAAqqr/7wAAAADiuP//AAAAAOK4/98AAAAAqqr/3wAAAAAxzP/vAAAAABvH//8AAAAA4rj/vwAAAACqqv+/AAAAABvH/78AAAAA4rj/72FgAAAxzP/vYWAAAOK4/99hYAAAMcz/3wAAAABU1f+/AAAAADHM/99hYAAAVNX/3wAAAAD///+/AAAAAP///98AAAAAVNX/7wAAAAD////vAAAAAFTV//8AAAAA/////wAAAABUVf8/l0MAAKqq/z+XQwAA")
}, {
"aabb": AABB(-0.14619195, 0.45840824, 0.48416355, 0.26931208, 0.029790878, 0.023900598),
"format": 34896613377,
"index_count": 12,
"index_data": PackedByteArray("AAABAAIAAAADAAEABAAFAAYABAAHAAUA"),
"name": "weiss",
"primitive": 3,
"uv_scale": Vector4(0, 0, 0, 0),
"vertex_count": 8,
"vertex_data": PackedByteArray("//8AAAAAAAAv5tPWAAAAAC/mAAAAAAAA///T1gAAAAAuABr+//8AABAdVj///wAABBv/////AAAAAOU3//8AAA==")
}]
blend_shape_mode = 0
[resource]
resource_name = "Dude_Cube_002"
_surfaces = [{
"aabb": AABB(-0.28403106, 0.008408189, -0.083770275, 0.6, 0.6000001, 0.60000014),
"attribute_data": PackedByteArray("x6zHrOH9x6zh/eH9x6zh/cesclfg/XJX4P2MqMesjKhVEvZkHQJyV44i9mRVEntyN1NyV1US/3+OIntyVRIImx0CjKj/QgibN1OMqMYy9mTGMnty/0L/f/9C9mT/QntyjKjh/XJXx6yMqMesclfh/WEhjiJMJo4iTCbGMmEhN1NMJv9CTCY3UzxlN1NRYDdTUWCzRTxlLjhRYC44h5M3U1aX/0JWlzdTh5P/QnEvN1OHKjdThyr/QnEvjiKHKsYyhyqOIn9+s0XIhDdTf343U8iEdUzIhBRJyISzRR0Cx6w3U8esN1Ph/R0C4f1yV3JXjKiMqHJXjKiMqHJXYZ//QpGbN1ORm/9CYZ83U5yjN1Nrp7NFa6c3U5yjs0V1r7NFpqs3U6ars0V1rzdTRHo3U/tz/0JEev9C+3MbS/tzz037c4NQ+3M3U0yPN1MDibNFTI+zRQOJFEkDiXVMA4k3U3dp/0LAbzdTd2k3U8Bvg1DAb89NwG8bS8Bv/0IrVzdTFlwuOBZcs0UrVy44Flw3U1zwcldc8Iyoz8dyV9jijKhU1Yyoz8eMqEu6cldLuoyoLjg4zbNF4f03U3DdJh3h/aEP4f0dAvZkVRJyV44iclcdAntyHQL/fx0Cg40dAgibN1P/f1SYx6wbiMesG4jh/f9/cleqZ+H9qmfHrON34f3jd8esVJjh/TdT9mT/QnJXN1N7csYyclfGMv9//0KDjTdTg42OIv9/N1MIm/9CjKjGMoyoxjIIm44ijKiOIgibVRKMqFUSg40Im3JXCJuMqIONcleDjYyo/3+MqHtycld7coyo9mRyV/ZkjKip7cesqe3h/XDdx6xw3eH9OM3HrDjN4f3/vMes/7zh/djicldU1XJXs0Wp7TdTqe0uOKntLjjh/bNFcN0uOHDdqiqp7aoq4f2qKnDds0U4zTdTOM2qKjjNs0X/vDdT/7yzRcesLjjHrC44/7yqKsesqir/vCYdx6wmHf+8oQ/HrCYdOM2hD/+8HQL/vKEPOM0dAjjNJh1w3aEPcN0dAnDdJh2p7aEPqe0dAqntYSHGMmEh/0I8ZbNFcS//QnEvxjIrV7NF"),
"format": 34896613399,
"index_count": 582,
"index_data": PackedByteArray("fQAZAH4AfQAbABkAfwB9AH4AfwB+AIAAewB/AIAAewCAAHoAgQB7AHoAgQB6AHkAGACBAHkAGAB5ABoAFgAMAIIAFgCDAAwAFwAWAIIAEwCDABYAFwCCAIQAEwCFAIMAFQAXAIQAFQCEAHgAhgAXABUAhwAVAHgAhgAUABcAhwB4AIgAiQAUAIYAEQCHAIgAEQCIAIoAiwARAIoAiwCKABIAjAARAIsAjACNABEAjgCNAIwAjgCPAI0AkACPAI4AkAAPAI8AEAAPAJAAEAB3AA8AdwCRAA8AdwB2AJEAdgANAJEAdgB1AA0AdQALAA0AdQB0AAsADQALAA4ADQAOAIkAiQAOABQADgATABQADgAKABMACgCFABMACgBzAIUAdAAIAAsACABzAAoAdABxAAgACAByAHMAcQByAAgAcQAJAHIAkgA8AJMAkgA+ADwAlACSAJMAlACTAJUAfACUAJUAfACVAJYAlwB8AJYAlwCWAJgAmQCXAJgAmQCYAJoAOwCZAJoAOwCaAD0AmwACAJwAmwABAAIAnQCbAJwAnQCcAJ4AnwCdAJ4AnwCeAKAAoQCfAKAAoQCgAKIAAAChAKIAAACiAAMAZAAGAGUAZAAFAAYAowBkAGUAowBlAGcApACjAGcApABnAGgAZgCkAGgAZgBoAGkAagBmAGkAagBpAGsABABqAGsABABrAAcApQA5AG0ApQCmADkApwClAG0ApwBtAKgAqQCmAKUAqQBuAKYAqgClAKcAqgCpAKUAqwCnAKgAqwCoAKwArQCqAKcArQCnAKsArgBuAKkArgCvAG4AbACpAKoAbACuAKkAsACqAK0AsABsAKoAsQCvAK4AsQCyAK8AswCyALEAswA4ALIAtACzALEAtQCxAK4AtACxALUAtQCuAGwAtgC0ALUAtwC1AGwAtgC1ALcAtwBsALAAuAC2ALcAuAC3ALkAuQC3ALAAugC4ALkAuQCwALsAugC5ALwAvAC5ALsANwC6ALwAuwCwAK0ANwC8AL0AvQC8AL4AvAC7AL4AvQC+AL8AuwCtAMAAvgC7AMAAwACtAKsAvwC+AMEAvgDAAMEAvwDBAMIAwACrAMMAwQDAAMMAwwCrAKwAwwCsAG8AwQDDAMQAwgDBAMQAxADDAG8AwgDEAMUAxABvAHAAxQDEAHAAxQBwADoAxgAdAB4AxgAcAB0AxwDGAB4AxwAeACAAHwDHACAAHwAgACEAyAAjACQAyAAiACMAJQDIACQAJQAkACYAJwAoACkAJwAqACgAyQAsAC0AyQArACwAygDJAC0AygAtAC8ALgDKAC8ALgAvADAAMQAyADMAMQA0ADIANAAxADUANQAxADYAPwBAAEEAPwBCAEAAQwBEAEUAQwBGAEQARwBIAEkARwBKAEgASwBMAE0ASwBOAEwASwBPAE4ATwBLAFAAUABLAFEAUgBTAFQAUgBVAFMAVQBSAFYAVgBSAFcAWABZAFoAWABbAFkAWABcAFsAXABYAF0AXQBYAF4AywBgAGEAywBiAGAAXwDLAGEAXwBhAGMA"),
"lods": [0.00012957268, PackedByteArray("AAABAAIAAAACAAMAZAAGAGUAZAAFAAYAZgBkAGUAZgBlAGcAZgBnAGgAZgBoAGkAagBmAGkAagBpAGsABABqAGsABABrAAcAbAA5AG0AbgA5AGwAbAA4AG4AbABtAG8ANwA4AGwANwBsAG8ANwBvAHAANwBwADoAcQByAAgAcQAJAHIACAByAHMAdABxAAgACABzAAoAdAAIAAsAdQB0AAsACgBzAAwAdQALAA0AdgB1AA0ADQALAA4AdgANAA8AdwB2AA8AEAB3AA8AEAAPABEAEAARABIAEQB4ABIAEQAVAHgAFQAMAHgADQAUABUADQAOABQAFQAUABcAFQAXAAwADgATABQADgAKABMACgAMABMAFwAWAAwAEwAMABYAGAB5ABoAGAB6AHkAGAB7AHoAewAZAHoAewAbABkAHAAdAB4AHwAcAB4AHwAeACAAHwAgACEAIgAjACQAJQAiACQAJQAkACYAJwAoACkAJwAqACgAKwAsAC0ALgArAC0ALgAtAC8ALgAvADAAMQAyADMAMQA0ADIANAAxADUANQAxADYAOwA8AD0AOwB8ADwAfAA+ADwAPwBAAEEAPwBCAEAAQwBEAEUAQwBGAEQARwBIAEkARwBKAEgASwBMAE0ASwBOAEwASwBPAE4ATwBLAFAAUABLAFEAUgBTAFQAUgBVAFMAVQBSAFYAVgBSAFcAWABZAFoAWABbAFkAWABcAFsAXABYAF0AXQBYAF4AXwBgAGEAXwBiAGAAXwBhAGMA"), 0.00025139967, PackedByteArray("AAABAAIAAAACAAMABAAFAAYABAAGAAcACAAJAAoACQAIAAsACgAJAAwACQALAA0ADQALAA4ACQANAA8AEAAJAA8AEAAPABEAEAARABIAEQAMABIADgAKABMACgAMABMADQAOABQADgATABQADQAUABUAEQAVAAwAEwAMABYAFQAUABcAFwAWAAwAFQAXAAwAGAAZABoAGAAbABkAHAAdAB4AHwAcAB4AHwAeACAAHwAgACEAIgAjACQAJQAiACQAJQAkACYAJwAoACkAJwAqACgAKwAsAC0ALgArAC0ALgAtAC8ALgAvADAAMQAyADMAMQA0ADIANAAxADUANQAxADYANwA4ADkANwA5ADoAOwA8AD0AOwA+ADwAPwBAAEEAPwBCAEAAQwBEAEUAQwBGAEQARwBIAEkARwBKAEgASwBMAE0ASwBOAEwASwBPAE4ATwBLAFAAUABLAFEAUgBTAFQAUgBVAFMAVQBSAFYAVgBSAFcAWABZAFoAWABbAFkAWABcAFsAXABYAF0AXQBYAF4AXwBgAGEAXwBiAGAAXwBhAGMA")],
"material": SubResource("StandardMaterial3D_h8qyk"),
"name": "pink.002",
"primitive": 3,
"uv_scale": Vector4(0, 0, 0, 0),
"vertex_count": 204,
"vertex_data": PackedByteArray("AAAAAAAA/7///wAAAAD/v///AAD///+/AAAAAP///7///wAAAABU1f////8AAFTV////////VNX//wAA//9U1czMVNX///////////////+ZmVTV/////8zMqqr/////AAD////////MzP9//////5mZqqr/////zMyqKv///////wAA/////zIzqir/////AAAAAP////9lZlTV/////2Vmqqr/////MjP/f/////8yM1TV/////zIzqqr//////////wAA/78AAP//////v/////////+/AAD//wAA/7/MzKoq//9U1czMqip58FTVmZmqKnnwVNUyM6oq//9U1WVmqip58FTVMjOqKnnwVNUyM6oq////vzIzqip58P+/MjNUVXnw/78yM/9/////vzIz/3958P+/MjOqqv//VNVlZqqq+PNU1TIzqqr481TVZWaqqv//VNUyM/9///9U1TIz/3958FTVZWb/f3nwVNXMzP9///9U1ZmZ/3958FTVzMz/f3nwVNXMzFTV////v8zMqqoo7P+/zMyqqv///7/MzP+/KOz/v8zMqcoo7P+/zMxU1Sjs/78AAAAAAAD/vwAA//8AAP+//////wAA/7///wAAAAD/vwAAAAD//1TVAAD//wAAVNUAAAAAAABU1QAA/////1TVZWZU1f//VNUyM1TV+PNU1WVmVNX481TVMjNU1f//VNVlZqqq////v2VmVNX48/+/ZWaqqvjz/79lZlTV////vzIzVNX///+/MjOqqvjz/78yM1TV+PP/vzIzqqr///+/mZlU1f//VNXMzFTVKOxU1czMVNX//1TVMrNU1SjsVNWpqlTVKOxU1SGiVNUo7FTVmZlU1SjsVNWZmaqq////v5mZVNUo7P+/mZlU1f///7+ZmanKKOz/v5mZ/78o7P+/mZmqqijs/7/MzKqq//9U1ZmZqqoo7FTVmZmqqv//VNUhoqqqKOxU1amqqqoo7FTVMrOqqijsVNXMzKqqKOxU1czMqir///+/zMz/f3nw/7/MzFRVefD/v8zM/3////+/zMyqKnnw/7///1TVAABU1f//VNX//1TV//9UVQAAVNX//6qq//9U1f///3///1TV//9UVf//VNX//6oqAABU1f//qir//1TVZWaqqgAA/7///1TVAAD/v5mZ//8AAP+///9UVQAA/7///6oqAAD/v///VNX/////zMz///////+Zmf//////////qqr/////////f////////1RV////////qir/////AAD/f//////MzP//////v5mZ//////+/mZn//wAA/78AAP9///9U1TIz//8AAP+/MjP//////79lZv//AAD/v2Vm//////+/zMz//wAA/78AAFTV/////zIz////////AACqqv////9lZv///////2Vm/3//////MjNUVf////8AAFVV/////5mZ/3//////AACqKv////8yMwAA/////2VmAAD/////ZWaqKv////+ZmQAA/////5mZqir/////zMwAAP/////MzFRV/////wAAVNX//1TVAABU1QAAVNUAAKqq//9U1QAAqqoAAFTVAAD/fwAAVNUAAFVV//9U1QAAVFUAAFTVAACqKv//VNUAAKoqAABU1czMAAAAAP+/zMwAAP///7+ZmQAAAAD/v5mZAAD///+/ZWYAAAAA/79lZgAA////vzIzAAAAAP+/MjMAAP///7///6qqAABU1f///38AAFTVzMxU1QAA/7/MzP//AAD/v8zMqqoAAP+///+qqgAA/7+ZmVTVAAD/v5mZqqoAAP+/zMz/fwAA/7////9/AAD/v5mZ/38AAP+/ZWZU1QAA/79lZv//AAD/v2Vm/38AAP+/MjNU1QAA/78yM///AAD/vwAAVNUAAP+/AACqqgAA/78yM6qqAAD/vwAA/38AAP+/MjP/fwAA/78AAFRVAAD/vzIzVFUAAP+/AACqKgAA/79lZlRVAAD/vzIzqioAAP+/MjMAAAAA/79lZqoqAAD/v2VmAAAAAP+/mZlUVQAA/7+ZmaoqAAD/v5mZAAAAAP+/zMxUVQAA/7/MzKoqAAD/v8zMAAAAAP+/mZmqKv//VNVlZqoq//9U1TIzVFX///+/ZWb/f///VNWZmf9///9U1czMVFX///+/////f////3////9/////f1TVVNVU1VTVVNVU1VTVVNX/f////3////9/////f////3////9/////f////3////9/////f/7//3////9/////f////3////9/////f///AAD/fwAA/38AAP9/AAD/f1RVVFVUVVRVVFVUVVRVVFVUVVRVVFVUVf9/////f////3////9/////f///VFVUVVRVVFVUVVRVVFVUVaqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqv9/AAD/fwAA/38AAP9/AAD/fwAA/38AAP////////////////////+qKqoqqiqqKqoqqiqqKqoqqqqqqqqqqqqqqqqqqqqqqv9/AAD/fwAA/38AAP9/AAD/f////3////9/////f///qqqpqqqqqqqqqqqqqqqpqqqqqaqpqqqqqqqqqv9//v//f/7//3////9//v//f/7//3///1VVVFVUVVVVVFVUVVRVVVVVVVRVVVVUVVRVVFX/fwAA/38AAP9/AAD/fwAA/38AAFTVVNVU1VTVVNVU1VTVVNVU1VTVVNVU1VTVVNVU1VTV////////////////////////////f////3////9/////f////3////9/////f////3/+/wAA/38AAP9/AAD/f6oqqioAAP9/AAD/fwAA/38AAP9/AAD/f/9/////f////3////9/////f////3/+//9//v//f////3////9/////f////3////9/////f////3////9///+qKqoqqiqqKqoqqiqqKqoqqiqqKqoqqiqqKqoqqiqqKqoqqir///9/////f////3////9/////f////3////9/////f1TVVNVU1VTV////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////VFVUVVRVVFX/f///qqqqqqqqqqr/fwAA")
}, {
"aabb": AABB(-0.16403107, 0.10840821, 0.46973133, 0.36, 0.39999998, 0.03833282),
"attribute_data": PackedByteArray("HQL/QqEPN1MdAjdTJh03UyYd/0IdAsYyJh3GMqEPjiImHY4iHQKOIqwzN1NQO85QMUE3U24+x1BuO6xMMUH/Qqwz/0J1PvZMj0+DUPBSN1OPTzdT8FKDUC5Mg1CPT9dMLkw3U/BSz01sRYNQbEU3U2xFz00uTNdMbEUbSy5MG0tsRf9CLkz/Qo9PG0uPT/9C8FIbS/BS/0KhD/9CoQ/GMljgN1Nk3otPWOCLT2TeN1Pw8NZP4/I3U/DwN1Pj8tZPk+SLT4bmN1OT5DdThuaLT7XsN1PB6tZPtezWT8HqN1NKzDdTlclmT0rMZk+VyTdTpcIVT1rFN1OlwjdTWsUVT3XXL1Ap2jdTddc3UynaL1A60zdThdAZUDrTGVCF0DdT"),
"format": 34896613399,
"index_count": 174,
"index_data": PackedByteArray("CgALAAwADQAMAAsACgAOAAsADwAMAA0ACgAQAA4ADgAQAA8ADwARAA4ADwANABEAEgATABQAEgAVABMAFgASABQAFwAVABIAFgAUABgAFwAZABUAGgAWABgAGgAYABsAHAAWABoAHAAdABYAHgAdABwAHgAfAB0AHwAXAB0AIAAfAB4AIAAhAB8AHwAiABcAIQAiAB8AIgAZABcAIQAjACIAIgAkABkAIwAkACIAIwAlACQAAAABAAIAAAAmAAEAAwABACYABQAmAAAAAwAmAAQABQAnACYAJwAEACYACQAnAAUAJwAGAAQACQAHACcABwAGACcABwAIAAYAKAApACoAKAArACkALAAtAC4ALAAvAC0AMAAxADIAMAAzADEANAA1ADYANAA3ADUAOAA5ADoAOAA7ADkAPAA9AD4APAA/AD0AQABBAEIAQABDAEEARABFAEYARABHAEUA"),
"lods": [0.1056379, PackedByteArray("AAABAAIAAwABAAAAAwAAAAQABQAEAAAABQAGAAQABwAGAAUABwAIAAYACQAHAAUA")],
"material": SubResource("StandardMaterial3D_c6dnh"),
"name": "schwarz",
"primitive": 3,
"uv_scale": Vector4(0, 0, 0, 0),
"vertex_count": 72,
"vertex_data": PackedByteArray("VFUAAJdD//8AAP8/l0P//wAAAACXQ///AAD/f5dD//9UVf9/l0P//6qqAACXQ///qqr/f5dD//////8/l0P//////3+XQ/////8AAJdD//8AAP+/THr//68MKORMev//AAD//0x6///SDOvyTHr//20ituRMev//VFX//0x6//9UVf+/THr//+UgD/NMev//4rj/7wAA//+qqv//AAD//6qq/+8AAP//4rj//wAA///iuP/fAAD//zHM/+8AAP//qqr/3wAA//8bx///AAD//+K4/78AAP//qqr/vwAA//8bx/+/AAD//zHM/98AAP//VNX/vwAA//9U1f/fAAD//////78AAP//////3wAA//9U1f/vAAD//////+8AAP//VNX//wAA////////AAD//1RV/z+XQ///qqr/P5dD///iuP/vAABU1THM/+9hYFTVMcz/7wAAVNXiuP/vYWBU1THM/+8AAP+/Mcz/32Fg/78xzP/fAAD/vzHM/+9hYP+/Mcz/3wAAVNXiuP/fYWBU1eK4/98AAFTVMcz/32FgVNXiuP/fAAD/v+K4/+9hYP+/4rj/7wAA/7/iuP/fYWD/v9IM6/JMeiXV5SAP8///JdXlIA/zTHol1dIM6/L//yXVbSK25Ex6qtSvDCjk//+q1K8MKORMeqrUbSK25P//qtTlIA/zTHoXwG0ituT//xfAbSK25Ex6F8DlIA/z//8XwK8MKORMev+/0gzr8v///7/SDOvyTHr/v68MKOT///+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v/+//7//v1RVVFVUVVRVVFVUVVRVVFX/f////3////9/////f///qqqqqqqqqqqqqqqqqqqqqv9/AAD/fwAA/38AAP9/AABxVRxVcVUcVXFVHFVxVRxVQqp5q0KqeatCqnmrQqp5q850ZvrOdGb6znRm+s50Zvp4fw0BeH8NAXh/DQF4fw0B")
}, {
"aabb": AABB(-0.14619195, 0.45840824, 0.48416355, 0.26931208, 0.029790878, 0.023900598),
"attribute_data": PackedByteArray("CbuLT2q+N1MJuzdTar6LT862GlOwsxRPurZJT7CzN1M="),
"format": 34896613399,
"index_count": 12,
"index_data": PackedByteArray("AAABAAIAAAADAAEABAAFAAYABAAHAAUA"),
"material": SubResource("StandardMaterial3D_i8imj"),
"name": "weiss",
"primitive": 3,
"uv_scale": Vector4(0, 0, 0, 0),
"vertex_count": 8,
"vertex_data": PackedByteArray("//8AAAAA//8v5tPWAAD//y/mAAAAAP/////T1gAA//8uABr+/////xAdVj//////BBv///////8AAOU3//////+//7//v/+//7//v/+//78Xv+fAF7/nwBe/58AXv+fA")
}]
blend_shape_mode = 0
shadow_mesh = SubResource("ArrayMesh_wt8sa")

View file

@ -0,0 +1,6 @@
[gd_scene format=3 uid="uid://dgjgtr82ye25d"]
[ext_resource type="ArrayMesh" uid="uid://bi22s15yeh6mw" path="res://assets/characters/humanoid/dude.tres" id="1_jchph"]
[node name="Dude" type="MeshInstance3D" unique_id=1185543431]
mesh = ExtResource("1_jchph")

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

View file

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://d1cyxxj8ypfu"
path="res://.godot/imported/logo_projekt_weltenauge.png-faafe98462d8081c55aa7ba6fc11610a.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/icons/program/logo_projekt_weltenauge.png"
dest_files=["res://.godot/imported/logo_projekt_weltenauge.png-faafe98462d8081c55aa7ba6fc11610a.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

9
weltenauge/game_root.gd Normal file
View file

@ -0,0 +1,9 @@
extends Node
## Project Fugue - Zentrale Steuerung
## Orchestriert den Übergang zwischen Menü und Spielwelt.
@onready var main_menu = $MainMenu
func _ready():
print("--- Start: Projekt Weltenauge ---")

View file

@ -0,0 +1 @@
uid://162cjpb4lac4

View file

@ -0,0 +1,9 @@
[gd_scene format=3 uid="uid://cpxxy0664jyjm"]
[ext_resource type="Script" uid="uid://162cjpb4lac4" path="res://game_root.gd" id="1_xj5yv"]
[ext_resource type="PackedScene" uid="uid://bhywhrlwjox6t" path="res://ui/menus/main_menu.tscn" id="2_pjpa4"]
[node name="Game_root" type="Node2D" unique_id=1336425327]
script = ExtResource("1_xj5yv")
[node name="MainMenu" parent="." unique_id=1731390780 instance=ExtResource("2_pjpa4")]

1
weltenauge/icon.svg Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128"><rect width="124" height="124" x="2" y="2" fill="#363d52" stroke="#212532" stroke-width="4" rx="14"/><g fill="#fff" transform="translate(12.322 12.322)scale(.101)"><path d="M105 673v33q407 354 814 0v-33z"/><path fill="#478cbf" d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 814 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H446l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z"/><path d="M483 600c0 34 58 34 58 0v-86c0-34-58-34-58 0z"/><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042" transform="translate(12.322 12.322)scale(.101)"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></svg>

After

Width:  |  Height:  |  Size: 995 B

View file

@ -0,0 +1,43 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://d4fyt5amswlam"
path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://icon.svg"
dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false

8
weltenauge/main.tscn Normal file
View file

@ -0,0 +1,8 @@
[gd_scene format=3 uid="uid://2fal1f0f8fdh"]
[ext_resource type="ArrayMesh" uid="uid://bi22s15yeh6mw" path="res://assets/characters/humanoid/dude.tres" id="1_ig7tw"]
[node name="Node3D" type="Node3D" unique_id=1431241737]
[node name="MeshInstance3D" type="MeshInstance3D" parent="." unique_id=231315459]
mesh = ExtResource("1_ig7tw")

View file

@ -0,0 +1,43 @@
[gd_scene format=3 uid="uid://h5qt2pcidh8x"]
[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_d3jw7"]
[sub_resource type="Sky" id="Sky_1yg6u"]
sky_material = SubResource("ProceduralSkyMaterial_d3jw7")
[sub_resource type="Environment" id="Environment_8r0t0"]
background_mode = 2
sky = SubResource("Sky_1yg6u")
tonemap_mode = 2
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_30klc"]
albedo_color = Color(9.3854965e-07, 0.4579985, 0.32070312, 1)
[sub_resource type="PlaneMesh" id="PlaneMesh_0iae2"]
material = SubResource("StandardMaterial3D_30klc")
[node name="keuwin_grasland" type="Node3D" unique_id=1953380732]
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="." unique_id=1262732162]
transform = Transform3D(-0.8660254, -0.3535534, 0.3535534, 0, 0.70710677, 0.70710677, -0.50000006, 0.6123724, -0.6123724, 0, 0, 0)
light_color = Color(0.90022373, 0.9250896, 0.6778064, 1)
light_energy = 1.5
shadow_enabled = true
[node name="WorldEnvironment" type="WorldEnvironment" parent="." unique_id=1286599151]
environment = SubResource("Environment_8r0t0")
[node name="Architecture" type="Node3D" parent="." unique_id=97923552]
[node name="MeshInstance3D" type="MeshInstance3D" parent="Architecture" unique_id=1708107393]
transform = Transform3D(10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0)
mesh = SubResource("PlaneMesh_0iae2")
[node name="Navigation" type="Node3D" parent="." unique_id=1472582667]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.01873529, 0)
[node name="SpawnPoints" type="Node3D" parent="." unique_id=438053421]
[node name="Interaction" type="Node3D" parent="." unique_id=1592705952]
[node name="Triggers" type="Node3D" parent="." unique_id=1507691477]

View file

@ -0,0 +1,47 @@
[gd_scene format=3 uid="uid://bef0tj7n6g8uo"]
[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_d3jw7"]
sky_top_color = Color(0.055328622, 0.3637527, 0.67898166, 1)
ground_bottom_color = Color(0.28193337, 0.24096331, 0.19489476, 1)
ground_horizon_color = Color(0.5439266, 0.5434616, 0.51488423, 1)
[sub_resource type="Sky" id="Sky_1yg6u"]
sky_material = SubResource("ProceduralSkyMaterial_d3jw7")
[sub_resource type="Environment" id="Environment_8r0t0"]
background_mode = 2
sky = SubResource("Sky_1yg6u")
tonemap_mode = 2
fog_enabled = true
fog_light_color = Color(0.061652586, 0.3592321, 0.673373, 1)
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_30klc"]
albedo_color = Color(0.1800012, 0.004964735, 0.2305904, 1)
[sub_resource type="PlaneMesh" id="PlaneMesh_0iae2"]
material = SubResource("StandardMaterial3D_30klc")
[node name="halle_der_ahnen" type="Node3D" unique_id=1953380732]
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="." unique_id=1262732162]
transform = Transform3D(-0.8660254, -0.12940952, 0.48296294, 0, 0.96592575, 0.258819, -0.50000006, 0.22414385, -0.8365162, 0, 0, 0)
light_color = Color(0.94507605, 0.7726238, 0.95401555, 1)
light_energy = 0.5
shadow_enabled = true
[node name="WorldEnvironment" type="WorldEnvironment" parent="." unique_id=1286599151]
environment = SubResource("Environment_8r0t0")
[node name="Architecture" type="Node3D" parent="." unique_id=97923552]
[node name="MeshInstance3D" type="MeshInstance3D" parent="Architecture" unique_id=1708107393]
transform = Transform3D(10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0)
mesh = SubResource("PlaneMesh_0iae2")
[node name="Navigation" type="Node3D" parent="." unique_id=1472582667]
[node name="SpawnPoints" type="Node3D" parent="." unique_id=438053421]
[node name="Interaction" type="Node3D" parent="." unique_id=1592705952]
[node name="Triggers" type="Node3D" parent="." unique_id=1507691477]

32
weltenauge/project.godot Normal file
View file

@ -0,0 +1,32 @@
; Engine configuration file.
; It's best edited using the editor UI and not directly,
; since the parameters that go here are not all obvious.
;
; Format:
; [section] ; section goes between []
; param=value ; assign values to parameters
config_version=5
[application]
config/name="Project Weltenauge"
run/main_scene="uid://cpxxy0664jyjm"
config/features=PackedStringArray("4.6", "Forward Plus")
boot_splash/image="uid://d1cyxxj8ypfu"
config/icon="res://icon.svg"
boot_splash/minimum_display_time=1000
[autoload]
GameEvents="*uid://4xof67e363t4"
ChatManager="*uid://c351ysuym2mdm"
NetworkManager="*uid://tniwwfk5703p"
[physics]
3d/physics_engine="Jolt Physics"
[rendering]
rendering_device/driver.windows="d3d12"

View file

@ -0,0 +1,20 @@
extends Node
@warning_ignore("unused_signal")
# Spieler-bezogene Events
# signal player_health_changed(new_health, max_health)
# signal player_xp_gained(amount)
# Welt-bezogene Events
# signal area_transition_started(area_name)
# signal area_loading_finished
# Netzwerk-Events
# signal server_message_received(message, type)
# UI-Events
signal join_requested(ip: String)
@warning_ignore("unused_signal")
signal host_requested()

View file

@ -0,0 +1 @@
uid://4xof67e363t4

View file

@ -0,0 +1,26 @@
extends Node
# Signal für die UI, um neue Nachrichten anzuzeigen
signal message_received(sender_name: String, message: String, channel: String)
@rpc("any_peer", "call_remote", "reliable")
func send_message(message: String):
var peer_id = multiplayer.get_remote_sender_id()
# Serverseitige Validierung (Spam-Schutz, Filter)
if message.length() > 256:
message = message.left(256)
var sender_name = "Player " + str(peer_id) # Hier später Name aus DB laden
# Ermittle die Area des Spielers (Sichtbarkeits-Logik)
var area = NetworkManager.player_area_map.get(peer_id, "")
# Broadcast: Nur an Spieler in der gleichen Area senden (NWN-Style)
for id in NetworkManager.player_area_map:
if NetworkManager.player_area_map[id] == area:
rpc_id(id, "receive_message", sender_name, message, "local")
@rpc("authority", "call_remote", "reliable")
func receive_message(sender_name: String, message: String, channel: String):
message_received.emit(sender_name, message, channel)

View file

@ -0,0 +1 @@
uid://c351ysuym2mdm

View file

@ -0,0 +1,191 @@
extends Node
const PORT = 7777
const MAX_CLIENTS = 32
# Kamera (wird nur auf dem Client gebraucht)
var local_camera: Camera3D = null
# Mapping der Areas
var area_paths = {
"keuwin_grasland": "res://maps/outdoor/grass/keuwin_grasland.tscn",
"ahnenhalle": "res://maps/planes/fugue/halle_der_ahnen.tscn"
}
# Server-seitiges Tracking: peer_id -> SubViewport (World)
var player_worlds = {}
func _ready():
GameEvents.host_requested.connect(host_game)
GameEvents.join_requested.connect(join_game)
if DisplayServer.get_name() == "headless" or OS.get_cmdline_args().has("--server"):
host_game()
func host_game():
var peer = ENetMultiplayerPeer.new()
peer.create_server(PORT, MAX_CLIENTS)
multiplayer.multiplayer_peer = peer
multiplayer.peer_connected.connect(_on_player_connected)
print("Server gestartet. id=" + str(multiplayer.get_unique_id()))
func join_game(ip = "127.0.0.1"):
var peer = ENetMultiplayerPeer.new()
peer.create_client(ip, PORT)
multiplayer.multiplayer_peer = peer
func _on_player_connected(id):
print("Player connected with id:", id)
# Standardmäßig in Area 1 starten
change_player_area(id, "keuwin_grasland")
func change_player_area(id: int, area_key: String):
if not multiplayer.is_server(): return
print("Server is loading ", area_key)
var path = area_paths[area_key]
var container_name = area_key + "_container"
var viewport_name = area_key + "_viewport"
# Server: Erstelle SubViewportContainer + SubViewport für physikalische Trennung, falls nicht existent
var container_node = get_node_or_null(container_name)
if not container_node:
#container_node = SubViewportContainer.new()
container_node = Node3D.new()
container_node.name = container_name
add_child(container_node)
var viewport_node = container_node.get_node_or_null(viewport_name)
var map_instance = null
if not viewport_node:
viewport_node = SubViewport.new()
viewport_node.name = viewport_name
viewport_node.own_world_3d = true # Multi-World Physics!
container_node.add_child(viewport_node)
else:
map_instance = viewport_node.get_node_or_null(area_key)
# Spawner muss vor laden der map hinzugefügt werden
var spawner = viewport_node.get_node_or_null("AreaSpawner")
if not spawner:
spawner = MultiplayerSpawner.new()
spawner.name = "AreaSpawner"
print("Viewport Name: " + str(viewport_node.name))
# "." bedeutet: Er spawnt Objekte als direkte Kinder des Viewports
spawner.add_spawnable_scene("res://systems/player/player.tscn")
viewport_node.add_child(spawner)
spawner.spawn_path = viewport_node.get_path()
map_instance = load(path).instantiate()
map_instance.name = area_key
viewport_node.add_child(map_instance)
# --- ALTEN ZUSTAND AUFRÄUMEN ---
if player_worlds.has(id):
player_worlds.erase(id)
# --- NEUEN ZUSTAND REGISTRIEREN ---
player_worlds[id] = viewport_node
# Client anweisen, Szene zu laden
rpc_id(id, "client_load_area", area_key)
# Avatar auf Server erstellen erfolgt erst wenn Client Vollzug meldet (client_ready_to_spawn)
#_spawn_player_in_world(id, viewport_node)
@rpc("any_peer", "call_local", "reliable")
func client_ready_to_spawn():
var id = multiplayer.get_remote_sender_id()
if not multiplayer.is_server(): return
if player_worlds.has(id):
var viewport_node = player_worlds[id]
print("Client ", id, " ist bereit. Spawne jetzt.")
_spawn_player_in_world(id, viewport_node)
@rpc("authority", "call_remote", "reliable")
func client_load_area(area_key):
print("Client loads area")
# Client löscht alte Map, lädt neue lokal in das Root
for child in get_children():
if child.is_in_group("maps"): child.queue_free()
var container_name = area_key + "_container"
var viewport_name = area_key + "_viewport"
var container_node = SubViewportContainer.new()
container_node.name = container_name
container_node.stretch = true
container_node.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
add_child(container_node)
container_node.add_to_group("maps")
var viewport_node = SubViewport.new()
viewport_node.own_world_3d = true
viewport_node.name = viewport_name
viewport_node.size = Vector2i(1280,720)
container_node.add_child(viewport_node)
# Spawner muss existieren bevor die map zum Viewport hinzugefügt wird
var spawner = MultiplayerSpawner.new()
spawner.name = "AreaSpawner"
spawner.add_spawnable_scene("res://systems/player/player.tscn")
viewport_node.add_child(spawner)
spawner.spawn_path = viewport_node.get_path()
var map = load(area_paths[area_key]).instantiate()
map.name = area_key
viewport_node.add_child(map)
# Kamera-Setup nur beim ersten Laden oder falls sie gelöscht wurde
if not multiplayer.is_server() and local_camera == null:
setup_client_camera(viewport_node)
# Jetzt können wir dem Server ok fürs Spawnen geben
client_ready_to_spawn.rpc_id(1) # Server ist immer id=1
func setup_client_camera(node):
local_camera = Camera3D.new()
local_camera.set_script(load("res://systems/player/camera_logic.gd"))
local_camera.current = true
node.add_child(local_camera)
# Ein AudioListener gehört auf dem Client auch an die Kamera
local_camera.add_child(AudioListener3D.new())
func _spawn_player_in_world(id, viewport_node):
var player_scene = load("res://systems/player/player.tscn")
var player = player_scene.instantiate()
player.name = str(id)
player.set_multiplayer_authority(id)
viewport_node.add_child(player)
# Visibility Filtering: Nur Spieler im gleichen Viewport sehen sich
var sync = player.get_node("MultiplayerSynchronizer")
for other in viewport_node.get_children():
if other.is_in_group("players"):
var other_id = other.name.to_int()
# Der neue Spieler sieht den alten
other.get_node("MultiplayerSynchronizer").set_visibility_for(id, true)
# Der alte Spieler sieht den neuen
sync.set_visibility_for(other_id, true)
# Wir schicken dem Client eine Info, welchen Node er verfolgen soll
# (Da der Name des Player-Nodes die ID ist, weiß der Client welcher seiner ist)
rpc_id(id, "assign_camera_target", str(id))
@rpc("authority", "call_remote", "reliable")
func assign_camera_target(node_name: String):
# Der Client sucht seinen Player-Node im Baum
var p = get_tree().root.find_child(node_name, true, false)
if p and local_camera:
local_camera.target = p
# var camera = get_viewport().get_camera_3d()

View file

@ -0,0 +1 @@
uid://tniwwfk5703p

View file

@ -0,0 +1,12 @@
extends Camera3D
var target: Node3D = null
#var offset = Vector3(0, 12, 8) # Klassische NWN Perspektive
var offset = Vector3(0, 3, 4) # Klassische NWN Perspektive
func _process(delta):
if is_instance_valid(target):
# Sanftes Folgen (Lerp) für smoothe Bewegungen
var target_pos = target.global_position + offset
global_position = global_position.lerp(target_pos, delta * 5.0)
look_at(target.global_position)

View file

@ -0,0 +1 @@
uid://ctxhm624vs1ya

View file

@ -0,0 +1,34 @@
[gd_scene format=3 uid="uid://bjurf8vfd1fg8"]
[ext_resource type="PackedScene" uid="uid://dgjgtr82ye25d" path="res://assets/characters/humanoid/dude.tscn" id="1_2anqx"]
[ext_resource type="Script" uid="uid://bhym64rc7xtin" path="res://systems/player/player_controller.gd" id="1_ktl23"]
[sub_resource type="CylinderShape3D" id="CylinderShape3D_ktl23"]
[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_fqfg4"]
properties/0/path = NodePath("CharacterBody3D:sync_position")
properties/0/spawn = true
properties/0/replication_mode = 1
properties/1/path = NodePath("CharacterBody3D:sync_rotation")
properties/1/spawn = true
properties/1/replication_mode = 1
[node name="CharacterBody3D" type="CharacterBody3D" unique_id=682006733]
script = ExtResource("1_ktl23")
[node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=159496934]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.0185384, 0)
shape = SubResource("CylinderShape3D_ktl23")
[node name="Visuals" type="Node3D" parent="." unique_id=1840405751]
[node name="Dude" parent="Visuals" unique_id=1185543431 instance=ExtResource("1_2anqx")]
[node name="AnimationPlayer" type="AnimationPlayer" parent="." unique_id=1343500738]
root_node = NodePath("../..")
[node name="MultiplayerSynchronizer" type="MultiplayerSynchronizer" parent="." unique_id=656518492]
root_path = NodePath("../..")
replication_interval = 0.05
replication_config = SubResource("SceneReplicationConfig_fqfg4")
public_visibility = false

View file

@ -0,0 +1,110 @@
extends CharacterBody3D
@onready var synchronizer = $MultiplayerSynchronizer
@export var target_position: Vector3
@export var sync_position: Vector3
@export var sync_rotation: Vector3
var path: PackedVector3Array = []
var speed = 5.0
func _enter_tree():
# Da der Name des Nodes die Peer-ID ist, setzen wir die Authority einfach selbst
if name.is_valid_int():
set_multiplayer_authority(name.to_int())
func _ready():
target_position = global_position
# Wir schalten die automatische Physik-Synchronisation aus
set_physics_process(multiplayer.is_server())
func _physics_process(delta):
# Dieser Teil läuft NUR auf dem Server
if path.size() > 0:
var next_point = path[0]
var direction = (next_point - global_position).normalized()
# Wir nutzen move_and_slide, damit Kollisionen (Wände) funktionieren
velocity = direction * speed
move_and_slide()
# Nach der Bewegung speichern wir das Ergebnis für die Clients
sync_position = global_position
sync_rotation = rotation
if global_position.distance_to(next_point) < 0.2:
path.remove_at(0)
else:
velocity = Vector3.ZERO
sync_position = global_position # Sicherstellen, dass Standbild syncron bleibt
@rpc("any_peer", "call_remote", "reliable")
func request_move(target: Vector3):
if not multiplayer.is_server(): return
# Sicherheits-Check: Nur der Besitzer des Avatars darf ihn bewegen
if multiplayer.get_remote_sender_id() != get_multiplayer_authority():
return
# Hier später: path = astar.get_point_path(global_position, target)
#path = PackedVector3Array([target])
print("Target: ", target)
path = [target]
target_position = target
func _input(event):
# NUR der Client, der diesen Spieler kontrolliert, darf klicken
if not is_multiplayer_authority(): return
if DisplayServer.get_name() == "headless": return # Server ignoriert Klicks
if event is InputEventMouseButton and event.pressed:
print("Click")
var target = _get_click_floor_pos()
if target != Vector3.INF:
print(" Request move")
print(" ", target)
# RPC an den Server (ID 1)
request_move.rpc_id(1, target)
func _get_click_floor_pos():
# Wir brauchen die Kamera, die tatsächlich für diesen Viewport zuständig ist
var camera = get_viewport().get_camera_3d()
# DEBUG: Falls keine Kamera gefunden wird, wissen wir woran es liegt
if not camera:
print("Keine Kamera im Viewport von ", name, " gefunden!")
return Vector3.INF
var mouse_pos = get_viewport().get_mouse_position()
var ray_origin = camera.project_ray_origin(mouse_pos)
var ray_dir = camera.project_ray_normal(mouse_pos)
# Da wir in einer isolierten World3D sind, müssen wir den Physics-State
# des Viewports direkt abfragen, statt nur gegen eine Plane zu prüfen:
var space_state = get_world_3d().direct_space_state
var query = PhysicsRayQueryParameters3D.create(ray_origin, ray_origin + ray_dir * 1000)
# Falls du Layer nutzt: query.collision_mask = 1
var result = space_state.intersect_ray(query)
if result:
return result.position
# Fallback auf Plane, falls kein Mesh getroffen wurde
var world_plane = Plane(Vector3.UP, 0)
var intersection = world_plane.intersects_ray(ray_origin, ray_dir)
return intersection if intersection else Vector3.INF
func _process(_delta):
# Dieser Teil läuft auf dem Client (besonders dem, der die Authority hat)
if not multiplayer.is_server():
# Wir erzwingen die Position, die der Server berechnet hat
global_position = sync_position
rotation = sync_rotation

View file

@ -0,0 +1 @@
uid://bhym64rc7xtin

View file

@ -0,0 +1,13 @@
extends Control
@onready var ip_input: TextEdit = $IPInput
func _on_host_pressed():
print("host pressed")
GameEvents.host_requested.emit()
hide()
func _on_join_pressed():
print("join pressed")
GameEvents.join_requested.emit(ip_input.text)
hide()

View file

@ -0,0 +1 @@
uid://bp7b3a25eh6dh

View file

@ -0,0 +1,36 @@
[gd_scene format=3 uid="uid://bhywhrlwjox6t"]
[ext_resource type="Script" uid="uid://bp7b3a25eh6dh" path="res://ui/menus/main_menu.gd" id="1_5oih7"]
[node name="MainMenu" type="Control" unique_id=1694671237]
layout_mode = 3
anchors_preset = 0
script = ExtResource("1_5oih7")
[node name="IPInput" type="TextEdit" parent="." unique_id=1340335140]
custom_minimum_size = Vector2(150, 40)
layout_mode = 0
offset_left = 8.0
offset_top = 7.0
offset_right = 158.0
offset_bottom = 47.0
text = "127.0.0.1"
[node name="Join_Button" type="Button" parent="." unique_id=811892478]
layout_mode = 0
offset_left = 13.0
offset_top = 58.0
offset_right = 51.0
offset_bottom = 89.0
text = "Join"
[node name="Host_Button" type="Button" parent="." unique_id=1465654892]
layout_mode = 0
offset_left = 111.0
offset_top = 58.0
offset_right = 155.0
offset_bottom = 89.0
text = "Host"
[connection signal="button_up" from="Join_Button" to="." method="_on_join_pressed"]
[connection signal="button_up" from="Host_Button" to="." method="_on_host_pressed"]

View file

@ -0,0 +1,126 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Zauberturm Projekt-Log</title>
<style>
:root {
--bg-color: #0f111a;
--card-bg: #1a1d2e;
--accent-color: #7c4dff;
--text-color: #e0e0e0;
}
body {
background-color: var(--bg-color);
color: var(--text-color);
font-family: 'Segoe UI', sans-serif;
margin: 0;
display: flex;
flex-direction: column;
align-items: center;
min-height: 100vh;
}
header {
width: 100%;
padding: 3rem 0;
text-align: center;
background: linear-gradient(to bottom, #161b33, var(--bg-color));
border-bottom: 2px solid var(--accent-color);
}
.gallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
gap: 2rem;
width: 90%;
max-width: 1200px;
padding: 3rem 0;
}
.screenshot-card {
background: var(--card-bg);
border-radius: 12px;
overflow: hidden;
border: 1px solid rgba(255, 255, 255, 0.05);
transition: all 0.3s ease;
}
.screenshot-card:hover {
transform: translateY(-5px);
border-color: var(--accent-color);
box-shadow: 0 10px 20px rgba(0,0,0,0.5);
}
.screenshot-card img {
width: 100%;
height: 250px;
object-fit: cover;
display: block;
}
.info { padding: 1rem; text-align: center; border-top: 1px solid rgba(255,255,255,0.05); }
.info span { font-size: 0.85rem; color: #888; font-family: monospace; }
.info small { display: block; margin-top: 4px; color: #555; }
.empty-msg { grid-column: 1 / -1; text-align: center; padding: 5rem; color: #555; }
footer { margin-top: auto; padding: 2rem; color: #444; }
</style>
</head>
<body>
<header>
<h1>Zauberturm.de</h1>
<p>Projekt-Entwicklung: Screenshot Log</p>
</header>
<div class="gallery">
<?php
$log_dir = 'image_log';
$allowed_extensions = ['jpg', 'jpeg', 'png', 'webp'];
// Verzeichnis erstellen, falls es nicht existiert
if (!is_dir($log_dir)) {
mkdir($log_dir, 0755, true);
}
// Dateien im Unterordner scannen
$files = array_diff(scandir($log_dir), array('..', '.'));
if (count($files) > 0) {
// Sortieren: Neueste Dateien zuerst
usort($files, function($a, $b) use ($log_dir) {
return filemtime($log_dir . '/' . $b) - filemtime($log_dir . '/' . $a);
});
foreach ($files as $file) {
$file_path = $log_dir . '/' . $file;
$ext = strtolower(pathinfo($file, PATHINFO_EXTENSION));
if (in_array($ext, $allowed_extensions)) {
$date = date("d.m.Y H:i", filemtime($file_path));
echo "
<div class='screenshot-card'>
<a href='$file_path' target='_blank'>
<img src='$file_path' alt='Projekt Screenshot'>
</a>
<div class='info'>
<span>$file</span>
<small>$date</small>
</div>
</div>";
}
}
} else {
echo "<div class='empty-msg'>Keine Screenshots im Ordner /image_log/ gefunden.</div>";
}
?>
</div>
<footer>&copy; 2026 zauberturm.de</footer>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB