override public void Render(DwarfTime gameTime, ChunkManager chunks, Camera camera, SpriteBatch spriteBatch, GraphicsDevice graphicsDevice, Shader effect, bool renderingForWater) { base.Render(gameTime, chunks, camera, spriteBatch, graphicsDevice, effect, renderingForWater); if (Debugger.Switches.DrawRailNetwork) { DrawNeighborConnection(TrackAbove); DrawNeighborConnection(TrackBelow); } if (Primitive == null) { Primitive = new RawPrimitive(); var voxel = GetContainingVoxel(); AddSideQuad(voxel, new GlobalVoxelOffset(1, 0, 0), (float)Math.PI * 0.5f, new Vector3(0.45f, 0.0f, 0.0f)); AddSideQuad(voxel, new GlobalVoxelOffset(0, 0, 1), 0.0f, new Vector3(0.0f, 0.0f, 0.45f)); AddSideQuad(voxel, new GlobalVoxelOffset(-1, 0, 0), (float)Math.PI * 0.5f, new Vector3(-0.45f, 0.0f, 0.0f)); AddSideQuad(voxel, new GlobalVoxelOffset(0, 0, -1), 0.0f, new Vector3(0.0f, 0.0f, -0.45f)); } if (Primitive.VertexCount == 0) { return; } var under = new VoxelHandle(chunks, GlobalVoxelCoordinate.FromVector3(Position)); if (under.IsValid) { Color color = new Color(under.Sunlight ? 255 : 0, 255, 0); LightRamp = color; } else { LightRamp = new Color(200, 255, 0); } Color origTint = effect.VertexColorTint; if (!Active) { DoStipple(effect); } effect.VertexColorTint = VertexColor; effect.LightRamp = LightRamp; effect.World = GlobalTransform; effect.MainTexture = Sheet.GetTexture(); effect.EnableWind = false; foreach (EffectPass pass in effect.CurrentTechnique.Passes) { pass.Apply(); Primitive.Render(graphicsDevice); } effect.VertexColorTint = origTint; if (!Active && !String.IsNullOrEmpty(previousEffect)) { effect.CurrentTechnique = effect.Techniques[previousEffect]; } }
public override void Construct() { AutoSizeColumns = true; IsRootTray = true; ItemSource = new Gui.Widget[] { new HorizontalMenuTray.MenuItem { Text = "CHEAT MODE", }, new HorizontalMenuTray.MenuItem { Text = "DEBUG", ExpansionChild = new HorizontalMenuTray.Tray { ItemSize = new Point(200, 20), ItemSource = Debugger.EnumerateSwitches().Select(s => new HorizontalMenuTray.CheckboxMenuItem { Text = Debugger.GetNicelyFormattedName(s.Name), InitialState = s.State, SetCallback = s.Set }) } }, new HorizontalMenuTray.MenuItem { Text = "DEBUG SAVE", OnClick = (sender, args) => { // Turn off binary compressed saves and save a nice straight json save for debugging purposes. // Todo: Why isn't World managing this paused state itself? bool paused = Master.World.Paused; var previousSetting = DwarfGame.COMPRESSED_BINARY_SAVES; DwarfGame.COMPRESSED_BINARY_SAVES = false; Master.World.Save( String.Format("{0}_{1}_DEBUG", Overworld.Name, Master.World.GameID), (success, exception) => { Master.World.MakeAnnouncement(success ? "Debug save created.": "Debug save failed - " + exception.Message); DwarfGame.COMPRESSED_BINARY_SAVES = previousSetting; Master.World.Paused = paused; }); } }, new HorizontalMenuTray.MenuItem { Text = "BUILD", ExpansionChild = new HorizontalMenuTray.Tray { ItemSource = RoomLibrary.GetRoomTypes().Select(r => new HorizontalMenuTray.MenuItem { Text = r, OnClick = (sender, args) => ActivateGodTool("Build/" + r) }) } }, new HorizontalMenuTray.MenuItem { Text = "SPAWN", ExpansionChild = new HorizontalMenuTray.Tray { Columns = 5, ItemSource = EntityFactory.EnumerateEntityTypes().Where(s => !s.Contains("Resource") || !ResourceLibrary.GetResourceByName(s.Substring(0, s.Length - " Resource".Length)).Generated).OrderBy(s => s).Select(s => new HorizontalMenuTray.MenuItem { Text = s, OnClick = (sender, args) => ActivateGodTool("Spawn/" + s) }) } }, new HorizontalMenuTray.MenuItem { Text = "PLACE BLOCK", ExpansionChild = new HorizontalMenuTray.Tray { Columns = 3, ItemSource = VoxelLibrary.GetTypes() .Where(t => t.Name != "_empty" && t.Name != "water") .OrderBy(s => s.Name) .Select(s => new HorizontalMenuTray.MenuItem { Text = s.Name, OnClick = (sender, args) => ActivateGodTool("Place/" + s.Name) }) } }, new HorizontalMenuTray.MenuItem { Text = "DELETE BLOCK", OnClick = (sender, args) => ActivateGodTool("Delete Block") }, new HorizontalMenuTray.MenuItem { Text = "KILL BLOCK", OnClick = (sender, args) => ActivateGodTool("Kill Block") }, new HorizontalMenuTray.MenuItem { Text = "PLACE GRASS", ExpansionChild = new HorizontalMenuTray.Tray { Columns = 3, ItemSource = GrassLibrary.TypeList .OrderBy(s => s.Name) .Select(s => new HorizontalMenuTray.MenuItem { Text = s.Name, OnClick = (sender, args) => ActivateGodTool("Grass/" + s.Name) }) } }, //new HorizontalMenuTray.MenuItem //{ // Text = "PLACE DECAL", // ExpansionChild = new HorizontalMenuTray.Tray // { // Columns = 3, // ItemSource = DecalLibrary.TypeList // .OrderBy(s => s.Name) // .Select(s => // new HorizontalMenuTray.MenuItem // { // Text = s.Name, // OnClick = (sender, args) => ActivateGodTool("Decal/" + s.Name) // }) // } //}, new HorizontalMenuTray.MenuItem { Text = "PLACE RAIL", ExpansionChild = new HorizontalMenuTray.Tray { Columns = 1, ItemSource = new HorizontalMenuTray.MenuItem[] { new HorizontalMenuTray.MenuItem { Text = "RAW PIECES", ExpansionChild = new HorizontalMenuTray.Tray { Columns = 2, ItemSize = new Point(200, 20), ItemSource = Rail.RailLibrary.EnumeratePieces().Select(p => new HorizontalMenuTray.MenuItem { Text = p.Name, OnClick = (sender, args) => ActivateGodTool("Rail/" + p.Name) }) } }, new HorizontalMenuTray.MenuItem { Text = "USING PATTERNS", ExpansionChild = new HorizontalMenuTray.Tray { Columns = 1, ItemSource = Rail.RailLibrary.EnumeratePatterns().Select(p => new HorizontalMenuTray.MenuItem { Text = p.Name, OnClick = (sender, args) => { var railTool = Master.Tools[GameMaster.ToolMode.BuildRail] as Rail.BuildRailTool; railTool.Pattern = p; Master.ChangeTool(GameMaster.ToolMode.BuildRail); railTool.GodModeSwitch = true; } }) } }, new HorizontalMenuTray.MenuItem { Text = "PAINT", OnClick = (sender, args) => { var railTool = Master.Tools[GameMaster.ToolMode.PaintRail] as Rail.PaintRailTool; railTool.SelectedResources = new List <ResourceAmount>(new ResourceAmount[] { new ResourceAmount("Rail", 1) }); Master.ChangeTool(GameMaster.ToolMode.PaintRail); railTool.GodModeSwitch = true; } } } } }, new HorizontalMenuTray.MenuItem { Text = "KILL THINGS", OnClick = (sender, args) => ActivateGodTool("Kill Things") }, new HorizontalMenuTray.MenuItem { Text = "TRAILER", ExpansionChild = new HorizontalMenuTray.Tray { ItemSource = new List <HorizontalMenuTray.MenuItem>() { new HorizontalMenuTray.MenuItem { Text = "SPIN +", OnClick = (sender, args) => this.Master.World.Camera.Trailer(Vector3.Zero, 2.0f, 0.0f), }, new HorizontalMenuTray.MenuItem { Text = "SPIN -", OnClick = (sender, args) => this.Master.World.Camera.Trailer(Vector3.Zero, -2.0f, 0.0f), }, new HorizontalMenuTray.MenuItem { Text = "ZOOM -", OnClick = (sender, args) => this.Master.World.Camera.Trailer(Vector3.Zero, 0.0f, 2.5f), }, new HorizontalMenuTray.MenuItem { Text = "ZOOM +", OnClick = (sender, args) => this.Master.World.Camera.Trailer(Vector3.Zero, 0.0f, -2.5f), }, new HorizontalMenuTray.MenuItem { Text = "FWD", OnClick = (sender, args) => this.Master.World.Camera.Trailer(Vector3.Forward * 5, 0.0f, 0.0f), }, new HorizontalMenuTray.MenuItem { Text = "BACK", OnClick = (sender, args) => this.Master.World.Camera.Trailer(Vector3.Backward * 5, 0.0f, 0.0f), }, new HorizontalMenuTray.MenuItem { Text = "LEFT", OnClick = (sender, args) => this.Master.World.Camera.Trailer(Vector3.Left * 5, 0.0f, 0.0f), }, new HorizontalMenuTray.MenuItem { Text = "RIGHT", OnClick = (sender, args) => this.Master.World.Camera.Trailer(Vector3.Right * 5, 0.0f, 0.0f), }, } } }, new HorizontalMenuTray.MenuItem { Text = "FILL WATER", OnClick = (sender, args) => ActivateGodTool("Fill Water") }, new HorizontalMenuTray.MenuItem { Text = "FILL LAVA", OnClick = (sender, args) => ActivateGodTool("Fill Lava") }, new HorizontalMenuTray.MenuItem { Text = "TRADE ENVOY", ExpansionChild = new HorizontalMenuTray.Tray { ItemSource = Master.World.Factions.Factions.Values.Where(f => f.Race.IsIntelligent && f != Master.Faction).Select(s => { return(new HorizontalMenuTray.MenuItem { Text = s.Name, OnClick = (sender, args) => Master.World.Diplomacy.SendTradeEnvoy(s, Master.World) }); }), } }, new HorizontalMenuTray.MenuItem { Text = "EVENT", ExpansionChild = new HorizontalMenuTray.Tray { ItemSource = Master.World.GoalManager.EventScheduler.Events.Events.Select(e => { return(new HorizontalMenuTray.MenuItem { Text = e.Name, OnClick = (sender, args) => Master.World.GoalManager.EventScheduler.ActivateEvent(Master.World, e) }); }), } }, new HorizontalMenuTray.MenuItem { Text = "WAR PARTY", ExpansionChild = new HorizontalMenuTray.Tray { ItemSource = Master.World.Factions.Factions.Values.Where(f => f.Race.IsIntelligent && f != Master.Faction).Select(s => { return(new HorizontalMenuTray.MenuItem { Text = s.Name, OnClick = (sender, args) => Master.World.Diplomacy.SendWarParty(s) }); }), } }, new HorizontalMenuTray.MenuItem { Text = "DWARF BUX", OnClick = (sender, args) => Master.Faction.AddMoney(100m) }, new HorizontalMenuTray.MenuItem { Text = "MINIONS", ExpansionChild = new HorizontalMenuTray.Tray { ItemSource = new HorizontalMenuTray.MenuItem[] { new HorizontalMenuTray.MenuItem { Text = "PAY", OnClick = (sender, args) => Master.PayEmployees() }, new HorizontalMenuTray.MenuItem { Text = "STARVE", OnClick = (sender, args) => { foreach (var minion in Master.Faction.Minions) { minion.Status.Hunger.CurrentValue = 0; } } }, new HorizontalMenuTray.MenuItem { Text = "XP", OnClick = (sender, args) => { foreach (var minion in Master.Faction.Minions) { minion.AddXP(100); } } }, new HorizontalMenuTray.MenuItem { Text = "DISEASE", OnClick = (sender, args) => ActivateGodTool("Disease") }, new HorizontalMenuTray.MenuItem { Text = "HAPPY", OnClick = (sender, args) => { foreach (var minion in Master.Faction.Minions) { var thoughts = minion.GetRoot().GetComponent <DwarfThoughts>(); if (thoughts != null) { thoughts.AddThought(Thought.ThoughtType.CheatedHappy); } } } }, new HorizontalMenuTray.MenuItem { Text = "PISSED", OnClick = (sender, args) => { foreach (var minion in Master.Faction.Minions) { var thoughts = minion.GetRoot().GetComponent <DwarfThoughts>(); if (thoughts != null) { thoughts.AddThought(Thought.ThoughtType.CheatedPissed); } } } }, new HorizontalMenuTray.MenuItem { Text = "GAMBLE", OnClick = (sender, args) => { foreach (var employee in Master.Faction.Minions) { employee.AssignTask(new Scripting.GambleTask() { Priority = Task.PriorityType.High }); } } }, new HorizontalMenuTray.MenuItem { Text = "PASS OUT", OnClick = (sender, args) => { var employee = Datastructures.SelectRandom(Master.Faction.Minions); if (employee != null) { employee.Creature.Heal(-employee.Status.Health.CurrentValue * employee.Creature.MaxHealth + 1); } } } } } }, new HorizontalMenuTray.MenuItem { Text = "SPAWN TEST", OnClick = (sender, args) => { // Copy is required because spawning some types results in the creation of new types. EG, snakes create snake meat. var keys = EntityFactory.EnumerateEntityTypes().ToList(); int num = keys.Count(); float gridSize = (float)Math.Ceiling(Math.Sqrt((double)num)); Vector3 gridCenter = Master.World.CursorLightPos; int i = 0; for (float dx = -gridSize / 2; dx <= gridSize / 2; dx++) { for (float dz = -gridSize / 2; dz <= gridSize / 2; dz++) { if (i >= num) { continue; } Vector3 pos = MathFunctions.Clamp(gridCenter + new Vector3(dx, VoxelConstants.ChunkSizeY, dz), Master.World.ChunkManager.Bounds); VoxelHandle handle = VoxelHelpers.FindFirstVisibleVoxelOnRay(Master.World.ChunkManager.ChunkData, pos, pos + Vector3.Down * 100); if (handle.IsValid) { EntityFactory.CreateEntity <GameComponent>(keys[i], handle.WorldPosition + Vector3.Up); } i++; } } } }, new HorizontalMenuTray.MenuItem { Text = "SPAWN CRAFTS", OnClick = (sender, args) => { // Copy is required because spawning some types results in the creation of new types. EG, snakes create snake meat. var itemTypes = CraftLibrary.EnumerateCraftables().Where(craft => craft.Type == CraftItem.CraftType.Object).ToList(); int num = itemTypes.Count(); float gridSize = (float)Math.Ceiling(Math.Sqrt((double)num)); Vector3 gridCenter = Master.World.CursorLightPos; int i = 0; for (float dx = -gridSize / 2; dx <= gridSize / 2; dx++) { for (float dz = -gridSize / 2; dz <= gridSize / 2; dz++) { if (i < num) { var item = itemTypes[i]; if (item.Name != "Explosive") { Vector3 pos = MathFunctions.Clamp(gridCenter + new Vector3(dx, VoxelConstants.ChunkSizeY, dz), Master.World.ChunkManager.Bounds); VoxelHandle handle = VoxelHelpers.FindFirstVisibleVoxelOnRay(Master.World.ChunkManager.ChunkData, pos, pos + Vector3.Down * 100); if (handle.IsValid) { var blackboard = new Blackboard(); List <ResourceAmount> resources = item.RequiredResources.Select(r => new ResourceAmount(ResourceLibrary.GetResourcesByTag(r.ResourceType).First(), r.NumResources)).ToList(); blackboard.SetData <List <ResourceAmount> >("Resources", resources); blackboard.SetData <string>("CraftType", item.Name); var entity = EntityFactory.CreateEntity <GameComponent>(item.EntityName, handle.WorldPosition + Vector3.Up + item.SpawnOffset, blackboard); if (entity != null) { if (item.AddToOwnedPool) { Master.Faction.OwnedObjects.Add(entity as Body); } if (item.Moveable) { entity.Tags.Add("Moveable"); } if (item.Deconstructable) { entity.Tags.Add("Deconstructable"); } } } } } i++; } } } }, new HorizontalMenuTray.MenuItem { Text = "+1 HOUR", OnClick = (sender, args) => { Master.World.Time.CurrentDate += new TimeSpan(1, 0, 0); } }, new HorizontalMenuTray.MenuItem { Text = "FORCE REBUILD", OnClick = (sender, args) => { foreach (var chunk in Master.World.ChunkManager.ChunkData.ChunkMap) { for (int Y = 0; Y < VoxelConstants.ChunkSizeY; ++Y) { chunk.InvalidateSlice(Y); } } } }, new HorizontalMenuTray.MenuItem { Text = "REPULSE", OnClick = (sender, args) => ActivateGodTool("Repulse") }, new HorizontalMenuTray.MenuItem { Text = "SLOWMO", OnClick = (sender, args) => GameSettings.Default.EnableSlowMotion = !GameSettings.Default.EnableSlowMotion }, new HorizontalMenuTray.MenuItem { Text = "LET IT SNOW", OnClick = (sender, args) => { var storm = Weather.CreateStorm(Vector3.One, 100.0f, Master.World); storm.TypeofStorm = StormType.SnowStorm; storm.Start(); } } }; base.Construct(); }
public static void GenerateCaves(VoxelChunk Chunk, ChunkGeneratorSettings Settings) { if (Library.GetBiome("Cave").HasValue(out BiomeData caveBiome) && Library.GetBiome("Hell").HasValue(out BiomeData hellBiome)) { for (int x = 0; x < VoxelConstants.ChunkSizeX; x++) { for (int z = 0; z < VoxelConstants.ChunkSizeZ; z++) { for (int i = 0; i < Settings.CaveLevels.Count; i++) { // Does layer intersect this voxel? int y = Settings.CaveLevels[i]; if (y + Settings.MaxCaveHeight < Chunk.Origin.Y) { continue; } if (y >= Chunk.Origin.Y + VoxelConstants.ChunkSizeY) { continue; } var coordinate = new GlobalVoxelCoordinate(Chunk.Origin.X + x, y, Chunk.Origin.Z + z); var data = GetCaveGenerationData(coordinate, i, Settings); var biome = (y <= Settings.HellLevel) ? hellBiome : caveBiome; if (!data.CaveHere) { continue; } for (int dy = 0; dy < data.Height; dy++) { var globalY = y + dy; // Prevent caves punching holes in bedrock. if (globalY <= 0) { continue; } // Check if voxel is inside chunk. if (globalY <= 0 || globalY < Chunk.Origin.Y || globalY >= Chunk.Origin.Y + VoxelConstants.ChunkSizeY) { continue; } var voxel = VoxelHandle.UnsafeCreateLocalHandle(Chunk, new LocalVoxelCoordinate(x, globalY - Chunk.Origin.Y, z)); // Prevent caves from breaking surface. bool caveBreaksSurface = false; foreach (var neighborCoordinate in VoxelHelpers.EnumerateAllNeighbors(voxel.Coordinate)) { var v = Chunk.Manager.CreateVoxelHandle(neighborCoordinate); if (!v.IsValid || (v.Sunlight)) { caveBreaksSurface = true; break; } } if (caveBreaksSurface) { break; } voxel.RawSetType(Library.EmptyVoxelType); if (dy == 0) { // Place soil voxel and grass below cave. var below = VoxelHelpers.GetVoxelBelow(voxel); if (below.IsValid) { below.RawSetType(Library.GetVoxelType(biome.SoilLayer.VoxelType)); var grassType = Library.GetGrassType(biome.GrassDecal); if (grassType != null) { below.RawSetGrass(grassType.ID); } } // Spawn flora and fauna. if (data.Noise > Settings.CaveSize * 1.8f && globalY > Settings.LavaLevel) { GenerateCaveFlora(below, biome, Settings); GenerateCaveFauna(below, biome, Settings); } } } } } } } }
public static VoxelChunk GenerateChunk(GlobalChunkCoordinate ID, ChunkGeneratorSettings Settings) { var origin = new GlobalVoxelCoordinate(ID, new LocalVoxelCoordinate(0, 0, 0)); var worldDepth = Settings.WorldSizeInChunks.Y * VoxelConstants.ChunkSizeY; var waterHeight = NormalizeHeight(Settings.Overworld.GenerationSettings.SeaLevel + 1.0f / worldDepth); var c = new VoxelChunk(Settings.World.ChunkManager, ID); for (int x = 0; x < VoxelConstants.ChunkSizeX; x++) { for (int z = 0; z < VoxelConstants.ChunkSizeZ; z++) { var overworldPosition = OverworldMap.WorldToOverworld(new Vector2(x + origin.X, z + origin.Z), Settings.Overworld.InstanceSettings.Origin); var biomeData = Settings.Overworld.Map.GetBiomeAt(new Vector3(x + origin.X, 0, z + origin.Z), Settings.Overworld.InstanceSettings.Origin); var normalizedHeight = NormalizeHeight(Settings.Overworld.Map.LinearInterpolate(overworldPosition, OverworldField.Height)); var height = MathFunctions.Clamp(normalizedHeight * worldDepth, 0.0f, worldDepth - 2); var stoneHeight = (int)MathFunctions.Clamp((int)(height - (biomeData.SoilLayer.Depth + (Math.Sin(overworldPosition.X) + Math.Cos(overworldPosition.Y)))), 1, height); for (int y = 0; y < VoxelConstants.ChunkSizeY; y++) { var globalY = origin.Y + y; var voxel = VoxelHandle.UnsafeCreateLocalHandle(c, new LocalVoxelCoordinate(x, y, z)); if (globalY == 0) { voxel.RawSetType(Library.GetVoxelType("Bedrock")); continue; } // Below the stone line, use subsurface layers. if (globalY <= stoneHeight && stoneHeight > 1) { var depth = stoneHeight - globalY; var subsurfaceLayer = 0; while (depth > 0 && subsurfaceLayer < biomeData.SubsurfaceLayers.Count - 1) { depth -= biomeData.SubsurfaceLayers[subsurfaceLayer].Depth; subsurfaceLayer += 1; } voxel.RawSetType(Library.GetVoxelType(biomeData.SubsurfaceLayers[subsurfaceLayer].VoxelType)); } // Otherwise, on the surface. else if ((globalY == (int)height || globalY == stoneHeight) && normalizedHeight > waterHeight) { voxel.RawSetType(Library.GetVoxelType(biomeData.SoilLayer.VoxelType)); if (!String.IsNullOrEmpty(biomeData.GrassDecal)) { if (!biomeData.ClumpGrass || (biomeData.ClumpGrass && Settings.NoiseGenerator.Noise(overworldPosition.X / biomeData.ClumpSize, 0, overworldPosition.Y / biomeData.ClumpSize) > biomeData.ClumpTreshold)) { voxel.RawSetGrass(Library.GetGrassType(biomeData.GrassDecal).ID); } } } else if (globalY > height && globalY > 0) { voxel.RawSetType(Library.EmptyVoxelType); } else if (normalizedHeight <= waterHeight) { voxel.RawSetType(Library.GetVoxelType(biomeData.ShoreVoxel)); } else { voxel.RawSetType(Library.GetVoxelType(biomeData.SoilLayer.VoxelType)); } } } } return(c); }
override public void Render(DwarfTime gameTime, ChunkManager chunks, Camera camera, SpriteBatch spriteBatch, GraphicsDevice graphicsDevice, Shader effect, bool renderingForWater) { base.Render(gameTime, chunks, camera, spriteBatch, graphicsDevice, effect, renderingForWater); if (Debugger.Switches.DrawRailNetwork) { //Drawer3D.DrawBox(GetContainingVoxel().GetBoundingBox(), Color.White, 0.01f, true); //Drawer3D.DrawLine(GetContainingVoxel().GetBoundingBox().Center(), GlobalTransform.Translation, Color.White, 0.01f); var transform = Matrix.CreateRotationY((float)Math.PI * 0.5f * (float)Piece.Orientation) * GlobalTransform; if (Library.GetRailPiece(Piece.RailPiece).HasValue(out var piece)) { foreach (var spline in piece.SplinePoints) { for (var i = 1; i < spline.Count; ++i) { Drawer3D.DrawLine(Vector3.Transform(spline[i - 1], transform), Vector3.Transform(spline[i], transform), Color.Purple, 0.1f); } } foreach (var connection in piece.EnumerateConnections()) { Drawer3D.DrawLine(Vector3.Transform(connection.Item1, transform) + new Vector3(0.0f, 0.2f, 0.0f), Vector3.Transform(connection.Item2, transform) + new Vector3(0.0f, 0.2f, 0.0f), Color.Brown, 0.1f); } //foreach (var neighborConnection in NeighborRails) //{ // var neighbor = Manager.FindComponent(neighborConnection.NeighborID); // if (neighbor == null) // Drawer3D.DrawLine(Position, Position + Vector3.UnitY, Color.CornflowerBlue, 0.1f); // else // Drawer3D.DrawLine(Position + new Vector3(0.0f, 0.5f, 0.0f), (neighbor as Body).Position + new Vector3(0.0f, 0.5f, 0.0f), Color.Teal, 0.1f); //} } } if (!IsVisible) { return; } if (Primitive == null) { var bounds = Vector4.Zero; var uvs = Sheet.GenerateTileUVs(Frame, out bounds); if (Library.GetRailPiece(Piece.RailPiece).HasValue(out var rawPiece)) { var transform = Matrix.CreateRotationY((float)Math.PI * 0.5f * (float)Piece.Orientation); var realShape = 0; if (rawPiece.AutoSlope) { var transformedConnections = GetTransformedConnections(); var matchingNeighbor1 = NeighborRails.FirstOrDefault(n => (n.Position - transformedConnections[0].Item1 - new Vector3(0.0f, 1.0f, 0.0f)).LengthSquared() < 0.001f); var matchingNeighbor2 = NeighborRails.FirstOrDefault(n => (n.Position - transformedConnections[1].Item1 - new Vector3(0.0f, 1.0f, 0.0f)).LengthSquared() < 0.001f); if (matchingNeighbor1 != null && matchingNeighbor2 != null) { realShape = 3; } else if (matchingNeighbor1 != null) { realShape = 1; } else if (matchingNeighbor2 != null) { realShape = 2; } } Primitive = new RawPrimitive(); Primitive.AddVertex(new ExtendedVertex(Vector3.Transform(new Vector3(-0.5f, VertexHeightOffsets[realShape, 0], 0.5f), transform), Color.White, Color.White, uvs[0], bounds)); Primitive.AddVertex(new ExtendedVertex(Vector3.Transform(new Vector3(0.5f, VertexHeightOffsets[realShape, 1], 0.5f), transform), Color.White, Color.White, uvs[1], bounds)); Primitive.AddVertex(new ExtendedVertex(Vector3.Transform(new Vector3(0.5f, VertexHeightOffsets[realShape, 2], -0.5f), transform), Color.White, Color.White, uvs[2], bounds)); Primitive.AddVertex(new ExtendedVertex(Vector3.Transform(new Vector3(-0.5f, VertexHeightOffsets[realShape, 3], -0.5f), transform), Color.White, Color.White, uvs[3], bounds)); Primitive.AddIndicies(new short[] { 0, 1, 3, 1, 2, 3 }); var sideBounds = Vector4.Zero; Vector2[] sideUvs = null; sideUvs = Sheet.GenerateTileUVs(new Point(3, 4), out sideBounds); AddScaffoldGeometry(transform, sideBounds, sideUvs, -1.0f, false); if (realShape == 3) { AddScaffoldGeometry(transform, sideBounds, sideUvs, 0.0f, false); } else if (realShape == 1) { sideUvs = Sheet.GenerateTileUVs(new Point(0, 4), out sideBounds); AddScaffoldGeometry(transform, sideBounds, sideUvs, 0.0f, true); } else if (realShape == 2) { sideUvs = Sheet.GenerateTileUVs(new Point(0, 4), out sideBounds); AddScaffoldGeometry(transform, sideBounds, sideUvs, 0.0f, false); } // Todo: Make these static and avoid recalculating them constantly. var bumperBackBounds = Vector4.Zero; var bumperBackUvs = Sheet.GenerateTileUVs(new Point(0, 5), out bumperBackBounds); var bumperFrontBounds = Vector4.Zero; var bumperFrontUvs = Sheet.GenerateTileUVs(new Point(1, 5), out bumperFrontBounds); var bumperSideBounds = Vector4.Zero; var bumperSideUvs = Sheet.GenerateTileUVs(new Point(2, 5), out bumperSideBounds); foreach (var connection in GetTransformedConnections()) { var matchingNeighbor = NeighborRails.FirstOrDefault(n => (n.Position - connection.Item1).LengthSquared() < 0.001f); if (matchingNeighbor == null && rawPiece.AutoSlope) { matchingNeighbor = NeighborRails.FirstOrDefault(n => (n.Position - connection.Item1 - new Vector3(0.0f, 1.0f, 0.0f)).LengthSquared() < 0.001f); } if (matchingNeighbor == null) { var bumperOffset = connection.Item1 - GlobalTransform.Translation; var bumperGap = Vector3.Normalize(bumperOffset) * 0.1f; var bumperAngle = AngleBetweenVectors(new Vector2(bumperOffset.X, bumperOffset.Z), new Vector2(0, 0.5f)); var xDiag = bumperOffset.X <-0.001f || bumperOffset.X> 0.001f; var zDiag = bumperOffset.Z <-0.001f || bumperOffset.Z> 0.001f; if (xDiag && zDiag) { var y = bumperOffset.Y; bumperOffset *= sqrt2; bumperOffset.Y = y; var endBounds = Vector4.Zero; var endUvs = Sheet.GenerateTileUVs(new Point(6, 2), out endBounds); Primitive.AddQuad( Matrix.CreateRotationY((float)Math.PI * 1.25f) * Matrix.CreateRotationY(bumperAngle) // This offset would not be correct if diagonals could slope. * Matrix.CreateTranslation(new Vector3(Sign(bumperOffset.X), 0.0f, Sign(bumperOffset.Z))), Color.White, Color.White, endUvs, endBounds); } Primitive.AddQuad( Matrix.CreateRotationX(-(float)Math.PI * 0.5f) * Matrix.CreateTranslation(0.0f, 0.3f, -0.2f) * Matrix.CreateRotationY(bumperAngle) * Matrix.CreateTranslation(bumperOffset + bumperGap), Color.White, Color.White, bumperBackUvs, bumperBackBounds); Primitive.AddQuad( Matrix.CreateRotationX(-(float)Math.PI * 0.5f) * Matrix.CreateTranslation(0.0f, 0.3f, -0.2f) * Matrix.CreateRotationY(bumperAngle) * Matrix.CreateTranslation(bumperOffset), Color.White, Color.White, bumperFrontUvs, bumperFrontBounds); var firstVoxelBelow = VoxelHelpers.FindFirstVoxelBelow(GetContainingVoxel()); if (firstVoxelBelow.IsValid && firstVoxelBelow.RampType == RampType.None) // if (VoxelHelpers.FindFirstVoxelBelow(GetContainingVoxel()).RampType == RampType.None) { Primitive.AddQuad( Matrix.CreateRotationX(-(float)Math.PI * 0.5f) * Matrix.CreateRotationY(-(float)Math.PI * 0.5f) * Matrix.CreateTranslation(0.3f, 0.3f, 0.18f) * Matrix.CreateRotationY(bumperAngle) * Matrix.CreateTranslation(bumperOffset), Color.White, Color.White, bumperSideUvs, bumperSideBounds); Primitive.AddQuad( Matrix.CreateRotationX(-(float)Math.PI * 0.5f) * Matrix.CreateRotationY(-(float)Math.PI * 0.5f) * Matrix.CreateTranslation(-0.3f, 0.3f, 0.18f) * Matrix.CreateRotationY(bumperAngle) * Matrix.CreateTranslation(bumperOffset), Color.White, Color.White, bumperSideUvs, bumperSideBounds); } } } } } // Everything that draws should set it's tint, making this pointless. var under = new VoxelHandle(chunks, GlobalVoxelCoordinate.FromVector3(Position)); if (under.IsValid) { Color color = new Color(under.Sunlight ? 255 : 0, 255, 0); LightRamp = color; } else { LightRamp = new Color(200, 255, 0); } Color origTint = effect.VertexColorTint; if (!Active) { DoStipple(effect); } effect.VertexColorTint = VertexColor; effect.LightRamp = LightRamp; effect.World = GlobalTransform; effect.MainTexture = Sheet.GetTexture(); effect.EnableWind = false; foreach (EffectPass pass in effect.CurrentTechnique.Passes) { pass.Apply(); Primitive.Render(graphicsDevice); } effect.VertexColorTint = origTint; if (!Active) { EndDraw(effect); } }