38f1ddb...178a853: v0.8.9.1, removed content folder

This commit is contained in:
Joonas Rikkonen
2019-03-18 19:46:58 +02:00
parent 38f1ddb6fe
commit 6c0679c297
1054 changed files with 151673 additions and 144931 deletions
@@ -1,10 +1,11 @@
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using Barotrauma.Extensions;
namespace Barotrauma
{
//TODO: perhaps find a better place for this?
//TODO: Currently this is only used for text positioning? -> move there?
[Flags]
public enum Alignment
{
@@ -21,6 +22,27 @@ namespace Barotrauma
return (i % n + n) % n;
}
public static double Distance(double x1, double y1, double x2, double y2)
{
double dX = x1 - x2;
double dY = y1 - y2;
return Math.Sqrt(dX * dX + dY * dY);
}
public static double DistanceSquared(double x1, double y1, double x2, double y2)
{
double dX = x1 - x2;
double dY = y1 - y2;
return dX * dX + dY * dY;
}
public static int DistanceSquared(int x1, int y1, int x2, int y2)
{
int dX = x1 - x2;
int dY = y1 - y2;
return dX * dX + dY * dY;
}
public static Vector2 SmoothStep(Vector2 v1, Vector2 v2, float amount)
{
return new Vector2(
@@ -31,13 +53,18 @@ namespace Barotrauma
public static Vector2 ClampLength(this Vector2 v, float length)
{
float currLength = v.Length();
if (v.Length() > length)
if (currLength > length)
{
return v / currLength * length;
}
return v;
}
public static bool Contains(this Rectangle rect, double x, double y)
{
return x > rect.X && x < rect.Right && y > rect.Y && y < rect.Bottom;
}
public static float Round(float value, float div)
{
return (value < 0.0f) ?
@@ -217,101 +244,116 @@ namespace Barotrauma
}
// a1 is line1 start, a2 is line1 end, b1 is line2 start, b2 is line2 end
public static Vector2? GetLineIntersection(Vector2 a1, Vector2 a2, Vector2 b1, Vector2 b2)
public static bool GetLineIntersection(Vector2 a1, Vector2 a2, Vector2 b1, Vector2 b2, out Vector2 intersection)
{
intersection = Vector2.Zero;
Vector2 b = a2 - a1;
Vector2 d = b2 - b1;
float bDotDPerp = b.X * d.Y - b.Y * d.X;
// if b dot d == 0, it means the lines are parallel so have infinite intersection points
if (bDotDPerp == 0) return null;
if (bDotDPerp == 0) return false;
Vector2 c = b1 - a1;
float t = (c.X * d.Y - c.Y * d.X) / bDotDPerp;
if (t < 0 || t > 1) return null;
if (t < 0 || t > 1) return false;
float u = (c.X * b.Y - c.Y * b.X) / bDotDPerp;
if (u < 0 || u > 1) return null;
if (u < 0 || u > 1) return false;
return a1 + t * b;
intersection = a1 + t * b;
return true;
}
public static Vector2? GetAxisAlignedLineIntersection(Vector2 a1, Vector2 a2, Vector2 axisAligned1, Vector2 axisAligned2, bool isHorizontal)
public static bool GetAxisAlignedLineIntersection(Vector2 a1, Vector2 a2, Vector2 axisAligned1, Vector2 axisAligned2, bool isHorizontal, out Vector2 intersection)
{
intersection = Vector2.Zero;
if (!isHorizontal)
{
if (Math.Sign(a1.X - axisAligned1.X) == Math.Sign(a2.X - axisAligned1.X))
return null;
float xDiff = axisAligned1.X - a1.X;
if (Math.Sign(xDiff) == Math.Sign(axisAligned1.X - a2.X)) { return false; }
float s = (a2.Y - a1.Y) / (a2.X - a1.X);
float y = a1.Y + (axisAligned1.X - a1.X) * s;
float y = a1.Y + xDiff * s;
if (axisAligned1.Y < axisAligned2.Y)
{
if (y < axisAligned1.Y) return null;
if (y > axisAligned2.Y) return null;
if (y < axisAligned1.Y) return false;
if (y > axisAligned2.Y) return false;
}
else
{
if (y > axisAligned1.Y) return null;
if (y < axisAligned2.Y) return null;
if (y > axisAligned1.Y) return false;
if (y < axisAligned2.Y) return false;
}
return new Vector2(axisAligned1.X, y);
intersection = new Vector2(axisAligned1.X, y);
return true;
}
else //horizontal line
{
if (Math.Sign(a1.Y - axisAligned1.Y) == Math.Sign(a2.Y - axisAligned1.Y))
return null;
float yDiff = axisAligned1.Y - a1.Y;
if (Math.Sign(yDiff) == Math.Sign(axisAligned1.Y - a2.Y)) { return false; }
float s = (a2.X - a1.X) / (a2.Y - a1.Y);
float x = a1.X + (axisAligned1.Y - a1.Y) * s;
float x = a1.X + yDiff * s;
if (axisAligned1.X < axisAligned2.X)
{
if (x < axisAligned1.X) return null;
if (x > axisAligned2.X) return null;
if (x < axisAligned1.X) return false;
if (x > axisAligned2.X) return false;
}
else
{
if (x > axisAligned1.X) return null;
if (x < axisAligned2.X) return null;
if (x > axisAligned1.X) return false;
if (x < axisAligned2.X) return false;
}
return new Vector2(x, axisAligned1.Y);
intersection = new Vector2(x, axisAligned1.Y);
return true;
}
}
public static Vector2? GetLineRectangleIntersection(Vector2 a1, Vector2 a2, Rectangle rect)
public static bool GetLineRectangleIntersection(Vector2 a1, Vector2 a2, Rectangle rect, out Vector2 intersection)
{
Vector2? intersection = GetAxisAlignedLineIntersection(a1, a2,
if (GetAxisAlignedLineIntersection(a1, a2,
new Vector2(rect.X, rect.Y),
new Vector2(rect.Right, rect.Y),
true);
true, out intersection))
{
return true;
}
if (intersection != null) return intersection;
intersection = GetAxisAlignedLineIntersection(a1, a2,
if (GetAxisAlignedLineIntersection(a1, a2,
new Vector2(rect.X, rect.Y-rect.Height),
new Vector2(rect.Right, rect.Y-rect.Height),
true);
true, out intersection))
{
return true;
}
if (intersection != null) return intersection;
intersection = GetAxisAlignedLineIntersection(a1, a2,
if(GetAxisAlignedLineIntersection(a1, a2,
new Vector2(rect.X, rect.Y),
new Vector2(rect.X, rect.Y - rect.Height),
false);
false, out intersection))
{
return true;
}
if (intersection != null) return intersection;
return GetAxisAlignedLineIntersection(a1, a2,
if (GetAxisAlignedLineIntersection(a1, a2,
new Vector2(rect.Right, rect.Y),
new Vector2(rect.Right, rect.Y - rect.Height),
false);
false, out intersection))
{
return true;
}
return false;
}
public static List<Vector2> GetLineRectangleIntersections(Vector2 a1, Vector2 a2, Rectangle rect)
/*public static List<Vector2> GetLineRectangleIntersections(Vector2 a1, Vector2 a2, Rectangle rect)
{
List<Vector2> intersections = new List<Vector2>();
@@ -344,6 +386,91 @@ namespace Barotrauma
if (intersection != null) intersections.Add((Vector2)intersection);
return intersections;
}*/
/// <summary>
/// Get the intersections between a line (either infinite or a line segment) and a circle
/// </summary>
/// <param name="circlePos">Center of the circle</param>
/// <param name="radius">Radius of the circle</param>
/// <param name="point1">1st point on the line</param>
/// <param name="point2">2nd point on the line</param>
/// <param name="isLineSegment">Is the line a segment or infinite</param>
/// <returns>The number of intersections</returns>
public static int GetLineCircleIntersections(Vector2 circlePos, float radius,
Vector2 point1, Vector2 point2, bool isLineSegment, out Vector2? intersection1, out Vector2? intersection2)
{
float dx, dy, A, B, C, det;
dx = point2.X - point1.X;
dy = point2.Y - point1.Y;
A = dx * dx + dy * dy;
B = 2 * (dx * (point1.X - circlePos.X) + dy * (point1.Y - circlePos.Y));
C = (point1.X - circlePos.X) * (point1.X - circlePos.X) + (point1.Y - circlePos.Y) * (point1.Y - circlePos.Y) - radius * radius;
det = B * B - 4 * A * C;
if ((A <= 0.0000001) || (det < 0))
{
// No real solutions.
intersection1 = null;
intersection2 = null;
return 0;
}
else if (det == 0)
{
// One solution.
float t = -B / (2 * A);
intersection1 = new Vector2(point1.X + t * dx, point1.Y + t * dy);
intersection2 = null;
return 1;
}
else
{
// Two solutions.
float t1 = (float)((-B + Math.Sqrt(det)) / (2 * A));
float t2 = (float)((-B - Math.Sqrt(det)) / (2 * A));
//if the line is not infinite, we need to check if the intersections are on the segment
if (isLineSegment)
{
if (t1 >= 0 && t1 <= 1.0f)
{
intersection1 = point1 + new Vector2(dx, dy) * t1;
if (t2 >= 0 && t2 <= 1.0f)
{
//both intersections on the segment
intersection2 = point1 + new Vector2(dx, dy) * t2;
return 2;
}
//only the first intersection is on the segment
intersection2 = null;
return 1;
}
else if (t2 >= 0 && t2 <= 1.0f)
{
//only the second intersection is on the segment
intersection1 = point1 + new Vector2(dx, dy) * t2;
intersection2 = null;
return 1;
}
else
{
//neither is on the segment
intersection1 = null;
intersection2 = null;
return 0;
}
}
else
{
intersection1 = point1 + new Vector2(dx, dy) * t1;
intersection2 = point1 + new Vector2(dx, dy) * t2;
return 2;
}
}
}
public static float LineToPointDistance(Vector2 lineA, Vector2 lineB, Vector2 point)
@@ -358,29 +485,26 @@ namespace Barotrauma
return (float)(Math.Abs(xDiff * (lineA.Y - point.Y) - yDiff * (lineA.X - point.X)) /
Math.Sqrt(xDiff * xDiff + yDiff * yDiff));
}
}
public static bool CircleIntersectsRectangle(Vector2 circlePos, float radius, Rectangle rect)
{
float xDist = Math.Abs(circlePos.X - rect.Center.X);
float yDist = Math.Abs(circlePos.Y - rect.Center.Y);
int halfWidth = rect.Width / 2;
float xDist = Math.Abs(circlePos.X - (rect.X + halfWidth));
if (xDist > halfWidth + radius) { return false; }
int halfHeight = rect.Height / 2;
if (xDist > (halfWidth + radius)) { return false; }
if (yDist > (halfHeight + radius)) { return false; }
float yDist = Math.Abs(circlePos.Y - (rect.Y + halfHeight));
if (yDist > halfHeight + radius) { return false; }
if (xDist <= (halfWidth)) { return true; }
if (yDist <= (halfHeight)) { return true; }
if (xDist <= halfWidth || yDist <= halfHeight) { return true; }
float distSqX = xDist - halfWidth;
float distSqY = yDist - halfHeight;
return (distSqX * distSqX + distSqY * distSqY <= (radius * radius));
return distSqX * distSqX + distSqY * distSqY <= radius * radius;
}
/// <summary>
/// divide a convex hull into triangles
/// </summary>
@@ -449,13 +573,13 @@ namespace Barotrauma
return wrappedPoints;
}
public static List<Vector2[]> GenerateJaggedLine(Vector2 start, Vector2 end, int generations, float offsetAmount)
public static List<Vector2[]> GenerateJaggedLine(Vector2 start, Vector2 end, int iterations, float offsetAmount)
{
List<Vector2[]> segments = new List<Vector2[]>();
segments.Add(new Vector2[] { start, end });
for (int n = 0; n < generations; n++)
for (int n = 0; n < iterations; n++)
{
for (int i = 0; i < segments.Count; i++)
{
@@ -475,6 +599,8 @@ namespace Barotrauma
i++;
}
offsetAmount *= 0.5f;
}
return segments;
@@ -574,6 +700,155 @@ namespace Barotrauma
}
}*/
}
/// <summary>
/// Float comparison. Note that may still fail in some cases.
/// </summary>
// References:
// http://floating-point-gui.de/errors/comparison/
// https://stackoverflow.com/questions/3874627/floating-point-comparison-functions-for-c-sharp
public static bool NearlyEqual(float a, float b, float epsilon = 0.0001f)
{
float diff = Math.Abs(a - b);
if (a == b)
{
// shortcut, handles infinities
return true;
}
else if (a == 0 || b == 0 || diff < float.Epsilon)
{
// a or b is zero or both are extremely close to it
// relative error is less meaningful here
return diff < epsilon;
}
else
{
// use relative error
return diff / (Math.Abs(a) + Math.Abs(b)) < epsilon;
}
}
/// Returns a position in a curve.
/// </summary>
public static Vector2 Bezier(Vector2 start, Vector2 control, Vector2 end, float t)
{
return Pow(1 - t, 2) * start + 2 * t * (1 - t) * control + Pow(t, 2) * end;
}
public static float Pow(float f, float p)
{
return (float)Math.Pow(f, p);
}
/// <summary>
/// Rotates a point in 2d space around another point.
/// Modified from:
/// http://www.gamefromscratch.com/post/2012/11/24/GameDev-math-recipes-Rotating-one-point-around-another-point.aspx
/// </summary>
public static Vector2 RotatePointAroundTarget(Vector2 point, Vector2 target, float degrees, bool clockWise = true)
{
// (Math.PI / 180) * degrees
var angle = MathHelper.ToRadians(degrees);
var sin = Math.Sin(angle);
var cos = Math.Cos(angle);
if (!clockWise)
{
sin = -sin;
}
Vector2 dir = point - target;
var x = (cos * dir.X) - (sin * dir.Y) + target.X;
var y = (sin * dir.X) + (cos * dir.Y) + target.Y;
return new Vector2((float)x, (float)y);
}
/// <summary>
/// Returns the corners of an imaginary rectangle.
/// Unlike the XNA rectangle, this can be rotated with the up parameter.
/// </summary>
public static Vector2[] GetImaginaryRect(Vector2 up, Vector2 center, Vector2 size)
{
return GetImaginaryRect(new Vector2[4], up, center, size);
}
/// <summary>
/// Returns the corners of an imaginary rectangle.
/// Unlike the XNA Rectangle, this can be rotated with the up parameter.
/// </summary>
public static Vector2[] GetImaginaryRect(Vector2[] corners, Vector2 up, Vector2 center, Vector2 size)
{
if (corners.Length != 4)
{
throw new Exception("Invalid length for the corners array. Must be 4.");
}
Vector2 halfSize = size / 2;
Vector2 left = up.Right();
corners[0] = center + up * halfSize.Y + left * halfSize.X;
corners[1] = center + up * halfSize.Y - left * halfSize.X;
corners[2] = center - up * halfSize.Y - left * halfSize.X;
corners[3] = center - up * halfSize.Y + left * halfSize.X;
return corners;
}
/// <summary>
/// Check if a point is inside a rectangle.
/// Unlike the XNA Rectangle, this rectangle might have been rotated.
/// For XNA Rectangles, use the Contains instance method.
/// </summary>
public static bool RectangleContainsPoint(Vector2[] corners, Vector2 point)
{
if (corners.Length != 4)
{
throw new Exception("Invalid length of the corners array! Must be 4");
}
return RectangleContainsPoint(corners[0], corners[1], corners[2], corners[3], point);
}
/// <summary>
/// Check if a point is inside a rectangle.
/// Unlike the XNA Rectangle, this rectangle might have been rotated.
/// For XNA Rectangles, use the Contains instance method.
/// </summary>
public static bool RectangleContainsPoint(Vector2 c1, Vector2 c2, Vector2 c3, Vector2 c4, Vector2 point)
{
return TriangleContainsPoint(c1, c2, c3, point) || TriangleContainsPoint(c1, c3, c4, point);
}
/// <summary>
/// Slightly modified from https://gamedev.stackexchange.com/questions/110229/how-do-i-efficiently-check-if-a-point-is-inside-a-rotated-rectangle
/// </summary>
public static bool TriangleContainsPoint(Vector2 c1, Vector2 c2, Vector2 c3, Vector2 point)
{
// Compute vectors
Vector2 v0 = c3 - c1;
Vector2 v1 = c2 - c1;
Vector2 v2 = point - c1;
// Compute dot products
float dot00 = Vector2.Dot(v0, v0);
float dot01 = Vector2.Dot(v0, v1);
float dot02 = Vector2.Dot(v0, v2);
float dot11 = Vector2.Dot(v1, v1);
float dot12 = Vector2.Dot(v1, v2);
// Compute barycentric coordinates
float invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
float u = (dot11 * dot02 - dot01 * dot12) * invDenom;
float v = (dot00 * dot12 - dot01 * dot02) * invDenom;
// Check if the point is in triangle
return u >= 0 && v >= 0 && (u + v) < 1;
}
/// <summary>
/// Returns a scalar t from a value v between a range from min to max. Clamped between 0 and 1.
/// </summary>
public static float InverseLerp(float min, float max, float v)
{
float diff = max - min;
// Ensure that we don't get division by zero exceptions.
if (diff == 0) { return v >= max ? 1f : 0f; }
return MathHelper.Clamp((v - min) / diff, 0f, 1f);
}
}
class CompareCCW : IComparer<Vector2>
@@ -1,9 +1,10 @@
using Microsoft.Xna.Framework;
using System;
using Voronoi2;
namespace Barotrauma
{
static class Rand
public static class Rand
{
public enum RandSync
{
@@ -17,6 +18,11 @@ namespace Barotrauma
new MTRandom(), new MTRandom()
};
public static Random GetRNG(RandSync randSync)
{
return randSync == RandSync.Unsynced ? localRandom : syncedRandom[(int)randSync];
}
public static void SetSyncedSeed(int seed)
{
syncedRandom[(int)RandSync.Server] = new MTRandom(seed);
@@ -39,6 +45,12 @@ namespace Barotrauma
return (float)(sync == RandSync.Unsynced ? localRandom : (syncedRandom[(int)sync])).NextDouble() * (maximum - minimum) + minimum;
}
public static double Range(double minimum, double maximum, RandSync sync = RandSync.Unsynced)
{
Assert(sync);
return (sync == RandSync.Unsynced ? localRandom : (syncedRandom[(int)sync])).NextDouble() * (maximum - minimum) + minimum;
}
public static int Range(int minimum, int maximum, RandSync sync = RandSync.Unsynced)
{
Assert(sync);
@@ -56,10 +68,41 @@ namespace Barotrauma
Assert(sync);
Vector2 randomVector = new Vector2(Range(-1.0f, 1.0f, sync), Range(-1.0f, 1.0f, sync));
if (randomVector == Vector2.Zero) return new Vector2(0.0f, length);
if (randomVector.LengthSquared() < 0.001f) return new Vector2(0.0f, length);
return Vector2.Normalize(randomVector) * length;
}
/// <summary>
/// Random float between 0 and 1.
/// </summary>
public static float Value(RandSync sync = RandSync.Unsynced)
{
return Range(0f, 1f, sync);
}
public static Color Color(bool randomAlpha = false, RandSync sync = RandSync.Unsynced)
{
if (randomAlpha)
{
return new Color(Value(sync), Value(sync), Value(sync), Value(sync));
}
else
{
return new Color(Value(sync), Value(sync), Value(sync));
}
}
public static DoubleVector2 Vector(double length, RandSync sync = RandSync.Unsynced)
{
Assert(sync);
double x = Range(-1.0, 1.0, sync);
double y = Range(-1.0, 1.0, sync);
double len = Math.Sqrt(x * x + y * y);
if (len < 0.00001) return new DoubleVector2(0.0, length);
return new DoubleVector2(x / len * length, y / len * length);
}
}
}
@@ -33,9 +33,9 @@ namespace Barotrauma
{
ClearFolder(tempPath, new string[] { GameMain.GameSession.Submarine.FilePath });
}
catch
catch (Exception e)
{
DebugConsole.ThrowError("Failed to clear folder", e);
}
try
@@ -48,7 +48,7 @@ namespace Barotrauma
Submarine.MainSub.FilePath = subPath;
Submarine.MainSub.SaveAs(Submarine.MainSub.FilePath);
}
else
else if (Submarine.MainSub.FilePath != subPath)
{
File.Copy(Submarine.MainSub.FilePath, subPath);
Submarine.MainSub.FilePath = subPath;
@@ -107,8 +107,9 @@ namespace Barotrauma
{
DecompressToDirectory(filePath, tempPath, null);
}
catch
catch (Exception e)
{
DebugConsole.ThrowError("Error decompressing " + filePath, e);
return null;
}
@@ -124,7 +125,24 @@ namespace Barotrauma
catch (Exception e)
{
DebugConsole.ThrowError("ERROR: deleting save file \"" + filePath + " failed.", e);
DebugConsole.ThrowError("ERROR: deleting save file \"" + filePath + "\" failed.", e);
}
//deleting a multiplayer save file -> also delete character data
if (Path.GetFullPath(Path.GetDirectoryName(filePath)).Equals(Path.GetFullPath(MultiplayerSaveFolder)))
{
string characterDataSavePath = MultiPlayerCampaign.GetCharacterDataSavePath(filePath);
if (File.Exists(characterDataSavePath))
{
try
{
File.Delete(characterDataSavePath);
}
catch (Exception e)
{
DebugConsole.ThrowError("ERROR: deleting character data file \"" + characterDataSavePath + "\" failed.", e);
}
}
}
}
@@ -274,6 +292,11 @@ namespace Barotrauma
return false;
int iNameLen = BitConverter.ToInt32(bytes, 0);
if (iNameLen > 255)
{
throw new Exception("Failed to decompress \""+sDir+"\" (file name length > 255). The file may be corrupted.");
}
bytes = new byte[sizeof(char)];
StringBuilder sb = new StringBuilder();
for (int i = 0; i < iNameLen; i++)
@@ -311,25 +334,64 @@ namespace Barotrauma
using (GZipStream zipStream = new GZipStream(inFile, CompressionMode.Decompress, true))
while (DecompressFile(sDir, zipStream, progress)) ;
}
private static void ClearFolder(string FolderName, string[] ignoredFiles = null)
public static void CopyFolder(string sourceDirName, string destDirName, bool copySubDirs)
{
// Get the subdirectories for the specified directory.
DirectoryInfo dir = new DirectoryInfo(sourceDirName);
if (!dir.Exists)
{
throw new DirectoryNotFoundException(
"Source directory does not exist or could not be found: "
+ sourceDirName);
}
DirectoryInfo[] dirs = dir.GetDirectories();
// If the destination directory doesn't exist, create it.
if (!Directory.Exists(destDirName))
{
Directory.CreateDirectory(destDirName);
}
// Get the files in the directory and copy them to the new location.
FileInfo[] files = dir.GetFiles();
foreach (FileInfo file in files)
{
string temppath = Path.Combine(destDirName, file.Name);
file.CopyTo(temppath, false);
}
// If copying subdirectories, copy them and their contents to new location.
if (copySubDirs)
{
foreach (DirectoryInfo subdir in dirs)
{
string temppath = Path.Combine(destDirName, subdir.Name);
CopyFolder(subdir.FullName, temppath, copySubDirs);
}
}
}
public static void ClearFolder(string FolderName, string[] ignoredFiles = null)
{
DirectoryInfo dir = new DirectoryInfo(FolderName);
foreach (FileInfo fi in dir.GetFiles())
{
bool ignore = false;
foreach (string ignoredFile in ignoredFiles)
if (ignoredFiles != null)
{
if (Path.GetFullPath(fi.FullName).Equals(Path.GetFullPath(ignoredFile)))
bool ignore = false;
foreach (string ignoredFile in ignoredFiles)
{
ignore = true;
break;
if (Path.GetFullPath(fi.FullName).Equals(Path.GetFullPath(ignoredFile)))
{
ignore = true;
break;
}
}
if (ignore) continue;
}
if (ignore) continue;
fi.IsReadOnly = false;
fi.Delete();
}
@@ -1,7 +1,9 @@
using Lidgren.Network;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
namespace Barotrauma
@@ -11,30 +13,40 @@ namespace Barotrauma
public T1 First { get; set; }
public T2 Second { get; set; }
public static Pair<T1, T2> Create(T1 first, T2 second)
public Pair(T1 first, T2 second)
{
Pair<T1, T2> pair = new Pair<T1, T2>();
pair.First = first;
pair.Second = second;
First = first;
Second = second;
}
}
return pair;
public class Triplet<T1, T2, T3>
{
public T1 First { get; set; }
public T2 Second { get; set; }
public T3 Third { get; set; }
public Triplet(T1 first, T2 second, T3 third)
{
First = first;
Second = second;
Third = third;
}
}
public static partial class ToolBox
{
public static bool IsProperFilenameCase(string filename)
{
char[] delimiters = { '/','\\' };
char[] delimiters = { '/', '\\' };
string[] subDirs = filename.Split(delimiters);
string originalFilename = filename;
filename = "";
for (int i=0;i<subDirs.Length-1;i++)
for (int i = 0; i < subDirs.Length - 1; i++)
{
filename += subDirs[i] + "/";
if (i == subDirs.Length - 2)
{
string[] filePaths = Directory.GetFiles(filename);
@@ -51,7 +63,7 @@ namespace Barotrauma
string[] dirPaths = Directory.GetDirectories(filename);
if (!dirPaths.Any(s => s.Equals(filename+subDirs[i+1],StringComparison.Ordinal)))
if (!dirPaths.Any(s => s.Equals(filename + subDirs[i + 1], StringComparison.Ordinal)))
{
if (dirPaths.Any(s => s.Equals(filename + subDirs[i + 1], StringComparison.OrdinalIgnoreCase)))
{
@@ -72,8 +84,8 @@ namespace Barotrauma
if (str == null || maxCharacters < 0) return null;
if (maxCharacters < 4 || str.Length <= maxCharacters) return str;
return str.Substring(0, maxCharacters-3) + "...";
return str.Substring(0, maxCharacters - 3) + "...";
}
public static string RandomSeed(int length)
@@ -122,8 +134,8 @@ namespace Barotrauma
if (n == 0 || m == 0) return 0;
for (int i = 0; i <= n; d[i, 0] = i++);
for (int j = 0; j <= m; d[0, j] = j++);
for (int i = 0; i <= n; d[i, 0] = i++) ;
for (int j = 0; j <= m; d[0, j] = j++) ;
for (int i = 1; i <= n; i++)
{
@@ -136,7 +148,7 @@ namespace Barotrauma
d[i - 1, j - 1] + cost);
}
}
return d[n, m];
}
@@ -157,47 +169,38 @@ namespace Barotrauma
}
}
private static Dictionary<string, List<string>> cachedLines = new Dictionary<string, List<string>>();
public static string GetRandomLine(string filePath)
{
try
List<string> lines;
if (cachedLines.ContainsKey(filePath))
{
string randomLine = "";
StreamReader file = new StreamReader(filePath);
var lines = File.ReadLines(filePath).ToList();
int lineCount = lines.Count;
if (lineCount == 0)
lines = cachedLines[filePath];
}
else
{
try
{
DebugConsole.ThrowError("File \"" + filePath + "\" is empty!");
file.Close();
using (StreamReader file = new StreamReader(filePath))
{
lines = File.ReadLines(filePath).ToList();
cachedLines.Add(filePath, lines);
if (lines.Count == 0)
{
DebugConsole.ThrowError("File \"" + filePath + "\" is empty!");
return "";
}
}
}
catch (Exception e)
{
DebugConsole.ThrowError("Couldn't open file \"" + filePath + "\"!", e);
return "";
}
int lineNumber = Rand.Int(lineCount, Rand.RandSync.Server);
int i = 0;
foreach (string line in lines)
{
if (i == lineNumber)
{
randomLine = line;
break;
}
i++;
}
file.Close();
return randomLine;
}
catch (Exception e)
{
DebugConsole.ThrowError("Couldn't open file \"" + filePath + "\"!", e);
return "";
}
if (lines.Count == 0) return "";
return lines[Rand.Range(0, lines.Count, Rand.RandSync.Server)];
}
/// <summary>
@@ -213,5 +216,75 @@ namespace Barotrauma
return buffer;
}
public static T SelectWeightedRandom<T>(IList<T> objects, IList<float> weights, Rand.RandSync randSync)
{
return SelectWeightedRandom(objects, weights, Rand.GetRNG(randSync));
}
public static T SelectWeightedRandom<T>(IList<T> objects, IList<float> weights, Random random)
{
if (objects.Count == 0) return default(T);
if (objects.Count != weights.Count)
{
DebugConsole.ThrowError("Error in SelectWeightedRandom, number of objects does not match the number of weights.\n" + Environment.StackTrace);
return objects[0];
}
float totalWeight = weights.Sum();
float randomNum = (float)(random.NextDouble() * totalWeight);
for (int i = 0; i < objects.Count; i++)
{
if (randomNum <= weights[i])
{
return objects[i];
}
randomNum -= weights[i];
}
return default(T);
}
/// <summary>
/// Returns a new instance of the class with all properties and fields copied.
/// </summary>
public static T CreateCopy<T>(this T source, BindingFlags flags = BindingFlags.Instance | BindingFlags.Public) where T : new() => CopyValues(source, new T(), flags);
public static T CopyValuesTo<T>(this T source, T target, BindingFlags flags = BindingFlags.Instance | BindingFlags.Public) => CopyValues(source, target, flags);
/// <summary>
/// Copies the values of the source to the destination. May not work, if the source is of higher inheritance class than the destination. Does not work with virtual properties.
/// </summary>
public static T CopyValues<T>(T source, T destination, BindingFlags flags = BindingFlags.Instance | BindingFlags.Public)
{
if (source == null)
{
throw new Exception("Failed to copy object. Source is null.");
}
if (destination == null)
{
throw new Exception("Failed to copy object. Destination is null.");
}
Type type = source.GetType();
var properties = type.GetProperties(flags);
foreach (var property in properties)
{
if (property.CanWrite)
{
property.SetValue(destination, property.GetValue(source, null), null);
}
}
var fields = type.GetFields(flags);
foreach (var field in fields)
{
field.SetValue(destination, field.GetValue(source));
}
// Check that the fields match.Uncomment to apply the test, if in doubt.
//if (fields.Any(f => { var value = f.GetValue(destination); return value == null || !value.Equals(f.GetValue(source)); }))
//{
// throw new Exception("Failed to copy some of the fields.");
//}
return destination;
}
}
}