v1.7.7.0 (Winter Update 2024)

This commit is contained in:
Regalis11
2024-12-11 13:26:13 +02:00
parent 7d5b7a310a
commit f6349b2175
256 changed files with 4794 additions and 1653 deletions
@@ -96,9 +96,13 @@ namespace Barotrauma
new Vector2(Math.Sign(targetHull.Rect.Center.X - rect.Center.X), 0.0f)
: new Vector2(0.0f, Math.Sign((rect.Y - rect.Height / 2.0f) - (targetHull.Rect.Y - targetHull.Rect.Height / 2.0f)));
Vector2 arrowPos = new Vector2(WorldRect.Center.X, -(WorldRect.Y - WorldRect.Height / 2));
Vector2 arrowPos = new Vector2(WorldRect.Center.X, WorldRect.Y - WorldRect.Height / 2);
if (Submarine != null)
{
arrowPos += (Submarine.DrawPosition - Submarine.Position);
}
arrowPos.Y = -arrowPos.Y;
arrowPos += new Vector2(dir.X * (WorldRect.Width / 2), dir.Y * (WorldRect.Height / 2));
bool invalidDir = false;
if (dir == Vector2.Zero)
{
@@ -404,8 +404,8 @@ namespace Barotrauma
//GUI.DrawRectangle(spriteBatch, new Rectangle((int)fs.LastExtinguishPos.X, (int)-fs.LastExtinguishPos.Y, 5,5), Color.Yellow, true);
}
GUI.DrawLine(spriteBatch, new Vector2(drawRect.X, -WorldSurface), new Vector2(drawRect.Right, -WorldSurface), Color.Cyan * 0.5f);
float worldSurface = surface + Submarine.DrawPosition.Y;
GUI.DrawLine(spriteBatch, new Vector2(drawRect.X, -worldSurface), new Vector2(drawRect.Right, -worldSurface), Color.Cyan * 0.5f);
for (int i = 0; i < waveY.Length - 1; i++)
{
GUI.DrawLine(spriteBatch,
@@ -578,8 +578,7 @@ namespace Barotrauma
corners[4] = new Vector3(x, bottom, 0.0f);
//bottom right
corners[5] = new Vector3(x + width, bottom, 0.0f);
Vector2[] uvCoords = new Vector2[4];
for (int n = 0; n < 4; n++)
{
uvCoords[n] = Vector2.Transform(new Vector2(corners[n].X, -corners[n].Y), transform);
@@ -9,26 +9,56 @@ namespace Barotrauma
{
static partial class CaveGenerator
{
public static List<VertexPositionTexture> GenerateWallVertices(List<Vector2[]> triangles, LevelGenerationParams generationParams, float zCoord)
public static List<VertexPositionColor> GenerateWallVertices(List<Vector2[]> triangles, Color color, float zCoord)
{
var vertices = new List<VertexPositionTexture>();
var vertices = new List<VertexPositionColor>();
for (int i = 0; i < triangles.Count; i++)
{
foreach (Vector2 vertex in triangles[i])
{
Vector2 uvCoords = vertex / generationParams.WallTextureSize;
vertices.Add(new VertexPositionTexture(new Vector3(vertex, zCoord), uvCoords));
vertices.Add(new VertexPositionColor(new Vector3(vertex, zCoord), color));
}
}
return vertices;
}
public static List<VertexPositionTexture> GenerateWallEdgeVertices(List<VoronoiCell> cells, Level level, float zCoord)
/// <summary>
/// Generates texture coordinates for the vertices based on their positions
/// </summary>
public static VertexPositionColorTexture[] ConvertToTextured(VertexPositionColor[] verts, float textureSize)
{
float outWardThickness = level.GenerationParams.WallEdgeExpandOutwardsAmount;
VertexPositionColorTexture[] texturedVerts = new VertexPositionColorTexture[verts.Length];
for (int i = 0; i < verts.Length; i++)
{
VertexPositionColor vertex = verts[i];
texturedVerts[i] = new VertexPositionColorTexture(vertex.Position, vertex.Color, textureCoordinate: Vector2.Zero);
}
GenerateTextureCoordinates(texturedVerts, textureSize);
return texturedVerts;
}
List<VertexPositionTexture> vertices = new List<VertexPositionTexture>();
/// <summary>
/// Generates texture coordinates for the vertices based on their positions
/// </summary>
public static void GenerateTextureCoordinates(VertexPositionColorTexture[] verts, float textureSize)
{
for (int i = 0; i < verts.Length; i++)
{
VertexPositionColorTexture vertex = verts[i];
Vector2 uvCoords = new Vector2(vertex.Position.X, vertex.Position.Y) / textureSize;
verts[i] = new VertexPositionColorTexture(verts[i].Position, verts[i].Color, uvCoords);
}
}
public static List<VertexPositionColorTexture> GenerateWallEdgeVertices(
List<VoronoiCell> cells,
float expandOutwards, float expandInwards,
Color outerColor, Color innerColor,
Level level, float zCoord, bool preventExpandThroughCell = false)
{
float outWardThickness = expandOutwards;
List<VertexPositionColorTexture> vertices = new List<VertexPositionColorTexture>();
foreach (VoronoiCell cell in cells)
{
Vector2 minVert = cell.Edges[0].Point1;
@@ -49,7 +79,10 @@ namespace Barotrauma
{
if (!edge.IsSolid) { continue; }
GraphEdge leftEdge = cell.Edges.Find(e => e != edge && (edge.Point1.NearlyEquals(e.Point1) || edge.Point1.NearlyEquals(e.Point2)));
//the left-side edge on this same cell
GraphEdge myLeftEdge = cell.Edges.Find(e => e != edge && (edge.Point1.NearlyEquals(e.Point1) || edge.Point1.NearlyEquals(e.Point2)));
//the left-side edge on either this cell, or the adjacent one if this is attached to another cell
GraphEdge leftEdge = myLeftEdge;
var leftAdjacentCell = leftEdge?.AdjacentCell(cell);
if (leftAdjacentCell != null)
{
@@ -57,7 +90,10 @@ namespace Barotrauma
if (adjEdge != null) { leftEdge = adjEdge; }
}
GraphEdge rightEdge = cell.Edges.Find(e => e != edge && (edge.Point2.NearlyEquals(e.Point1) || edge.Point2.NearlyEquals(e.Point2)));
//the right-side edge on this same cell
GraphEdge myRightEdge = cell.Edges.Find(e => e != edge && (edge.Point2.NearlyEquals(e.Point1) || edge.Point2.NearlyEquals(e.Point2)));
//the right-side edge on either this cell, or the adjacent one if this is attached to another cell
GraphEdge rightEdge = myRightEdge;
var rightAdjacentCell = rightEdge?.AdjacentCell(cell);
if (rightAdjacentCell != null)
{
@@ -67,18 +103,25 @@ namespace Barotrauma
Vector2 leftNormal = Vector2.Zero, rightNormal = Vector2.Zero;
float inwardThickness1 = level.GenerationParams.WallEdgeExpandInwardsAmount;
float inwardThickness2 = level.GenerationParams.WallEdgeExpandInwardsAmount;
float inwardThickness1 = Math.Min(expandInwards, edge.Length);
float inwardThickness2 = inwardThickness1;
if (leftEdge != null && !leftEdge.IsSolid)
{
//the left-side edge is non-solid (an edge between two cells, not an actual solid wall edge)
// -> expand in the direction of that edge
leftNormal = edge.Point1.NearlyEquals(leftEdge.Point1) ?
Vector2.Normalize(leftEdge.Point2 - leftEdge.Point1) :
Vector2.Normalize(leftEdge.Point1 - leftEdge.Point2);
//maximum expansion is half of the size of the edge (otherwise the expansions from different sides of the edge could overlap or even extend "through" the cell)
inwardThickness1 = Math.Min(inwardThickness1, leftEdge.Length / 2);
}
else if (leftEdge != null)
{
//use the average of this edge's and the adjacent edge's normals
leftNormal = -Vector2.Normalize(edge.GetNormal(cell) + leftEdge.GetNormal(leftAdjacentCell ?? cell));
if (!MathUtils.IsValid(leftNormal)) { leftNormal = -edge.GetNormal(cell); }
//maximum expansion is the length of the adjacent edge (more expansion causes the textures to distort)
inwardThickness1 = Math.Min(Math.Min(inwardThickness1, leftEdge.Length), myLeftEdge.Length);
}
else
{
@@ -109,11 +152,13 @@ namespace Barotrauma
rightNormal = edge.Point2.NearlyEquals(rightEdge.Point1) ?
Vector2.Normalize(rightEdge.Point2 - rightEdge.Point1) :
Vector2.Normalize(rightEdge.Point1 - rightEdge.Point2);
inwardThickness2 = Math.Min(inwardThickness2, rightEdge.Length / 2);
}
else if (rightEdge != null)
{
rightNormal = -Vector2.Normalize(edge.GetNormal(cell) + rightEdge.GetNormal(rightAdjacentCell ?? cell));
if (!MathUtils.IsValid(rightNormal)) { rightNormal = -edge.GetNormal(cell); }
inwardThickness2 = Math.Min(Math.Min(inwardThickness2, rightEdge.Length), myRightEdge.Length);
}
else
{
@@ -150,10 +195,51 @@ namespace Barotrauma
point1UV = point1UV / MathHelper.TwoPi * textureRepeatCount;
point2UV = point2UV / MathHelper.TwoPi * textureRepeatCount;
//if calculating the UVs based on polar coordinates would result in stretching (using less than 10% of the texture for a wall the size of the texture)
//just calculate the UVs based on the length of the wall
//(this will mean the textures don't align at point2, but it doesn't seem that noticeable)
if ((point2UV - point1UV) * level.GenerationParams.WallEdgeTextureWidth < edge.Length * 0.1f)
{
point2UV = point1UV + edge.Length / 2 / level.GenerationParams.WallEdgeTextureWidth;
}
//"extruding" inwards, need to make sure we don't make the edge poke through the cell from the other side
if (preventExpandThroughCell)
{
foreach (GraphEdge otherEdge in cell.Edges)
{
if (otherEdge == edge || Vector2.Dot(otherEdge.GetNormal(cell), edge.GetNormal(cell)) > 0) { continue; }
if (otherEdge != leftEdge)
{
inwardThickness1 = ClampThickness(otherEdge, edge.Point1, leftNormal, inwardThickness1);
}
if (otherEdge != rightEdge)
{
inwardThickness2 = ClampThickness(otherEdge, edge.Point2, rightNormal, inwardThickness2);
}
}
static float ClampThickness(GraphEdge otherEdge, Vector2 thisPoint, Vector2 thisEdgeNormal, float currThickness)
{
if (MathUtils.GetLineIntersection(
thisPoint, thisPoint + thisEdgeNormal * currThickness,
otherEdge.Point1, otherEdge.Point2, areLinesInfinite: false, out Vector2 intersection1))
{
return Math.Min(currThickness, Vector2.Distance(thisPoint, intersection1));
}
return currThickness;
}
}
//there needs to be some minimum amount of inward thickness,
//if the edge texture doesn't extend inside at all you can see through between the edge texture and the solid part of the cell
inwardThickness1 = Math.Max(inwardThickness1, Math.Min(100.0f, expandInwards));
inwardThickness2 = Math.Max(inwardThickness2, Math.Min(100.0f, expandInwards));
for (int i = 0; i < 2; i++)
{
Vector2[] verts = new Vector2[3];
VertexPositionTexture[] vertPos = new VertexPositionTexture[3];
VertexPositionColorTexture[] vertPos = new VertexPositionColorTexture[3];
if (i == 0)
{
@@ -161,9 +247,9 @@ namespace Barotrauma
verts[1] = edge.Point2 - rightNormal * outWardThickness;
verts[2] = edge.Point1 + leftNormal * inwardThickness1;
vertPos[0] = new VertexPositionTexture(new Vector3(verts[0], zCoord), new Vector2(point1UV, 0.0f));
vertPos[1] = new VertexPositionTexture(new Vector3(verts[1], zCoord), new Vector2(point2UV, 0.0f));
vertPos[2] = new VertexPositionTexture(new Vector3(verts[2], zCoord), new Vector2(point1UV, 1.0f));
vertPos[0] = new VertexPositionColorTexture(new Vector3(verts[0], zCoord), outerColor, new Vector2(point1UV, 0.0f));
vertPos[1] = new VertexPositionColorTexture(new Vector3(verts[1], zCoord), outerColor, new Vector2(point2UV, 0.0f));
vertPos[2] = new VertexPositionColorTexture(new Vector3(verts[2], zCoord), innerColor, new Vector2(point1UV, 1.0f));
}
else
{
@@ -172,9 +258,9 @@ namespace Barotrauma
verts[1] = edge.Point2 - rightNormal * outWardThickness;
verts[2] = edge.Point2 + rightNormal * inwardThickness2;
vertPos[0] = new VertexPositionTexture(new Vector3(verts[0], zCoord), new Vector2(point1UV, 1.0f));
vertPos[1] = new VertexPositionTexture(new Vector3(verts[1], zCoord), new Vector2(point2UV, 0.0f));
vertPos[2] = new VertexPositionTexture(new Vector3(verts[2], zCoord), new Vector2(point2UV, 1.0f));
vertPos[0] = new VertexPositionColorTexture(new Vector3(verts[0], zCoord), innerColor, new Vector2(point1UV, 1.0f));
vertPos[1] = new VertexPositionColorTexture(new Vector3(verts[1], zCoord), outerColor, new Vector2(point2UV, 0.0f));
vertPos[2] = new VertexPositionColorTexture(new Vector3(verts[2], zCoord), innerColor, new Vector2(point2UV, 1.0f));
}
vertices.AddRange(vertPos);
}
@@ -10,9 +10,11 @@ namespace Barotrauma
{
partial class LevelObjectManager
{
private readonly List<LevelObject> visibleObjectsBack = new List<LevelObject>();
private readonly List<LevelObject> visibleObjectsMid = new List<LevelObject>();
private readonly List<LevelObject> visibleObjectsFront = new List<LevelObject>();
// Pre-initialized to the max size, so that we don't have to resize the lists at runtime. TODO: Could the capacity (of some collections?) be lower?
private readonly List<LevelObject> visibleObjectsBack = new List<LevelObject>(MaxVisibleObjects);
private readonly List<LevelObject> visibleObjectsMid = new List<LevelObject>(MaxVisibleObjects);
private readonly List<LevelObject> visibleObjectsFront = new List<LevelObject>(MaxVisibleObjects);
private readonly HashSet<LevelObject> allVisibleObjects = new HashSet<LevelObject>(MaxVisibleObjects);
private double NextRefreshTime;
@@ -47,9 +49,25 @@ namespace Barotrauma
}
}
public IEnumerable<LevelObject> GetVisibleObjects()
/// <summary>
/// Returns all visible objects, but not in order, because internally uses a HashSet.
/// </summary>
public IEnumerable<LevelObject> GetAllVisibleObjects()
{
return visibleObjectsBack.Union(visibleObjectsMid).Union(visibleObjectsFront);
allVisibleObjects.Clear();
foreach (LevelObject obj in visibleObjectsBack)
{
allVisibleObjects.Add(obj);
}
foreach (LevelObject obj in visibleObjectsMid)
{
allVisibleObjects.Add(obj);
}
foreach (LevelObject obj in visibleObjectsFront)
{
allVisibleObjects.Add(obj);
}
return allVisibleObjects;
}
/// <summary>
@@ -11,10 +11,25 @@ namespace Barotrauma
{
class LevelWallVertexBuffer : IDisposable
{
public VertexBuffer WallEdgeBuffer, WallBuffer;
/// <summary>
/// Buffer for the vertices of the "actual" wall texture.
/// </summary>
public VertexBuffer WallBuffer;
/// <summary>
/// Buffer for the vertices of the repeating edge texture drawn at the edges of the walls.
/// </summary>
public VertexBuffer WallEdgeBuffer;
/// <summary>
/// Buffer for the vertices of the inner, non-textured black part of the wall.
/// </summary>
public VertexBuffer WallInnerBuffer;
public readonly Texture2D WallTexture, EdgeTexture;
private VertexPositionColorTexture[] wallVertices;
private VertexPositionColorTexture[] wallEdgeVertices;
private VertexPositionColor[] wallInnerVertices;
public bool IsDisposed
{
@@ -22,7 +37,7 @@ namespace Barotrauma
private set;
}
public LevelWallVertexBuffer(VertexPositionTexture[] wallVertices, VertexPositionTexture[] wallEdgeVertices, Texture2D wallTexture, Texture2D edgeTexture, Color color)
public LevelWallVertexBuffer(VertexPositionColorTexture[] wallVertices, VertexPositionColorTexture[] wallEdgeVertices, VertexPositionColor[] wallInnerVertices, Texture2D wallTexture, Texture2D edgeTexture)
{
if (wallVertices.Length == 0)
{
@@ -32,32 +47,41 @@ namespace Barotrauma
{
throw new ArgumentException("Failed to instantiate a LevelWallVertexBuffer (no wall edge vertices).");
}
this.wallVertices = LevelRenderer.GetColoredVertices(wallVertices, color);
this.wallVertices = wallVertices;
WallBuffer = new VertexBuffer(GameMain.Instance.GraphicsDevice, VertexPositionColorTexture.VertexDeclaration, wallVertices.Length, BufferUsage.WriteOnly);
WallBuffer.SetData(this.wallVertices);
WallTexture = wallTexture;
this.wallEdgeVertices = LevelRenderer.GetColoredVertices(wallEdgeVertices, color);
this.wallEdgeVertices = wallEdgeVertices;
WallEdgeBuffer = new VertexBuffer(GameMain.Instance.GraphicsDevice, VertexPositionColorTexture.VertexDeclaration, wallEdgeVertices.Length, BufferUsage.WriteOnly);
WallEdgeBuffer.SetData(this.wallEdgeVertices);
EdgeTexture = edgeTexture;
if (wallInnerVertices != null)
{
this.wallInnerVertices = wallInnerVertices;
WallInnerBuffer = new VertexBuffer(GameMain.Instance.GraphicsDevice, VertexPositionColor.VertexDeclaration, wallInnerVertices.Length, BufferUsage.WriteOnly);
WallInnerBuffer.SetData(this.wallInnerVertices);
}
}
public void Append(VertexPositionTexture[] wallVertices, VertexPositionTexture[] wallEdgeVertices, Color color)
public void Append(VertexPositionColorTexture[] newWallVertices, VertexPositionColorTexture[] newWallEdgeVertices, VertexPositionColor[] newWallInnerVertices)
{
WallBuffer.Dispose();
WallBuffer = new VertexBuffer(GameMain.Instance.GraphicsDevice, VertexPositionColorTexture.VertexDeclaration, this.wallVertices.Length + wallVertices.Length, BufferUsage.WriteOnly);
int originalWallVertexCount = this.wallVertices.Length;
Array.Resize(ref this.wallVertices, originalWallVertexCount + wallVertices.Length);
Array.Copy(LevelRenderer.GetColoredVertices(wallVertices, color), 0, this.wallVertices, originalWallVertexCount, wallVertices.Length);
WallBuffer.SetData(this.wallVertices);
WallBuffer = Append(WallBuffer, ref wallVertices, newWallVertices, VertexPositionColorTexture.VertexDeclaration);
WallEdgeBuffer = Append(WallEdgeBuffer, ref wallEdgeVertices, newWallEdgeVertices, VertexPositionColorTexture.VertexDeclaration);
WallInnerBuffer = Append(WallInnerBuffer, ref wallInnerVertices, newWallInnerVertices, VertexPositionColor.VertexDeclaration);
WallEdgeBuffer.Dispose();
WallEdgeBuffer = new VertexBuffer(GameMain.Instance.GraphicsDevice, VertexPositionColorTexture.VertexDeclaration, this.wallEdgeVertices.Length + wallEdgeVertices.Length, BufferUsage.WriteOnly);
int originalWallEdgeVertexCount = this.wallEdgeVertices.Length;
Array.Resize(ref this.wallEdgeVertices, originalWallEdgeVertexCount + wallEdgeVertices.Length);
Array.Copy(LevelRenderer.GetColoredVertices(wallEdgeVertices, color), 0, this.wallEdgeVertices, originalWallEdgeVertexCount, wallEdgeVertices.Length);
WallEdgeBuffer.SetData(this.wallEdgeVertices);
static VertexBuffer Append<T>(VertexBuffer buffer, ref T[] currentVertices, T[] newVertices, VertexDeclaration vertexDeclaration) where T : struct, IVertexType
{
buffer?.Dispose();
int originalVertexCount = currentVertices.Length;
int newBufferSize = originalVertexCount + newVertices.Length;
buffer = new VertexBuffer(GameMain.Instance.GraphicsDevice, vertexDeclaration, newBufferSize, BufferUsage.WriteOnly);
Array.Resize(ref currentVertices, newBufferSize);
Array.Copy(newVertices, 0, currentVertices, originalVertexCount, newVertices.Length);
buffer.SetData(currentVertices);
return buffer;
}
}
public void Dispose()
@@ -70,7 +94,7 @@ namespace Barotrauma
class LevelRenderer : IDisposable
{
private static BasicEffect wallEdgeEffect, wallCenterEffect;
private static BasicEffect wallEdgeEffect, wallCenterEffect, wallInnerEffect;
private Vector2 waterParticleOffset;
private Vector2 waterParticleVelocity;
@@ -129,7 +153,16 @@ namespace Barotrauma
};
wallCenterEffect.CurrentTechnique = wallCenterEffect.Techniques["BasicEffect_Texture"];
}
if (wallInnerEffect == null)
{
wallInnerEffect = new BasicEffect(GameMain.Instance.GraphicsDevice)
{
VertexColorEnabled = true,
TextureEnabled = false
};
wallInnerEffect.CurrentTechnique = wallInnerEffect.Techniques["BasicEffect_Texture"];
}
this.level = level;
}
@@ -184,7 +217,7 @@ namespace Barotrauma
//calculate the sum of the forces of nearby level triggers
//and use it to move the water texture and water distortion effect
Vector2 currentWaterParticleVel = level.GenerationParams.WaterParticleVelocity;
foreach (LevelObject levelObject in level.LevelObjectManager.GetVisibleObjects())
foreach (LevelObject levelObject in level.LevelObjectManager.GetAllVisibleObjects())
{
if (levelObject.Triggers == null) { continue; }
//use the largest water flow velocity of all the triggers
@@ -225,16 +258,16 @@ namespace Barotrauma
return verts;
}
public void SetVertices(VertexPositionTexture[] wallVertices, VertexPositionTexture[] wallEdgeVertices, Texture2D wallTexture, Texture2D edgeTexture, Color color)
public void SetVertices(VertexPositionColorTexture[] wallVertices, VertexPositionColorTexture[] wallEdgeVertices, VertexPositionColor[] wallInnerVertices, Texture2D wallTexture, Texture2D edgeTexture)
{
var existingBuffer = vertexBuffers.Find(vb => vb.WallTexture == wallTexture && vb.EdgeTexture == edgeTexture);
if (existingBuffer != null)
{
existingBuffer.Append(wallVertices, wallEdgeVertices,color);
existingBuffer.Append(wallVertices, wallEdgeVertices, wallInnerVertices);
}
else
{
vertexBuffers.Add(new LevelWallVertexBuffer(wallVertices, wallEdgeVertices, wallTexture, edgeTexture, color));
vertexBuffers.Add(new LevelWallVertexBuffer(wallVertices, wallEdgeVertices, wallInnerVertices, wallTexture, edgeTexture));
}
}
@@ -497,15 +530,16 @@ namespace Barotrauma
}
}
wallEdgeEffect.Alpha = 1.0f;
wallCenterEffect.Alpha = 1.0f;
wallCenterEffect.World = transformMatrix;
wallEdgeEffect.World = transformMatrix;
wallEdgeEffect.Alpha = wallInnerEffect.Alpha = wallCenterEffect.Alpha = 1.0f;
wallCenterEffect.World = wallInnerEffect.World = wallEdgeEffect.World = transformMatrix;
//render static walls
foreach (var vertexBuffer in vertexBuffers)
{
wallInnerEffect.CurrentTechnique.Passes[0].Apply();
graphicsDevice.SetVertexBuffer(vertexBuffer.WallInnerBuffer);
graphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, (int)Math.Floor(vertexBuffer.WallInnerBuffer.VertexCount / 3.0f));
wallCenterEffect.Texture = vertexBuffer.WallTexture;
wallCenterEffect.CurrentTechnique.Passes[0].Apply();
graphicsDevice.SetVertexBuffer(vertexBuffer.WallBuffer);
@@ -1,10 +1,7 @@
using Barotrauma.Extensions;
using FarseerPhysics;
using FarseerPhysics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Barotrauma
{
@@ -26,22 +23,29 @@ namespace Barotrauma
Matrix.CreateTranslation(new Vector3(ConvertUnits.ToDisplayUnits(Body.Position), 0.0f));
}
public void SetWallVertices(VertexPositionTexture[] wallVertices, VertexPositionTexture[] wallEdgeVertices, Texture2D wallTexture, Texture2D edgeTexture, Color color)
public void SetWallVertices(
VertexPositionColorTexture[] wallVertices, VertexPositionColorTexture[] wallEdgeVertices,
Texture2D wallTexture, Texture2D edgeTexture)
{
if (VertexBuffer != null && !VertexBuffer.IsDisposed) { VertexBuffer.Dispose(); }
VertexBuffer = new LevelWallVertexBuffer(wallVertices, wallEdgeVertices, wallTexture, edgeTexture, color);
VertexBuffer = new LevelWallVertexBuffer(wallVertices, wallEdgeVertices, wallInnerVertices: null, wallTexture, edgeTexture);
}
public void GenerateVertices()
{
float zCoord = this is DestructibleLevelWall ? Rand.Range(0.9f, 1.0f) : 0.9f;
List<VertexPositionTexture> wallVertices = CaveGenerator.GenerateWallVertices(triangles, level.GenerationParams, zCoord);
var nonTexturedWallVerts =
CaveGenerator.GenerateWallVertices(triangles, color, zCoord: 0.9f).ToArray();
var wallVerts = CaveGenerator.ConvertToTextured(nonTexturedWallVerts, level.GenerationParams.WallTextureSize);
SetWallVertices(
wallVertices.ToArray(),
CaveGenerator.GenerateWallEdgeVertices(Cells, level, zCoord).ToArray(),
wallVertices: wallVerts,
wallEdgeVertices: CaveGenerator.GenerateWallEdgeVertices(Cells,
level.GenerationParams.WallEdgeExpandOutwardsAmount, level.GenerationParams.WallEdgeExpandInwardsAmount,
outerColor: color, innerColor: color,
level, zCoord)
.ToArray(),
level.GenerationParams.WallSprite.Texture,
level.GenerationParams.WallEdgeSprite.Texture,
color);
level.GenerationParams.WallEdgeSprite.Texture);
}
public bool IsVisible(Rectangle worldView)
@@ -443,10 +443,10 @@ namespace Barotrauma.Lights
public bool Intersects(Rectangle rect)
{
if (!Enabled) return false;
if (!Enabled) { return false; }
Rectangle transformedBounds = BoundingBox;
if (ParentEntity != null && ParentEntity.Submarine != null)
if (ParentEntity is { Submarine: not null })
{
transformedBounds.X += (int)ParentEntity.Submarine.Position.X;
transformedBounds.Y += (int)ParentEntity.Submarine.Position.Y;
@@ -243,6 +243,7 @@ namespace Barotrauma.Lights
}
}
/// <param name="backgroundObstructor">A render target that contains the structures that should obstruct lights in the background. If not given, damageable walls and hulls are rendered to obstruct the background lights.</param>
public void RenderLightMap(GraphicsDevice graphics, SpriteBatch spriteBatch, Camera cam, RenderTarget2D backgroundObstructor = null)
{
if (!LightingEnabled) { return; }
@@ -411,11 +412,21 @@ namespace Barotrauma.Lights
}
spriteBatch.End();
GameMain.GameScreen.DamageEffect.CurrentTechnique = GameMain.GameScreen.DamageEffect.Techniques["StencilShaderSolidColor"];
GameMain.GameScreen.DamageEffect.Parameters["solidColor"].SetValue(Color.Black.ToVector4());
spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.NonPremultiplied, SamplerState.LinearWrap, transformMatrix: spriteBatchTransform, effect: GameMain.GameScreen.DamageEffect);
Submarine.DrawDamageable(spriteBatch, GameMain.GameScreen.DamageEffect);
spriteBatch.End();
if (backgroundObstructor != null)
{
spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.NonPremultiplied, SamplerState.LinearWrap, transformMatrix: Matrix.Identity, effect: GameMain.GameScreen.DamageEffect);
spriteBatch.Draw(backgroundObstructor, new Rectangle(0, 0,
(int)(GameMain.GraphicsWidth * currLightMapScale), (int)(GameMain.GraphicsHeight * currLightMapScale)), Color.Black);
spriteBatch.End();
}
else
{
GameMain.GameScreen.DamageEffect.CurrentTechnique = GameMain.GameScreen.DamageEffect.Techniques["StencilShaderSolidColor"];
GameMain.GameScreen.DamageEffect.Parameters["solidColor"].SetValue(Color.Black.ToVector4());
spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.NonPremultiplied, SamplerState.LinearWrap, transformMatrix: spriteBatchTransform, effect: GameMain.GameScreen.DamageEffect);
Submarine.DrawDamageable(spriteBatch, GameMain.GameScreen.DamageEffect);
spriteBatch.End();
}
graphics.BlendState = BlendState.Additive;
@@ -680,11 +691,14 @@ namespace Barotrauma.Lights
}
return visibleHulls;
}
private static readonly List<VertexPositionColor> ShadowVertices = new List<VertexPositionColor>(500);
private static readonly List<VertexPositionTexture> PenumbraVertices = new List<VertexPositionTexture>(500);
public void UpdateObstructVision(GraphicsDevice graphics, SpriteBatch spriteBatch, Camera cam, Vector2 lookAtPosition)
{
if ((!LosEnabled || LosMode == LosMode.None) && ObstructVisionAmount <= 0.0f) { return; }
if (ViewTarget == null) return;
if (ViewTarget == null) { return; }
graphics.SetRenderTarget(LosTexture);
@@ -767,11 +781,11 @@ namespace Barotrauma.Lights
if (convexHulls != null)
{
List<VertexPositionColor> shadowVerts = new List<VertexPositionColor>();
List<VertexPositionTexture> penumbraVerts = new List<VertexPositionTexture>();
ShadowVertices.Clear();
PenumbraVertices.Clear();
foreach (ConvexHull convexHull in convexHulls)
{
if (!convexHull.Enabled || !convexHull.Intersects(camView)) { continue; }
if (!convexHull.Intersects(camView)) { continue; }
Vector2 relativeViewPos = pos;
if (convexHull.ParentEntity?.Submarine != null)
@@ -783,26 +797,26 @@ namespace Barotrauma.Lights
for (int i = 0; i < convexHull.ShadowVertexCount; i++)
{
shadowVerts.Add(convexHull.ShadowVertices[i]);
ShadowVertices.Add(convexHull.ShadowVertices[i]);
}
for (int i = 0; i < convexHull.PenumbraVertexCount; i++)
{
penumbraVerts.Add(convexHull.PenumbraVertices[i]);
PenumbraVertices.Add(convexHull.PenumbraVertices[i]);
}
}
if (shadowVerts.Count > 0)
if (ShadowVertices.Count > 0)
{
ConvexHull.shadowEffect.World = shadowTransform;
ConvexHull.shadowEffect.CurrentTechnique.Passes[0].Apply();
graphics.DrawUserPrimitives(PrimitiveType.TriangleList, shadowVerts.ToArray(), 0, shadowVerts.Count / 3, VertexPositionColor.VertexDeclaration);
graphics.DrawUserPrimitives(PrimitiveType.TriangleList, ShadowVertices.ToArray(), 0, ShadowVertices.Count / 3, VertexPositionColor.VertexDeclaration);
if (penumbraVerts.Count > 0)
if (PenumbraVertices.Count > 0)
{
ConvexHull.penumbraEffect.World = shadowTransform;
ConvexHull.penumbraEffect.CurrentTechnique.Passes[0].Apply();
graphics.DrawUserPrimitives(PrimitiveType.TriangleList, penumbraVerts.ToArray(), 0, penumbraVerts.Count / 3, VertexPositionTexture.VertexDeclaration);
graphics.DrawUserPrimitives(PrimitiveType.TriangleList, PenumbraVertices.ToArray(), 0, PenumbraVertices.Count / 3, VertexPositionTexture.VertexDeclaration);
}
}
}
@@ -592,7 +592,17 @@ namespace Barotrauma.Lights
private void CheckHullsInRange(Submarine sub)
{
//find the list of convexhulls that belong to the sub
ConvexHullList chList = convexHullsInRange.FirstOrDefault(chList => chList.Submarine == sub);
// Performance-sensitive code, hence implemented without Linq.
ConvexHullList chList = null;
foreach (var chl in convexHullsInRange)
{
if (chl.Submarine == sub)
{
chList = chl;
break;
}
}
//not found -> create one
if (chList == null)
@@ -451,7 +451,7 @@ namespace Barotrauma
MathUtils.PositiveModulo(-textureOffset.X, Prefab.BackgroundSprite.SourceRect.Width * TextureScale.X * Scale),
MathUtils.PositiveModulo(-textureOffset.Y, Prefab.BackgroundSprite.SourceRect.Height * TextureScale.Y * Scale));
float rotationRad = rotationForSprite(this.rotationRad, Prefab.BackgroundSprite);
float rotationRad = GetRotationForSprite(this.rotationRad, Prefab.BackgroundSprite);
Prefab.BackgroundSprite.DrawTiled(
spriteBatch,
@@ -492,7 +492,7 @@ namespace Barotrauma
advanceY = advanceY.FlipX();
}
float sectionSpriteRotationRad = rotationForSprite(this.rotationRad, Prefab.Sprite);
float sectionSpriteRotationRad = GetRotationForSprite(this.rotationRad, Prefab.Sprite);
for (int i = 0; i < Sections.Length; i++)
{
@@ -501,11 +501,17 @@ namespace Barotrauma
{
float newCutoff = MathHelper.Lerp(0.0f, 0.65f, Sections[i].damage / MaxHealth);
if (Math.Abs(newCutoff - Submarine.DamageEffectCutoff) > 0.01f || color != Submarine.DamageEffectColor)
if (Math.Abs(newCutoff - Submarine.DamageEffectCutoff) > 0.05f)
{
spriteBatch.End();
spriteBatch.Begin(SpriteSortMode.BackToFront,
BlendState.NonPremultiplied, SamplerState.LinearWrap,
null, null,
damageEffect,
Screen.Selected.Cam.Transform);
damageEffect.Parameters["aCutoff"].SetValue(newCutoff);
damageEffect.Parameters["cCutoff"].SetValue(newCutoff * 1.2f);
damageEffect.Parameters["inColor"].SetValue(color.ToVector4());
damageEffect.CurrentTechnique.Passes[0].Apply();
@@ -570,9 +576,13 @@ namespace Barotrauma
}
}
static float rotationForSprite(float rotationRad, Sprite sprite)
static float GetRotationForSprite(float rotationRad, Sprite sprite)
{
if (sprite.effects.HasFlag(SpriteEffects.FlipHorizontally) != sprite.effects.HasFlag(SpriteEffects.FlipVertically))
// Use bitwise operations instead of HasFlag to avoid boxing, as this is performance-sensitive code.
bool flipHorizontally = (sprite.effects & SpriteEffects.FlipHorizontally) == SpriteEffects.FlipHorizontally;
bool flipVertically = (sprite.effects & SpriteEffects.FlipVertically) == SpriteEffects.FlipVertically;
if (flipHorizontally != flipVertically)
{
rotationRad = -rotationRad;
}
@@ -604,6 +614,10 @@ namespace Barotrauma
if (GetSection(i).damage > 0)
{
var textPos = SectionPosition(i, true);
if (Submarine != null)
{
textPos += (Submarine.DrawPosition - Submarine.Position);
}
textPos.Y = -textPos.Y;
GUI.DrawString(spriteBatch, textPos, "Damage: " + (int)((GetSection(i).damage / MaxHealth) * 100f) + "%", Color.Yellow);
}
@@ -134,7 +134,7 @@ namespace Barotrauma
foreach (Submarine sub in Loaded)
{
Rectangle worldBorders = sub.Borders;
worldBorders.Location += sub.WorldPosition.ToPoint();
worldBorders.Location += (sub.DrawPosition + sub.HiddenSubPosition).ToPoint();
worldBorders.Y = -worldBorders.Y;
GUI.DrawRectangle(spriteBatch, worldBorders, Color.White, false, 0, 5);
@@ -161,38 +161,38 @@ namespace Barotrauma
public static float DamageEffectCutoff;
public static Color DamageEffectColor;
private static readonly List<Structure> depthSortedDamageable = new List<Structure>();
public static void DrawDamageable(SpriteBatch spriteBatch, Effect damageEffect, bool editing = false, Predicate<MapEntity> predicate = null)
{
var entitiesToRender = !editing && visibleEntities != null ? visibleEntities : MapEntity.MapEntityList;
depthSortedDamageable.Clear();
//insertion sort according to draw depth
foreach (MapEntity e in entitiesToRender)
if (!editing && visibleEntities != null)
{
if (e is Structure structure && structure.DrawDamageEffect)
foreach (MapEntity e in visibleEntities)
{
if (predicate != null)
if (e is Structure structure && structure.DrawDamageEffect)
{
if (!predicate(e)) { continue; }
if (predicate != null)
{
if (!predicate(structure)) { continue; }
}
structure.DrawDamage(spriteBatch, damageEffect, editing);
}
float drawDepth = structure.GetDrawDepth();
int i = 0;
while (i < depthSortedDamageable.Count)
}
}
else
{
foreach (Structure structure in Structure.WallList)
{
if (structure.DrawDamageEffect)
{
float otherDrawDepth = depthSortedDamageable[i].GetDrawDepth();
if (otherDrawDepth < drawDepth) { break; }
i++;
if (predicate != null)
{
if (!predicate(structure)) { continue; }
}
structure.DrawDamage(spriteBatch, damageEffect, editing);
}
depthSortedDamageable.Insert(i, structure);
}
}
foreach (Structure s in depthSortedDamageable)
{
s.DrawDamage(spriteBatch, damageEffect, editing);
}
if (damageEffect != null)
{
damageEffect.Parameters["aCutoff"].SetValue(0.0f);
@@ -506,6 +506,16 @@ namespace Barotrauma
warnings.Add(SubEditorScreen.WarningType.WaterInHulls);
Hull.ShowHulls = true;
}
if (Info.IsWreck)
{
Point vanillaBrainSize = new Point(204, 204);
if (WreckAI.GetPotentialBrainRooms(this, WreckAIConfig.GetRandom(), minSize: vanillaBrainSize).None())
{
errorMsgs.Add(TextManager.Get("NoSuitableBrainRoomsWarning").Value);
warnings.Add(SubEditorScreen.WarningType.NoSuitableBrainRooms);
}
}
if (!IsWarningSuppressed(SubEditorScreen.WarningType.NotEnoughContainers))
{
@@ -46,6 +46,10 @@ namespace Barotrauma
}
if (IsHighlighted || IsHighlighted) { clr = Color.Lerp(clr, Color.White, 0.8f); }
if (Stairs is { Removed: true }) { Stairs = null; }
if (Ladders is { Item.Removed: true }) { Ladders = null; }
if (ConnectedGap is { Removed: true }) { ConnectedGap = null; }
int iconSize = spawnType == SpawnType.Path ? WaypointSize : SpawnPointSize;
if (ConnectedDoor != null || Ladders != null || Stairs != null || SpawnType != SpawnType.Path)
{