38f1ddb...178a853: v0.8.9.1, removed content folder
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user