using Godot; using System; using System.Collections.Generic; using System.Linq; using static GameData; public partial class World : Node3D { public Dictionary tileMeshes; public Dictionary decorationMeshes; public Dictionary> tilePlaceholders; PackedScene layerPrefab = ResourceLoader.LoadLayerPrefab(); private Dictionary multiMeshes = new(); private Dictionary meshLibrary = new(); Layer[] map; Layer layerNode; // Called when the node enters the scene tree for the first time. public override void _Ready() { WFC.FillAdjacencies(); tileMeshes = ResourceLoader.LoadTiles(); decorationMeshes = ResourceLoader.LoadDecorations(); tilePlaceholders = new Dictionary>(); foreach (var kvp in tileMeshes) { tilePlaceholders.Add(kvp.Key, new List()); foreach (MeshInstance3D child in kvp.Value.GetChildren()) { tilePlaceholders[kvp.Key].Add(new Placeholder(child.Name, child.Transform.Origin)); } var temp = kvp.Value; meshLibrary[kvp.Key] = temp.Mesh; temp.QueueFree(); } foreach (var kvp in meshLibrary) { var mm = new MultiMesh(); mm.Mesh = kvp.Value; mm.TransformFormat = MultiMesh.TransformFormatEnum.Transform3D; var instance = new MultiMeshInstance3D(); instance.Multimesh = mm; AddChild(instance); multiMeshes[kvp.Key] = instance; } map = new Layer[ruinSize]; GenerateWorld(); GD.Print("World generated"); BuildMeshesForLayer(0); } // Called every frame. 'delta' is the elapsed time since the previous frame. public override void _Process(double delta) { if (Input.IsActionJustPressed("layer_up") && currentLayer > 0) currentLayer--; if (Input.IsActionJustPressed("layer_down") && currentLayer < ruinSize - 1) currentLayer++; if (currentLayer != visibleLayer) { BuildMeshesForLayer(currentLayer); visibleLayer = currentLayer; } } private void GenerateWorld() { DateTime now = DateTime.Now; for (int layer = 0; layer < ruinSize; layer++) { layerNode = layerPrefab.Instantiate(); AddChild(layerNode); layerNode.SetupLayer(layerSize, layer, tileMeshes); map[layer] = layerNode; } GD.Print("Time for map generation: " + (DateTime.Now - now).Seconds); } private void BuildMeshesForLayer(int layerIndex) { foreach (MultiMeshInstance3D mm in multiMeshes.Values) { mm.Multimesh.InstanceCount = 0; } Layer layer = map[layerIndex]; Dictionary> batches = new(); for (int x = 0; x < layerSize; x++) { for (int y = 0; y < layerSize; y++) { Tile tile = layer.tiles[x, y]; string key = tile.collapsedMesh; if (!batches.ContainsKey(key)) batches[key] = new List(); batches[key].Add(new Transform3D( Basis.Identity, tile.Position )); } } foreach (var kvp in batches) { MultiMesh mm = multiMeshes[kvp.Key].Multimesh; List placeholders = tilePlaceholders[kvp.Key]; List list = kvp.Value; mm.InstanceCount = list.Count; for (int i = 0; i < list.Count; i++) { mm.SetInstanceTransform(i, list[i]); if (placeholders.Count > 0) { Node3D decoration; Mesh mesh = decorationMeshes.Values.ToList()[0].Mesh; for(int j = 0; j < placeholders.Count; j++) { foreach (MeshInstance3D meshes in decorationMeshes.Values) { if (meshes.Name.ToString().ToLower() == placeholders[j].name.ToLower()) { mesh = meshes.Mesh; break; } } decoration = new MeshInstance3D(); (decoration as MeshInstance3D).Mesh = mesh; if (placeholders[j].name.ToLower() == "light") { GD.Print("Adding OmniLight"); decoration.AddChild(new OmniLight3D() { OmniAttenuation = 2f, LightColor = new Color("#eae7ad"), ShadowEnabled = true, LightEnergy = 5f, LightIndirectEnergy = 1.5f, Position = new Vector3(0.5f, 0, 0) }); } decoration.Transform = list[i]; decoration.Position += placeholders[j].pos; decoration.Name = placeholders[j].name + j; decoration.Rotate(Vector3.Up, Mathf.DegToRad(-90)); layer.AddChild(decoration); } } } } } }