Renamed project folders from Subsurface to Barotrauma
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,136 @@
|
||||
using System;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
/// <summary>
|
||||
/// Mersenne Twister based random
|
||||
/// </summary>
|
||||
public sealed class MTRandom : Random
|
||||
{
|
||||
private const int N = 624;
|
||||
private const int M = 397;
|
||||
private const uint MATRIX_A = 0x9908b0dfU;
|
||||
private const uint UPPER_MASK = 0x80000000U;
|
||||
private const uint LOWER_MASK = 0x7fffffffU;
|
||||
private const uint TEMPER1 = 0x9d2c5680U;
|
||||
private const uint TEMPER2 = 0xefc60000U;
|
||||
private const int TEMPER3 = 11;
|
||||
private const int TEMPER4 = 7;
|
||||
private const int TEMPER5 = 15;
|
||||
private const int TEMPER6 = 18;
|
||||
|
||||
private UInt32[] mt;
|
||||
private int mti;
|
||||
private UInt32[] mag01;
|
||||
|
||||
private const double c_realUnitInt = 1.0 / ((double)int.MaxValue + 1.0);
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with randomized seed
|
||||
/// </summary>
|
||||
public MTRandom()
|
||||
{
|
||||
Initialize((uint)Environment.TickCount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with provided 32 bit seed
|
||||
/// </summary>
|
||||
[CLSCompliant(false)]
|
||||
public MTRandom(int seed)
|
||||
{
|
||||
Initialize((uint)Math.Abs(seed));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// (Re)initialize this instance with provided 32 bit seed
|
||||
/// </summary>
|
||||
[CLSCompliant(false)]
|
||||
private void Initialize(uint seed)
|
||||
{
|
||||
mt = new UInt32[N];
|
||||
mti = N + 1;
|
||||
mag01 = new UInt32[] { 0x0U, MATRIX_A };
|
||||
mt[0] = seed;
|
||||
for (int i = 1; i < N; i++)
|
||||
mt[i] = (UInt32)(1812433253 * (mt[i - 1] ^ (mt[i - 1] >> 30)) + i);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates a random value from UInt32.MinValue to UInt32.MaxValue, inclusively
|
||||
/// </summary>
|
||||
[CLSCompliant(false)]
|
||||
private uint NextUInt32()
|
||||
{
|
||||
UInt32 y;
|
||||
if (mti >= N)
|
||||
{
|
||||
GenRandAll();
|
||||
mti = 0;
|
||||
}
|
||||
y = mt[mti++];
|
||||
y ^= (y >> TEMPER3);
|
||||
y ^= (y << TEMPER4) & TEMPER1;
|
||||
y ^= (y << TEMPER5) & TEMPER2;
|
||||
y ^= (y >> TEMPER6);
|
||||
return y;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates a random value that is greater or equal than 0 and less than Int32.MaxValue
|
||||
/// </summary>
|
||||
public override int Next()
|
||||
{
|
||||
var retval = (int)(0x7FFFFFFF & NextUInt32());
|
||||
if (retval == 0x7FFFFFFF)
|
||||
return NextInt32();
|
||||
return retval;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a random value is greater or equal than 0 and less than maxValue
|
||||
/// </summary>
|
||||
public override int Next(int maxValue)
|
||||
{
|
||||
return (int)(NextDouble() * maxValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates a random value greater or equal than 0 and less or equal than Int32.MaxValue (inclusively)
|
||||
/// </summary>
|
||||
public int NextInt32()
|
||||
{
|
||||
return (int)(0x7FFFFFFF & NextUInt32());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns random value larger or equal to 0.0 and less than 1.0
|
||||
/// </summary>
|
||||
public override double NextDouble()
|
||||
{
|
||||
return c_realUnitInt * NextInt32();
|
||||
}
|
||||
|
||||
private void GenRandAll()
|
||||
{
|
||||
int kk = 1;
|
||||
UInt32 y;
|
||||
UInt32 p;
|
||||
y = mt[0] & UPPER_MASK;
|
||||
do
|
||||
{
|
||||
p = mt[kk];
|
||||
mt[kk - 1] = mt[kk + (M - 1)] ^ ((y | (p & LOWER_MASK)) >> 1) ^ mag01[p & 1];
|
||||
y = p & UPPER_MASK;
|
||||
} while (++kk < N - M + 1);
|
||||
do
|
||||
{
|
||||
p = mt[kk];
|
||||
mt[kk - 1] = mt[kk + (M - N - 1)] ^ ((y | (p & LOWER_MASK)) >> 1) ^ mag01[p & 1];
|
||||
y = p & UPPER_MASK;
|
||||
} while (++kk < N);
|
||||
p = mt[0];
|
||||
mt[N - 1] = mt[M - 1] ^ ((y | (p & LOWER_MASK)) >> 1) ^ mag01[p & 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,550 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
static class MathUtils
|
||||
{
|
||||
public static Vector2 SmoothStep(Vector2 v1, Vector2 v2, float amount)
|
||||
{
|
||||
return new Vector2(
|
||||
MathHelper.SmoothStep(v1.X, v2.X, amount),
|
||||
MathHelper.SmoothStep(v1.Y, v2.Y, amount));
|
||||
}
|
||||
|
||||
public static float Round(float value, float div)
|
||||
{
|
||||
return (value < 0.0f) ?
|
||||
(float)Math.Ceiling(value / div) * div :
|
||||
(float)Math.Floor(value / div) * div;
|
||||
}
|
||||
|
||||
public static float RoundTowardsClosest(float value, float div)
|
||||
{
|
||||
return (float)Math.Round(value / div) * div;
|
||||
}
|
||||
|
||||
public static float VectorToAngle(Vector2 vector)
|
||||
{
|
||||
return (float)Math.Atan2(vector.Y, vector.X);
|
||||
}
|
||||
|
||||
public static bool IsValid(float value)
|
||||
{
|
||||
return (!float.IsInfinity(value) && !float.IsNaN(value));
|
||||
}
|
||||
|
||||
public static bool IsValid(Vector2 vector)
|
||||
{
|
||||
return (IsValid(vector.X) && IsValid(vector.Y));
|
||||
}
|
||||
|
||||
public static Rectangle ExpandRect(Rectangle rect, int amount)
|
||||
{
|
||||
return new Rectangle(rect.X - amount, rect.Y + amount, rect.Width + amount * 2, rect.Height + amount * 2);
|
||||
}
|
||||
|
||||
public static int VectorOrientation(Vector2 p1, Vector2 p2, Vector2 p)
|
||||
{
|
||||
// Determinant
|
||||
float Orin = (p2.X - p1.X) * (p.Y - p1.Y) - (p.X - p1.X) * (p2.Y - p1.Y);
|
||||
|
||||
if (Orin > 0)
|
||||
return -1; // (* Orientation is to the left-hand side *)
|
||||
if (Orin < 0)
|
||||
return 1; // (* Orientation is to the right-hand side *)
|
||||
|
||||
return 0; // (* Orientation is neutral aka collinear *)
|
||||
}
|
||||
|
||||
|
||||
public static float CurveAngle(float from, float to, float step)
|
||||
{
|
||||
|
||||
from = WrapAngleTwoPi(from);
|
||||
to = WrapAngleTwoPi(to);
|
||||
|
||||
if (Math.Abs(from - to) < MathHelper.Pi)
|
||||
{
|
||||
// The simple case - a straight lerp will do.
|
||||
return MathHelper.Lerp(from, to, step);
|
||||
}
|
||||
|
||||
// If we get here we have the more complex case.
|
||||
// First, increment the lesser value to be greater.
|
||||
if (from < to)
|
||||
from += MathHelper.TwoPi;
|
||||
else
|
||||
to += MathHelper.TwoPi;
|
||||
|
||||
float retVal = MathHelper.Lerp(from, to, step);
|
||||
|
||||
// Now ensure the return value is between 0 and 2pi
|
||||
if (retVal >= MathHelper.TwoPi)
|
||||
retVal -= MathHelper.TwoPi;
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// wrap the angle between 0.0f and 2pi
|
||||
/// </summary>
|
||||
public static float WrapAngleTwoPi(float angle)
|
||||
{
|
||||
if (float.IsInfinity(angle) || float.IsNegativeInfinity(angle) || float.IsNaN(angle))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
while (angle < 0)
|
||||
angle += MathHelper.TwoPi;
|
||||
while (angle >= MathHelper.TwoPi)
|
||||
angle -= MathHelper.TwoPi;
|
||||
|
||||
return angle;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// wrap the angle between -pi and pi
|
||||
/// </summary>
|
||||
public static float WrapAnglePi(float angle)
|
||||
{
|
||||
if (float.IsInfinity(angle) || float.IsNegativeInfinity(angle) || float.IsNaN(angle))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
// Ensure that -pi <= angle < pi for both "from" and "to"
|
||||
while (angle < -MathHelper.Pi)
|
||||
angle += MathHelper.TwoPi;
|
||||
while (angle >= MathHelper.Pi)
|
||||
angle -= MathHelper.TwoPi;
|
||||
|
||||
return angle;
|
||||
}
|
||||
|
||||
public static float GetShortestAngle(float from, float to)
|
||||
{
|
||||
// Ensure that 0 <= angle < 2pi for both "from" and "to"
|
||||
from = WrapAngleTwoPi(from);
|
||||
to = WrapAngleTwoPi(to);
|
||||
|
||||
if (Math.Abs(from - to) < MathHelper.Pi)
|
||||
{
|
||||
return to - from;
|
||||
}
|
||||
|
||||
// If we get here we have the more complex case.
|
||||
// First, increment the lesser value to be greater.
|
||||
if (from < to)
|
||||
from += MathHelper.TwoPi;
|
||||
else
|
||||
to += MathHelper.TwoPi;
|
||||
|
||||
return to - from;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// solves the angle opposite to side a (parameters: lengths of each side)
|
||||
/// </summary>
|
||||
public static float SolveTriangleSSS(float a, float b, float c)
|
||||
{
|
||||
float A = (float)Math.Acos((b * b + c * c - a * a) / (2 * b * c));
|
||||
|
||||
if (float.IsNaN(A)) A = 1.0f;
|
||||
|
||||
return A;
|
||||
}
|
||||
|
||||
public static byte AngleToByte(float angle)
|
||||
{
|
||||
angle = WrapAngleTwoPi(angle);
|
||||
angle = angle * (255.0f / MathHelper.TwoPi);
|
||||
return Convert.ToByte(angle);
|
||||
}
|
||||
|
||||
public static float ByteToAngle(byte b)
|
||||
{
|
||||
float angle = (float)b;
|
||||
angle = angle * (MathHelper.TwoPi / 255.0f);
|
||||
return angle;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// check whether line from a to b is intersecting with line from c to b
|
||||
/// </summary>
|
||||
public static bool LinesIntersect(Vector2 a, Vector2 b, Vector2 c, Vector2 d)
|
||||
{
|
||||
float denominator = ((b.X - a.X) * (d.Y - c.Y)) - ((b.Y - a.Y) * (d.X - c.X));
|
||||
float numerator1 = ((a.Y - c.Y) * (d.X - c.X)) - ((a.X - c.X) * (d.Y - c.Y));
|
||||
float numerator2 = ((a.Y - c.Y) * (b.X - a.X)) - ((a.X - c.X) * (b.Y - a.Y));
|
||||
|
||||
if (denominator == 0) return numerator1 == 0 && numerator2 == 0;
|
||||
|
||||
float r = numerator1 / denominator;
|
||||
float s = numerator2 / denominator;
|
||||
|
||||
return (r >= 0 && r <= 1) && (s >= 0 && s <= 1);
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
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;
|
||||
|
||||
Vector2 c = b1 - a1;
|
||||
float t = (c.X * d.Y - c.Y * d.X) / bDotDPerp;
|
||||
if (t < 0 || t > 1) return null;
|
||||
|
||||
float u = (c.X * b.Y - c.Y * b.X) / bDotDPerp;
|
||||
if (u < 0 || u > 1) return null;
|
||||
|
||||
return a1 + t * b;
|
||||
}
|
||||
|
||||
public static Vector2? GetAxisAlignedLineIntersection(Vector2 a1, Vector2 a2, Vector2 axisAligned1, Vector2 axisAligned2, bool isHorizontal)
|
||||
{
|
||||
if (!isHorizontal)
|
||||
{
|
||||
if (Math.Sign(a1.X - axisAligned1.X) == Math.Sign(a2.X - axisAligned1.X))
|
||||
return null;
|
||||
|
||||
float s = (a2.Y - a1.Y) / (a2.X - a1.X);
|
||||
float y = a1.Y + (axisAligned1.X - a1.X) * s;
|
||||
|
||||
if (axisAligned1.Y < axisAligned2.Y)
|
||||
{
|
||||
if (y < axisAligned1.Y) return null;
|
||||
if (y > axisAligned2.Y) return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (y > axisAligned1.Y) return null;
|
||||
if (y < axisAligned2.Y) return null;
|
||||
}
|
||||
|
||||
return new Vector2(axisAligned1.X, y);
|
||||
}
|
||||
else //horizontal line
|
||||
{
|
||||
if (Math.Sign(a1.Y - axisAligned1.Y) == Math.Sign(a2.Y - axisAligned1.Y))
|
||||
return null;
|
||||
|
||||
float s = (a2.X - a1.X) / (a2.Y - a1.Y);
|
||||
float x = a1.X + (axisAligned1.Y - a1.Y) * s;
|
||||
|
||||
if (axisAligned1.X < axisAligned2.X)
|
||||
{
|
||||
if (x < axisAligned1.X) return null;
|
||||
if (x > axisAligned2.X) return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (x > axisAligned1.X) return null;
|
||||
if (x < axisAligned2.X) return null;
|
||||
}
|
||||
|
||||
return new Vector2(x, axisAligned1.Y);
|
||||
}
|
||||
}
|
||||
|
||||
public static Vector2? GetLineRectangleIntersection(Vector2 a1, Vector2 a2, Rectangle rect)
|
||||
{
|
||||
Vector2? intersection = GetAxisAlignedLineIntersection(a1, a2,
|
||||
new Vector2(rect.X, rect.Y),
|
||||
new Vector2(rect.Right, rect.Y),
|
||||
true);
|
||||
|
||||
if (intersection != null) return intersection;
|
||||
|
||||
intersection = GetAxisAlignedLineIntersection(a1, a2,
|
||||
new Vector2(rect.X, rect.Y-rect.Height),
|
||||
new Vector2(rect.Right, rect.Y-rect.Height),
|
||||
true);
|
||||
|
||||
if (intersection != null) return intersection;
|
||||
|
||||
intersection = GetAxisAlignedLineIntersection(a1, a2,
|
||||
new Vector2(rect.X, rect.Y),
|
||||
new Vector2(rect.X, rect.Y - rect.Height),
|
||||
false);
|
||||
|
||||
if (intersection != null) return intersection;
|
||||
|
||||
return GetAxisAlignedLineIntersection(a1, a2,
|
||||
new Vector2(rect.Right, rect.Y),
|
||||
new Vector2(rect.Right, rect.Y - rect.Height),
|
||||
false);
|
||||
}
|
||||
|
||||
public static List<Vector2> GetLineRectangleIntersections(Vector2 a1, Vector2 a2, Rectangle rect)
|
||||
{
|
||||
List<Vector2> intersections = new List<Vector2>();
|
||||
|
||||
Vector2? intersection = GetAxisAlignedLineIntersection(a1, a2,
|
||||
new Vector2(rect.X, rect.Y),
|
||||
new Vector2(rect.Right, rect.Y),
|
||||
true);
|
||||
|
||||
if (intersection != null) intersections.Add((Vector2)intersection);
|
||||
|
||||
intersection = GetAxisAlignedLineIntersection(a1, a2,
|
||||
new Vector2(rect.X, rect.Y - rect.Height),
|
||||
new Vector2(rect.Right, rect.Y - rect.Height),
|
||||
true);
|
||||
|
||||
if (intersection != null) intersections.Add((Vector2)intersection);
|
||||
|
||||
intersection = GetAxisAlignedLineIntersection(a1, a2,
|
||||
new Vector2(rect.X, rect.Y),
|
||||
new Vector2(rect.X, rect.Y - rect.Height),
|
||||
false);
|
||||
|
||||
if (intersection != null) intersections.Add((Vector2)intersection);
|
||||
|
||||
intersection = GetAxisAlignedLineIntersection(a1, a2,
|
||||
new Vector2(rect.Right, rect.Y),
|
||||
new Vector2(rect.Right, rect.Y - rect.Height),
|
||||
false);
|
||||
|
||||
if (intersection != null) intersections.Add((Vector2)intersection);
|
||||
|
||||
return intersections;
|
||||
}
|
||||
|
||||
public static float LineToPointDistance(Vector2 lineA, Vector2 lineB, Vector2 point)
|
||||
{
|
||||
float xDiff = lineB.X - lineA.X;
|
||||
float yDiff = lineB.Y - lineA.Y;
|
||||
|
||||
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;
|
||||
int halfHeight = rect.Height / 2;
|
||||
|
||||
if (xDist > (halfWidth + radius)) { return false; }
|
||||
if (yDist > (halfHeight + radius)) { return false; }
|
||||
|
||||
|
||||
if (xDist <= (halfWidth)) { return true; }
|
||||
if (yDist <= (halfHeight)) { return true; }
|
||||
|
||||
float distSqX = xDist - halfWidth;
|
||||
float distSqY = yDist - halfHeight;
|
||||
|
||||
return (distSqX * distSqX + distSqY * distSqY <= (radius * radius));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// divide a convex hull into triangles
|
||||
/// </summary>
|
||||
/// <returns>List of triangle vertices (sorted counter-clockwise)</returns>
|
||||
public static List<Vector2[]> TriangulateConvexHull(List<Vector2> vertices, Vector2 center)
|
||||
{
|
||||
List<Vector2[]> triangles = new List<Vector2[]>();
|
||||
|
||||
int triangleCount = vertices.Count - 2;
|
||||
|
||||
vertices.Sort(new CompareCCW(center));
|
||||
|
||||
int lastIndex = 1;
|
||||
for (int i = 0; i < triangleCount; i++)
|
||||
{
|
||||
Vector2[] triangleVertices = new Vector2[3];
|
||||
triangleVertices[0] = vertices[0];
|
||||
int k = 1;
|
||||
for (int j = lastIndex; j <= lastIndex + 1; j++)
|
||||
{
|
||||
triangleVertices[k] = vertices[j];
|
||||
k++;
|
||||
}
|
||||
lastIndex += 1;
|
||||
|
||||
triangles.Add(triangleVertices);
|
||||
}
|
||||
|
||||
return triangles;
|
||||
}
|
||||
|
||||
public static List<Vector2> GiftWrap(List<Vector2> points)
|
||||
{
|
||||
if (points.Count == 0) return points;
|
||||
|
||||
Vector2 leftMost = points[0];
|
||||
foreach (Vector2 point in points)
|
||||
{
|
||||
if (point.X < leftMost.X) leftMost = point;
|
||||
}
|
||||
|
||||
List<Vector2> wrappedPoints = new List<Vector2>();
|
||||
|
||||
Vector2 currPoint = leftMost;
|
||||
Vector2 endPoint;
|
||||
do
|
||||
{
|
||||
wrappedPoints.Add(currPoint);
|
||||
endPoint = points[0];
|
||||
|
||||
for (int i = 1; i < points.Count; i++)
|
||||
{
|
||||
if (points[i] == currPoint) continue;
|
||||
if (currPoint == endPoint ||
|
||||
MathUtils.VectorOrientation(currPoint, endPoint, points[i]) == -1)
|
||||
{
|
||||
endPoint = points[i];
|
||||
}
|
||||
}
|
||||
|
||||
currPoint = endPoint;
|
||||
|
||||
}
|
||||
while (endPoint != leftMost);
|
||||
|
||||
return wrappedPoints;
|
||||
}
|
||||
|
||||
public static List<Vector2[]> GenerateJaggedLine(Vector2 start, Vector2 end, int generations, float offsetAmount)
|
||||
{
|
||||
List<Vector2[]> segments = new List<Vector2[]>();
|
||||
|
||||
segments.Add(new Vector2[] { start, end });
|
||||
|
||||
for (int n = 0; n < generations; n++)
|
||||
{
|
||||
for (int i = 0; i < segments.Count; i++)
|
||||
{
|
||||
Vector2 startSegment = segments[i][0];
|
||||
Vector2 endSegment = segments[i][1];
|
||||
|
||||
segments.RemoveAt(i);
|
||||
|
||||
Vector2 midPoint = (startSegment + endSegment) / 2.0f;
|
||||
|
||||
Vector2 normal = Vector2.Normalize(endSegment - startSegment);
|
||||
normal = new Vector2(-normal.Y, normal.X);
|
||||
midPoint += normal * Rand.Range(-offsetAmount, offsetAmount, false);
|
||||
|
||||
segments.Insert(i, new Vector2[] { startSegment, midPoint });
|
||||
segments.Insert(i + 1, new Vector2[] { midPoint, endSegment });
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
return segments;
|
||||
}
|
||||
|
||||
// Returns the human-readable file size for an arbitrary, 64-bit file size
|
||||
// The default format is "0.### XB", e.g. "4.2 KB" or "1.434 GB"
|
||||
public static string GetBytesReadable(long i)
|
||||
{
|
||||
// Get absolute value
|
||||
long absolute_i = (i < 0 ? -i : i);
|
||||
// Determine the suffix and readable value
|
||||
string suffix;
|
||||
double readable;
|
||||
if (absolute_i >= 0x1000000000000000) // Exabyte
|
||||
{
|
||||
suffix = "EB";
|
||||
readable = (i >> 50);
|
||||
}
|
||||
else if (absolute_i >= 0x4000000000000) // Petabyte
|
||||
{
|
||||
suffix = "PB";
|
||||
readable = (i >> 40);
|
||||
}
|
||||
else if (absolute_i >= 0x10000000000) // Terabyte
|
||||
{
|
||||
suffix = "TB";
|
||||
readable = (i >> 30);
|
||||
}
|
||||
else if (absolute_i >= 0x40000000) // Gigabyte
|
||||
{
|
||||
suffix = "GB";
|
||||
readable = (i >> 20);
|
||||
}
|
||||
else if (absolute_i >= 0x100000) // Megabyte
|
||||
{
|
||||
suffix = "MB";
|
||||
readable = (i >> 10);
|
||||
}
|
||||
else if (absolute_i >= 0x400) // Kilobyte
|
||||
{
|
||||
suffix = "KB";
|
||||
readable = i;
|
||||
}
|
||||
else
|
||||
{
|
||||
return i.ToString("0 B"); // Byte
|
||||
}
|
||||
// Divide by 1024 to get fractional value
|
||||
readable = (readable / 1024);
|
||||
// Return formatted number with suffix
|
||||
return readable.ToString("0.# ") + suffix;
|
||||
}
|
||||
}
|
||||
|
||||
class CompareCCW : IComparer<Vector2>
|
||||
{
|
||||
private Vector2 center;
|
||||
|
||||
public CompareCCW(Vector2 center)
|
||||
{
|
||||
this.center = center;
|
||||
}
|
||||
public int Compare(Vector2 a, Vector2 b)
|
||||
{
|
||||
return Compare(a, b, center);
|
||||
}
|
||||
|
||||
public static int Compare(Vector2 a, Vector2 b, Vector2 center)
|
||||
{
|
||||
if (a == b) return 0;
|
||||
if (a.X - center.X >= 0 && b.X - center.X < 0) return -1;
|
||||
if (a.X - center.X < 0 && b.X - center.X >= 0) return 1;
|
||||
if (a.X - center.X == 0 && b.X - center.X == 0)
|
||||
{
|
||||
if (a.Y - center.Y >= 0 || b.Y - center.Y >= 0) return Math.Sign(b.Y - a.Y);
|
||||
return Math.Sign(a.Y - b.Y);
|
||||
}
|
||||
|
||||
// compute the cross product of vectors (center -> a) x (center -> b)
|
||||
float det = (a.X - center.X) * (b.Y - center.Y) - (b.X - center.X) * (a.Y - center.Y);
|
||||
if (det < 0) return -1;
|
||||
if (det > 0) return 1;
|
||||
|
||||
// points a and b are on the same line from the center
|
||||
// check which point is closer to the center
|
||||
float d1 = (a.X - center.X) * (a.X - center.X) + (a.Y - center.Y) * (a.Y - center.Y);
|
||||
float d2 = (b.X - center.X) * (b.X - center.X) + (b.Y - center.Y) * (b.Y - center.Y);
|
||||
return Math.Sign(d2 - d1);
|
||||
}
|
||||
}
|
||||
|
||||
class CompareSegmentPointCW : IComparer<Lights.SegmentPoint>
|
||||
{
|
||||
private Vector2 center;
|
||||
|
||||
public CompareSegmentPointCW(Vector2 center)
|
||||
{
|
||||
this.center = center;
|
||||
}
|
||||
public int Compare(Lights.SegmentPoint a, Lights.SegmentPoint b)
|
||||
{
|
||||
return -CompareCCW.Compare(a.WorldPos, b.WorldPos, center);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
static class Rand
|
||||
{
|
||||
private static Random localRandom = new Random();
|
||||
private static Random syncedRandom = new MTRandom();
|
||||
|
||||
public static void SetSyncedSeed(int seed)
|
||||
{
|
||||
syncedRandom = new MTRandom(seed);
|
||||
}
|
||||
|
||||
public static float Range(float minimum, float maximum, bool local = true)
|
||||
{
|
||||
return (float)(local ? localRandom : syncedRandom).NextDouble() * (maximum - minimum) + minimum;
|
||||
}
|
||||
|
||||
public static int Range(int minimum, int maximum, bool local = true)
|
||||
{
|
||||
return (local ? localRandom : syncedRandom).Next(maximum - minimum) + minimum;
|
||||
}
|
||||
|
||||
public static int Int(int max = int.MaxValue, bool local = true)
|
||||
{
|
||||
return (local ? localRandom : syncedRandom).Next(max);
|
||||
}
|
||||
|
||||
public static Vector2 Vector(float length = 1.0f, bool local = true)
|
||||
{
|
||||
Vector2 randomVector = new Vector2(Range(-1.0f, 1.0f, local), Range(-1.0f, 1.0f, local));
|
||||
|
||||
if (randomVector == Vector2.Zero) return new Vector2(0.0f, length);
|
||||
|
||||
return Vector2.Normalize(randomVector) * length;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,315 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Text;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
public class SaveUtil
|
||||
{
|
||||
public static string SaveFolder = "Data"+Path.DirectorySeparatorChar+"Saves";
|
||||
|
||||
public delegate void ProgressDelegate(string sMessage);
|
||||
|
||||
public static string TempPath
|
||||
{
|
||||
get { return Path.Combine(SaveFolder, "temp"); }
|
||||
}
|
||||
|
||||
public static void SaveGame(string fileName)
|
||||
{
|
||||
fileName = Path.Combine(SaveFolder, fileName);
|
||||
|
||||
string tempPath = Path.Combine(SaveFolder, "temp");
|
||||
|
||||
Directory.CreateDirectory(tempPath);
|
||||
try
|
||||
{
|
||||
ClearFolder(tempPath, new string[] { GameMain.GameSession.Submarine.FilePath });
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (Submarine.MainSub != null && Submarine.Loaded.Contains(Submarine.MainSub))
|
||||
{
|
||||
Submarine.MainSub.FilePath = Path.Combine(tempPath, Submarine.MainSub.Name + ".sub");
|
||||
Submarine.MainSub.SaveAs(Submarine.MainSub.FilePath);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Error saving submarine", e);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
GameMain.GameSession.Save(Path.Combine(tempPath, "gamesession.xml"));
|
||||
}
|
||||
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Error saving gamesession", e);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
CompressDirectory(tempPath, fileName+".save", null);
|
||||
}
|
||||
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Error compressing save file", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void LoadGame(string fileName)
|
||||
{
|
||||
string filePath = Path.Combine(SaveFolder, fileName+".save");
|
||||
|
||||
DecompressToDirectory(filePath, TempPath, null);
|
||||
|
||||
XDocument doc = ToolBox.TryLoadXml(Path.Combine(TempPath, "gamesession.xml"));
|
||||
|
||||
string subPath = Path.Combine(TempPath, ToolBox.GetAttributeString(doc.Root, "submarine", ""))+".sub";
|
||||
Submarine selectedMap = new Submarine(subPath, "");// Submarine.Load();
|
||||
GameMain.GameSession = new GameSession(selectedMap, fileName, doc);
|
||||
|
||||
//Directory.Delete(tempPath, true);
|
||||
}
|
||||
|
||||
public static XDocument LoadGameSessionDoc(string fileName)
|
||||
{
|
||||
string filePath = Path.Combine(SaveFolder, fileName + ".save");
|
||||
|
||||
string tempPath = Path.Combine(SaveFolder, "temp");
|
||||
|
||||
try
|
||||
{
|
||||
DecompressToDirectory(filePath, tempPath, null);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return ToolBox.TryLoadXml(Path.Combine(tempPath, "gamesession.xml"));
|
||||
}
|
||||
|
||||
public static void DeleteSave(string fileName)
|
||||
{
|
||||
fileName = Path.Combine(SaveFolder, fileName + ".save");
|
||||
|
||||
try
|
||||
{
|
||||
File.Delete(fileName);
|
||||
}
|
||||
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("ERROR: deleting save file \""+fileName+" failed.", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static string[] GetSaveFiles()
|
||||
{
|
||||
if (!Directory.Exists(SaveFolder))
|
||||
{
|
||||
DebugConsole.ThrowError("Save folder \"" + SaveFolder + " not found! Attempting to create a new folder");
|
||||
try
|
||||
{
|
||||
Directory.CreateDirectory(SaveFolder);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to create the folder \"" + SaveFolder + "\"!", e);
|
||||
}
|
||||
}
|
||||
|
||||
string[] files = Directory.GetFiles(SaveFolder, "*.save");
|
||||
|
||||
for (int i = 0; i < files.Length; i++)
|
||||
{
|
||||
files[i] = Path.GetFileNameWithoutExtension(files[i]);
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
public static string CreateSavePath(string fileName="Save")
|
||||
{
|
||||
if (!Directory.Exists(SaveFolder))
|
||||
{
|
||||
DebugConsole.ThrowError("Save folder \""+SaveFolder+"\" not found. Created new folder");
|
||||
Directory.CreateDirectory(SaveFolder);
|
||||
}
|
||||
|
||||
string extension = ".save";
|
||||
string pathWithoutExtension = Path.Combine(SaveFolder, fileName);
|
||||
|
||||
int i = 0;
|
||||
while (File.Exists(pathWithoutExtension + " " + i + extension))
|
||||
{
|
||||
i++;
|
||||
}
|
||||
|
||||
return fileName + " " + i;
|
||||
}
|
||||
|
||||
public static void CompressStringToFile(string fileName, string value)
|
||||
{
|
||||
// A.
|
||||
// Write string to temporary file.
|
||||
string temp = Path.GetTempFileName();
|
||||
File.WriteAllText(temp, value);
|
||||
|
||||
// B.
|
||||
// Read file into byte array buffer.
|
||||
byte[] b;
|
||||
using (FileStream f = new FileStream(temp, FileMode.Open))
|
||||
{
|
||||
b = new byte[f.Length];
|
||||
f.Read(b, 0, (int)f.Length);
|
||||
}
|
||||
|
||||
// C.
|
||||
// Use GZipStream to write compressed bytes to target file.
|
||||
using (FileStream f2 = new FileStream(fileName, FileMode.Create))
|
||||
using (GZipStream gz = new GZipStream(f2, CompressionMode.Compress, false))
|
||||
{
|
||||
gz.Write(b, 0, b.Length);
|
||||
}
|
||||
}
|
||||
|
||||
public static Stream DecompressFiletoStream(string fileName)
|
||||
{
|
||||
if (!File.Exists(fileName))
|
||||
{
|
||||
DebugConsole.ThrowError("File \""+fileName+" doesn't exist!");
|
||||
return null;
|
||||
}
|
||||
|
||||
using (FileStream originalFileStream = new FileStream(fileName, FileMode.Open))
|
||||
{
|
||||
MemoryStream decompressedFileStream = new MemoryStream();
|
||||
|
||||
using (GZipStream decompressionStream = new GZipStream(originalFileStream, CompressionMode.Decompress))
|
||||
{
|
||||
decompressionStream.CopyTo(decompressedFileStream);
|
||||
return decompressedFileStream;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void CompressFile(string sDir, string sRelativePath, GZipStream zipStream)
|
||||
{
|
||||
//Compress file name
|
||||
char[] chars = sRelativePath.ToCharArray();
|
||||
zipStream.Write(BitConverter.GetBytes(chars.Length), 0, sizeof(int));
|
||||
foreach (char c in chars)
|
||||
zipStream.Write(BitConverter.GetBytes(c), 0, sizeof(char));
|
||||
|
||||
//Compress file content
|
||||
byte[] bytes = File.ReadAllBytes(Path.Combine(sDir, sRelativePath));
|
||||
zipStream.Write(BitConverter.GetBytes(bytes.Length), 0, sizeof(int));
|
||||
zipStream.Write(bytes, 0, bytes.Length);
|
||||
}
|
||||
|
||||
public static bool DecompressFile(string sDir, GZipStream zipStream, ProgressDelegate progress)
|
||||
{
|
||||
//Decompress file name
|
||||
byte[] bytes = new byte[sizeof(int)];
|
||||
int Readed = zipStream.Read(bytes, 0, sizeof(int));
|
||||
if (Readed < sizeof(int))
|
||||
return false;
|
||||
|
||||
int iNameLen = BitConverter.ToInt32(bytes, 0);
|
||||
bytes = new byte[sizeof(char)];
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < iNameLen; i++)
|
||||
{
|
||||
zipStream.Read(bytes, 0, sizeof(char));
|
||||
char c = BitConverter.ToChar(bytes, 0);
|
||||
sb.Append(c);
|
||||
}
|
||||
string sFileName = sb.ToString();
|
||||
if (progress != null)
|
||||
progress(sFileName);
|
||||
|
||||
//Decompress file content
|
||||
bytes = new byte[sizeof(int)];
|
||||
zipStream.Read(bytes, 0, sizeof(int));
|
||||
int iFileLen = BitConverter.ToInt32(bytes, 0);
|
||||
|
||||
bytes = new byte[iFileLen];
|
||||
zipStream.Read(bytes, 0, bytes.Length);
|
||||
|
||||
string sFilePath = Path.Combine(sDir, sFileName);
|
||||
string sFinalDir = Path.GetDirectoryName(sFilePath);
|
||||
if (!Directory.Exists(sFinalDir))
|
||||
Directory.CreateDirectory(sFinalDir);
|
||||
|
||||
using (FileStream outFile = new FileStream(sFilePath, FileMode.Create, FileAccess.Write, FileShare.None))
|
||||
outFile.Write(bytes, 0, iFileLen);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void CompressDirectory(string sInDir, string sOutFile, ProgressDelegate progress)
|
||||
{
|
||||
string[] sFiles = Directory.GetFiles(sInDir, "*.*", SearchOption.AllDirectories);
|
||||
int iDirLen = sInDir[sInDir.Length - 1] == Path.DirectorySeparatorChar ? sInDir.Length : sInDir.Length + 1;
|
||||
|
||||
using (FileStream outFile = new FileStream(sOutFile, FileMode.Create, FileAccess.Write, FileShare.None))
|
||||
using (GZipStream str = new GZipStream(outFile, CompressionMode.Compress))
|
||||
foreach (string sFilePath in sFiles)
|
||||
{
|
||||
string sRelativePath = sFilePath.Substring(iDirLen);
|
||||
if (progress != null)
|
||||
progress(sRelativePath);
|
||||
CompressFile(sInDir, sRelativePath, str);
|
||||
}
|
||||
}
|
||||
|
||||
public static void DecompressToDirectory(string sCompressedFile, string sDir, ProgressDelegate progress)
|
||||
{
|
||||
using (FileStream inFile = new FileStream(sCompressedFile, FileMode.Open, FileAccess.Read, FileShare.None))
|
||||
using (GZipStream zipStream = new GZipStream(inFile, CompressionMode.Decompress, true))
|
||||
while (DecompressFile(sDir, zipStream, progress)) ;
|
||||
}
|
||||
|
||||
private 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 (Path.GetFullPath(fi.FullName).Equals(Path.GetFullPath(ignoredFile)))
|
||||
{
|
||||
ignore = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ignore) continue;
|
||||
|
||||
fi.IsReadOnly = false;
|
||||
fi.Delete();
|
||||
}
|
||||
|
||||
foreach (DirectoryInfo di in dir.GetDirectories())
|
||||
{
|
||||
ClearFolder(di.FullName, ignoredFiles);
|
||||
di.Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
using System.IO;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Color = Microsoft.Xna.Framework.Color;
|
||||
using System;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
/// <summary>
|
||||
/// Based on http://jakepoz.com/jake_poznanski__background_load_xna.html
|
||||
/// </summary>
|
||||
public static class TextureLoader
|
||||
{
|
||||
static TextureLoader()
|
||||
{
|
||||
|
||||
BlendColorBlendState = new BlendState
|
||||
{
|
||||
ColorDestinationBlend = Blend.Zero,
|
||||
ColorWriteChannels = ColorWriteChannels.Red | ColorWriteChannels.Green | ColorWriteChannels.Blue,
|
||||
AlphaDestinationBlend = Blend.Zero,
|
||||
AlphaSourceBlend = Blend.SourceAlpha,
|
||||
ColorSourceBlend = Blend.SourceAlpha
|
||||
};
|
||||
|
||||
BlendAlphaBlendState = new BlendState
|
||||
{
|
||||
ColorWriteChannels = ColorWriteChannels.Alpha,
|
||||
AlphaDestinationBlend = Blend.Zero,
|
||||
ColorDestinationBlend = Blend.Zero,
|
||||
AlphaSourceBlend = Blend.One,
|
||||
ColorSourceBlend = Blend.One
|
||||
};
|
||||
}
|
||||
|
||||
public static void Init(GraphicsDevice graphicsDevice, bool needsBmp = false)
|
||||
{
|
||||
_graphicsDevice = graphicsDevice;
|
||||
_needsBmp = needsBmp;
|
||||
_spriteBatch = new SpriteBatch(_graphicsDevice);
|
||||
}
|
||||
|
||||
public static Texture2D FromFile(string path, bool preMultiplyAlpha = true)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
using (Stream fileStream = File.OpenRead(path))
|
||||
{
|
||||
var texture = Texture2D.FromStream(_graphicsDevice, fileStream);
|
||||
texture = PreMultiplyAlpha(texture);
|
||||
return texture;
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Loading texture \""+path+"\" failed!", e);
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static Texture2D PreMultiplyAlpha(Texture2D texture)
|
||||
{
|
||||
// Setup a render target to hold our final texture which will have premulitplied alpha values
|
||||
using (RenderTarget2D renderTarget = new RenderTarget2D(_graphicsDevice, texture.Width, texture.Height))
|
||||
{
|
||||
Viewport viewportBackup = _graphicsDevice.Viewport;
|
||||
_graphicsDevice.SetRenderTarget(renderTarget);
|
||||
_graphicsDevice.Clear(Color.Black);
|
||||
|
||||
// Multiply each color by the source alpha, and write in just the color values into the final texture
|
||||
_spriteBatch.Begin(SpriteSortMode.Immediate, BlendColorBlendState);
|
||||
_spriteBatch.Draw(texture, texture.Bounds, Color.White);
|
||||
_spriteBatch.End();
|
||||
|
||||
// Now copy over the alpha values from the source texture to the final one, without multiplying them
|
||||
_spriteBatch.Begin(SpriteSortMode.Immediate, BlendAlphaBlendState);
|
||||
_spriteBatch.Draw(texture, texture.Bounds, Color.White);
|
||||
_spriteBatch.End();
|
||||
|
||||
// Release the GPU back to drawing to the screen
|
||||
_graphicsDevice.SetRenderTarget(null);
|
||||
_graphicsDevice.Viewport = viewportBackup;
|
||||
|
||||
// Store data from render target because the RenderTarget2D is volatile
|
||||
Color[] data = new Color[texture.Width * texture.Height];
|
||||
renderTarget.GetData(data);
|
||||
|
||||
// Unset texture from graphic device and set modified data back to it
|
||||
_graphicsDevice.Textures[0] = null;
|
||||
texture.SetData(data);
|
||||
}
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
|
||||
private static readonly BlendState BlendColorBlendState;
|
||||
private static readonly BlendState BlendAlphaBlendState;
|
||||
|
||||
private static GraphicsDevice _graphicsDevice;
|
||||
private static SpriteBatch _spriteBatch;
|
||||
private static bool _needsBmp;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,612 @@
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
public class Pair<T1, T2>
|
||||
{
|
||||
public T1 First { get; set; }
|
||||
public T2 Second { get; set; }
|
||||
|
||||
public static Pair<T1, T2> Create(T1 first, T2 second)
|
||||
{
|
||||
Pair<T1, T2> pair = new Pair<T1, T2>();
|
||||
pair.First = first;
|
||||
pair.Second = second;
|
||||
|
||||
return pair;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ToolBox
|
||||
{
|
||||
public static bool IsProperFilenameCase(string filename)
|
||||
{
|
||||
char[] delimiters = { '/','\\' };
|
||||
string[] subDirs = filename.Split(delimiters);
|
||||
string originalFilename = filename;
|
||||
filename = "";
|
||||
|
||||
for (int i=0;i<subDirs.Length-1;i++)
|
||||
{
|
||||
filename += subDirs[i] + "/";
|
||||
|
||||
if (i == subDirs.Length - 2)
|
||||
{
|
||||
string[] filePaths = Directory.GetFiles(filename);
|
||||
if (filePaths.Any(s => s.Equals(filename + subDirs[i + 1], StringComparison.Ordinal)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (filePaths.Any(s => s.Equals(filename + subDirs[i + 1], StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
DebugConsole.ThrowError(originalFilename + " has incorrect case!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
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.OrdinalIgnoreCase)))
|
||||
{
|
||||
DebugConsole.ThrowError(originalFilename + " has incorrect case!");
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError(originalFilename + " doesn't exist!");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static XDocument TryLoadXml(string filePath)
|
||||
{
|
||||
XDocument doc;
|
||||
try
|
||||
{
|
||||
IsProperFilenameCase(filePath);
|
||||
doc = XDocument.Load(filePath);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Couldn't load xml document \""+filePath+"\"!", e);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (doc.Root == null) return null;
|
||||
|
||||
return doc;
|
||||
}
|
||||
|
||||
/*public static SpriteFont TryLoadFont(string file, Microsoft.Xna.Framework.Content.ContentManager contentManager)
|
||||
{
|
||||
SpriteFont font = null;
|
||||
try
|
||||
{
|
||||
font = contentManager.Load<SpriteFont>(file);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Loading font \""+file+"\" failed", e);
|
||||
}
|
||||
|
||||
return font;
|
||||
}*/
|
||||
|
||||
public static object GetAttributeObject(XElement element, string name)
|
||||
{
|
||||
if (element == null || element.Attribute(name) == null) return null;
|
||||
return GetAttributeObject(element.Attribute(name));
|
||||
}
|
||||
|
||||
public static object GetAttributeObject(XAttribute attribute)
|
||||
{
|
||||
if (attribute == null) return null;
|
||||
|
||||
return ParseToObject(attribute.Value.ToString());
|
||||
}
|
||||
|
||||
public static object ParseToObject(string value)
|
||||
{
|
||||
float floatVal;
|
||||
int intVal;
|
||||
if (value.ToString().Contains(".") && float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out floatVal))
|
||||
{
|
||||
return floatVal;
|
||||
}
|
||||
else if (int.TryParse(value, out intVal))
|
||||
{
|
||||
return intVal;
|
||||
}
|
||||
else
|
||||
{
|
||||
string lowerTrimmedVal = value.ToLowerInvariant().Trim();
|
||||
if (lowerTrimmedVal == "true")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (lowerTrimmedVal == "false")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static string GetAttributeString(XElement element, string name, string defaultValue)
|
||||
{
|
||||
if (element == null || element.Attribute(name) == null) return defaultValue;
|
||||
return GetAttributeString(element.Attribute(name), defaultValue);
|
||||
}
|
||||
|
||||
public static string GetAttributeString(XAttribute attribute, string defaultValue)
|
||||
{
|
||||
string value = attribute.Value;
|
||||
if (String.IsNullOrEmpty(value)) return defaultValue;
|
||||
return value;
|
||||
}
|
||||
|
||||
public static float GetAttributeFloat(XElement element, string name, float defaultValue)
|
||||
{
|
||||
if (element == null || element.Attribute(name) == null) return defaultValue;
|
||||
|
||||
float val = defaultValue;
|
||||
|
||||
try
|
||||
{
|
||||
if (!float.TryParse(element.Attribute(name).Value, NumberStyles.Float, CultureInfo.InvariantCulture, out val))
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Error in "+element+"!", e);
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
public static float GetAttributeFloat(XAttribute attribute, float defaultValue)
|
||||
{
|
||||
if (attribute == null) return defaultValue;
|
||||
|
||||
float val = defaultValue;
|
||||
|
||||
try
|
||||
{
|
||||
val = float.Parse(attribute.Value, CultureInfo.InvariantCulture);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Error in " + attribute + "! ", e);
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
public static int GetAttributeInt(XElement element, string name, int defaultValue)
|
||||
{
|
||||
if (element == null || element.Attribute(name) == null) return defaultValue;
|
||||
|
||||
int val = defaultValue;
|
||||
|
||||
try
|
||||
{
|
||||
val = int.Parse(element.Attribute(name).Value);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Error in " + element + "! ", e);
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
public static bool GetAttributeBool(XElement element, string name, bool defaultValue)
|
||||
{
|
||||
if (element == null || element.Attribute(name) == null) return defaultValue;
|
||||
|
||||
return GetAttributeBool(element.Attribute(name), defaultValue);
|
||||
}
|
||||
|
||||
public static bool GetAttributeBool(XAttribute attribute, bool defaultValue)
|
||||
{
|
||||
if (attribute == null) return defaultValue;
|
||||
|
||||
string val = attribute.Value.ToLowerInvariant().Trim();
|
||||
if (val == "true")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (val == "false")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError("Error in " + attribute.Value.ToString() + "! \"" + val + "\" is not a valid boolean value");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static Vector2 GetAttributeVector2(XElement element, string name, Vector2 defaultValue)
|
||||
{
|
||||
if (element == null || element.Attribute(name) == null) return defaultValue;
|
||||
|
||||
string val = element.Attribute(name).Value;
|
||||
|
||||
return ParseToVector2(val);
|
||||
}
|
||||
|
||||
public static Vector3 GetAttributeVector3(XElement element, string name, Vector3 defaultValue)
|
||||
{
|
||||
if (element == null || element.Attribute(name) == null) return defaultValue;
|
||||
|
||||
string val = element.Attribute(name).Value;
|
||||
|
||||
return ParseToVector3(val);
|
||||
}
|
||||
|
||||
public static Vector4 GetAttributeVector4(XElement element, string name, Vector4 defaultValue)
|
||||
{
|
||||
if (element == null || element.Attribute(name) == null) return defaultValue;
|
||||
|
||||
string val = element.Attribute(name).Value;
|
||||
|
||||
return ParseToVector4(val);
|
||||
}
|
||||
|
||||
public static string ElementInnerText(this XElement el)
|
||||
{
|
||||
StringBuilder str = new StringBuilder();
|
||||
foreach (XNode element in el.DescendantNodes().Where(x => x.NodeType == XmlNodeType.Text))
|
||||
{
|
||||
str.Append(element.ToString());
|
||||
}
|
||||
return str.ToString();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public static Vector2 ParseToVector2(string stringVector2, bool errorMessages = true)
|
||||
{
|
||||
string[] components = stringVector2.Split(',');
|
||||
|
||||
Vector2 vector = Vector2.Zero;
|
||||
|
||||
if (components.Length!=2)
|
||||
{
|
||||
if (!errorMessages) return vector;
|
||||
DebugConsole.ThrowError("Failed to parse the string \""+stringVector2+"\" to Vector2");
|
||||
return vector;
|
||||
}
|
||||
|
||||
float.TryParse(components[0], NumberStyles.Any, CultureInfo.InvariantCulture, out vector.X);
|
||||
float.TryParse(components[1], NumberStyles.Any, CultureInfo.InvariantCulture, out vector.Y);
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
public static string Vector2ToString(Vector2 vector)
|
||||
{
|
||||
return vector.X.ToString("G", CultureInfo.InvariantCulture) + "," + vector.Y.ToString("G", CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
public static Vector3 ParseToVector3(string stringVector3, bool errorMessages = true)
|
||||
{
|
||||
string[] components = stringVector3.Split(',');
|
||||
|
||||
Vector3 vector = Vector3.Zero;
|
||||
|
||||
if (components.Length!=3)
|
||||
{
|
||||
if (!errorMessages) return vector;
|
||||
DebugConsole.ThrowError("Failed to parse the string \""+stringVector3+"\" to Vector3");
|
||||
return vector;
|
||||
}
|
||||
|
||||
float.TryParse(components[0], NumberStyles.Any, CultureInfo.InvariantCulture, out vector.X);
|
||||
float.TryParse(components[1], NumberStyles.Any, CultureInfo.InvariantCulture, out vector.Y);
|
||||
float.TryParse(components[2], NumberStyles.Any, CultureInfo.InvariantCulture, out vector.Z);
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
public static Vector4 ParseToVector4(string stringVector4, bool errorMessages = true)
|
||||
{
|
||||
string[] components = stringVector4.Split(',');
|
||||
|
||||
Vector4 vector = Vector4.Zero;
|
||||
|
||||
if (components.Length < 3)
|
||||
{
|
||||
if (errorMessages) DebugConsole.ThrowError("Failed to parse the string \"" + stringVector4 + "\" to Vector4");
|
||||
return vector;
|
||||
}
|
||||
|
||||
float.TryParse(components[0], NumberStyles.Float, CultureInfo.InvariantCulture, out vector.X);
|
||||
float.TryParse(components[1], NumberStyles.Float, CultureInfo.InvariantCulture, out vector.Y);
|
||||
float.TryParse(components[2], NumberStyles.Float, CultureInfo.InvariantCulture, out vector.Z);
|
||||
if (components.Length>3)
|
||||
float.TryParse(components[3], NumberStyles.Float, CultureInfo.InvariantCulture, out vector.W);
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
public static string Vector4ToString(Vector4 vector, string format = "G")
|
||||
{
|
||||
return vector.X.ToString(format, CultureInfo.InvariantCulture) + "," +
|
||||
vector.Y.ToString(format, CultureInfo.InvariantCulture) + "," +
|
||||
vector.Z.ToString(format, CultureInfo.InvariantCulture) + "," +
|
||||
vector.W.ToString(format, CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
public static float[] ParseArrayToFloat(string[] stringArray)
|
||||
{
|
||||
if (stringArray == null || stringArray.Length == 0) return null;
|
||||
|
||||
float[] floatArray = new float[stringArray.Length];
|
||||
for (int i = 0; i<floatArray.Length; i++)
|
||||
{
|
||||
floatArray[i]=0.0f;
|
||||
float.TryParse(stringArray[i], NumberStyles.Float, CultureInfo.InvariantCulture, out floatArray[i]);
|
||||
}
|
||||
|
||||
return floatArray;
|
||||
}
|
||||
|
||||
public static string LimitString(string str, int maxCharacters)
|
||||
{
|
||||
if (str == null || maxCharacters < 0) return null;
|
||||
|
||||
if (maxCharacters < 4 || str.Length <= maxCharacters) return str;
|
||||
|
||||
return str.Substring(0, maxCharacters-3) + "...";
|
||||
}
|
||||
|
||||
public static string LimitString(string str, ScalableFont font, int maxWidth)
|
||||
{
|
||||
if (maxWidth <= 0 || string.IsNullOrWhiteSpace(str)) return "";
|
||||
|
||||
float currWidth = font.MeasureString("...").X;
|
||||
for (int i = 0; i < str.Length; i++ )
|
||||
{
|
||||
currWidth += font.MeasureString(str[i].ToString()).X;
|
||||
|
||||
if (currWidth > maxWidth)
|
||||
{
|
||||
return str.Substring(0, Math.Max(i - 2, 1)) + "...";
|
||||
}
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
public static string RandomSeed(int length)
|
||||
{
|
||||
var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
return new string(
|
||||
Enumerable.Repeat(chars, length)
|
||||
.Select(s => s[Rand.Int(s.Length)])
|
||||
.ToArray());
|
||||
}
|
||||
|
||||
public static int StringToInt(string str)
|
||||
{
|
||||
str = str.Substring(0, Math.Min(str.Length, 32));
|
||||
|
||||
str = str.PadLeft(4, 'a');
|
||||
|
||||
byte[] asciiBytes = Encoding.ASCII.GetBytes(str);
|
||||
|
||||
for (int i = 4; i < asciiBytes.Length; i++)
|
||||
{
|
||||
asciiBytes[i % 4] ^= asciiBytes[i];
|
||||
}
|
||||
|
||||
return BitConverter.ToInt32(asciiBytes, 0);
|
||||
}
|
||||
/// <summary>
|
||||
/// a method for changing inputtypes with old names to the new ones to ensure backwards compatibility with older subs
|
||||
/// </summary>
|
||||
public static string ConvertInputType(string inputType)
|
||||
{
|
||||
if (inputType == "ActionHit" || inputType == "Action") return "Use";
|
||||
if (inputType == "SecondarHit" || inputType == "Secondary") return "Aim";
|
||||
|
||||
return inputType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the minimum number of single-character edits (i.e. insertions, deletions or substitutions) required to change one string into the other
|
||||
/// </summary>
|
||||
public static int LevenshteinDistance(string s, string t)
|
||||
{
|
||||
int n = s.Length;
|
||||
int m = t.Length;
|
||||
int[,] d = new int[n + 1, m + 1];
|
||||
|
||||
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 = 1; i <= n; i++)
|
||||
{
|
||||
for (int j = 1; j <= m; j++)
|
||||
{
|
||||
int cost = (t[j - 1] == s[i - 1]) ? 0 : 1;
|
||||
|
||||
d[i, j] = Math.Min(
|
||||
Math.Min(d[i - 1, j] + 1, d[i, j - 1] + 1),
|
||||
d[i - 1, j - 1] + cost);
|
||||
}
|
||||
}
|
||||
|
||||
return d[n, m];
|
||||
}
|
||||
|
||||
public static string WrapText(string text, float lineLength, ScalableFont font, float textScale = 1.0f) //TODO: could integrate this into the ScalableFont class directly
|
||||
{
|
||||
if (font.MeasureString(text).X < lineLength) return text;
|
||||
|
||||
text = text.Replace("\n", " \n ");
|
||||
|
||||
string[] words = text.Split(' ');
|
||||
|
||||
StringBuilder wrappedText = new StringBuilder();
|
||||
float linePos = 0f;
|
||||
float spaceWidth = font.MeasureString(" ").X * textScale;
|
||||
for (int i = 0; i < words.Length; ++i)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(words[i]) && words[i] != "\n") continue;
|
||||
|
||||
Vector2 size = font.MeasureString(words[i]) * textScale;
|
||||
if (size.X > lineLength)
|
||||
{
|
||||
if (linePos == 0.0f)
|
||||
{
|
||||
wrappedText.AppendLine(words[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
do
|
||||
{
|
||||
if (words[i].Length == 0) break;
|
||||
|
||||
wrappedText.Append(words[i][0]);
|
||||
words[i] = words[i].Remove(0, 1);
|
||||
|
||||
linePos += size.X;
|
||||
} while (words[i].Length > 0 && (size = font.MeasureString((words[i][0]).ToString()) * textScale).X + linePos < lineLength);
|
||||
|
||||
wrappedText.Append("\n");
|
||||
linePos = 0.0f;
|
||||
i--;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (linePos + size.X < lineLength)
|
||||
{
|
||||
wrappedText.Append(words[i]);
|
||||
if (words[i] == "\n")
|
||||
{
|
||||
linePos = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
linePos += size.X + spaceWidth;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
wrappedText.Append("\n");
|
||||
wrappedText.Append(words[i]);
|
||||
|
||||
linePos = size.X + spaceWidth;
|
||||
}
|
||||
|
||||
if (i < words.Length - 1) wrappedText.Append(" ");
|
||||
}
|
||||
|
||||
return wrappedText.ToString();
|
||||
}
|
||||
|
||||
public static string SecondsToReadableTime(float seconds)
|
||||
{
|
||||
if (seconds < 60.0f)
|
||||
{
|
||||
return (int)seconds + " s";
|
||||
}
|
||||
else
|
||||
{
|
||||
int m = (int)(seconds / 60.0f);
|
||||
int s = (int)(seconds % 60.0f);
|
||||
|
||||
return s == 0 ?
|
||||
m + " m" :
|
||||
m + " m " + s + " s";
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetRandomLine(string filePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
string randomLine = "";
|
||||
StreamReader file = new StreamReader(filePath);
|
||||
|
||||
var lines = File.ReadLines(filePath).ToList();
|
||||
int lineCount = lines.Count;
|
||||
|
||||
if (lineCount == 0)
|
||||
{
|
||||
DebugConsole.ThrowError("File \"" + filePath + "\" is empty!");
|
||||
file.Close();
|
||||
return "";
|
||||
}
|
||||
|
||||
int lineNumber = Rand.Int(lineCount, false);
|
||||
|
||||
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 "";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a number of bits from the buffer and inserts them to a new NetBuffer instance
|
||||
/// </summary>
|
||||
public static NetBuffer ExtractBits(this NetBuffer originalBuffer, int numberOfBits)
|
||||
{
|
||||
var buffer = new NetBuffer();
|
||||
byte[] data = new byte[(int)Math.Ceiling(numberOfBits / (double)8)];
|
||||
|
||||
originalBuffer.ReadBits(data, 0, numberOfBits);
|
||||
buffer.Write(data);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
public static class UpdaterUtil
|
||||
{
|
||||
public const string Version = "1.1";
|
||||
|
||||
public static void SaveFileList(string filePath)
|
||||
{
|
||||
XDocument doc = new XDocument(CreateFileList());
|
||||
|
||||
doc.Save(filePath);
|
||||
}
|
||||
|
||||
public static XElement CreateFileList()
|
||||
{
|
||||
XElement root = new XElement("filelist");
|
||||
string currentDir = Directory.GetCurrentDirectory();
|
||||
|
||||
string[] files = Directory.GetFiles(currentDir, "*", SearchOption.AllDirectories);
|
||||
|
||||
foreach (string file in files)
|
||||
{
|
||||
XElement fileElement = new XElement("file");
|
||||
fileElement.Add(new XAttribute("path", GetRelativePath(file, currentDir)));
|
||||
fileElement.Add(new XAttribute("md5", GetFileMd5Hash(file)));
|
||||
|
||||
root.Add(fileElement);
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
public static List<string> GetFileList(XDocument fileListDoc)
|
||||
{
|
||||
List<string> fileList = new List<string>();
|
||||
|
||||
XElement fileListElement = fileListDoc.Root;
|
||||
|
||||
if (fileListElement == null)
|
||||
{
|
||||
throw new Exception("Received list of new files was corrupted");
|
||||
}
|
||||
|
||||
foreach (XElement file in fileListElement.Elements())
|
||||
{
|
||||
string filePath = ToolBox.GetAttributeString(file, "path", "");
|
||||
|
||||
fileList.Add(filePath);
|
||||
}
|
||||
|
||||
return fileList;
|
||||
}
|
||||
|
||||
public static List<string> GetRequiredFiles(XDocument fileListDoc)
|
||||
{
|
||||
List<string> requiredFiles = new List<string>();
|
||||
|
||||
XElement fileList = fileListDoc.Root;
|
||||
|
||||
if (fileList==null)
|
||||
{
|
||||
throw new Exception("Received list of new files was corrupted");
|
||||
}
|
||||
|
||||
foreach (XElement file in fileList.Elements())
|
||||
{
|
||||
string filePath = ToolBox.GetAttributeString(file, "path", "");
|
||||
|
||||
if (!File.Exists(filePath))
|
||||
{
|
||||
requiredFiles.Add(filePath);
|
||||
continue;
|
||||
}
|
||||
|
||||
string md5 = ToolBox.GetAttributeString(file, "md5", "");
|
||||
|
||||
if (GetFileMd5Hash(filePath) != md5)
|
||||
{
|
||||
requiredFiles.Add(filePath);
|
||||
}
|
||||
}
|
||||
|
||||
return requiredFiles;
|
||||
}
|
||||
|
||||
private static string GetFileMd5Hash(string filePath)
|
||||
{
|
||||
Md5Hash md5Hash = null;
|
||||
var md5 = MD5.Create();
|
||||
using (var stream = File.OpenRead(filePath))
|
||||
{
|
||||
md5Hash = new Md5Hash(md5.ComputeHash(stream));
|
||||
}
|
||||
|
||||
return md5Hash.Hash;
|
||||
}
|
||||
|
||||
public static string GetRelativePath(string filespec, string folder)
|
||||
{
|
||||
Uri pathUri = new Uri(filespec);
|
||||
// Folders must end in a slash
|
||||
if (!folder.EndsWith(Path.DirectorySeparatorChar.ToString()))
|
||||
{
|
||||
folder += Path.DirectorySeparatorChar;
|
||||
}
|
||||
Uri folderUri = new Uri(folder);
|
||||
return Uri.UnescapeDataString(folderUri.MakeRelativeUri(pathUri).ToString().Replace('/', Path.DirectorySeparatorChar));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// moves the files in the updatefolder to the install folder
|
||||
/// if there's an existing file with the same name in the install folder and it can't be removed,
|
||||
/// it will be renamed as "OLD_[filename]"
|
||||
/// </summary>
|
||||
/// <param name="updateFileFolder"></param>
|
||||
public static void InstallUpdatedFiles(string updateFileFolder)
|
||||
{
|
||||
string[] files = Directory.GetFiles(updateFileFolder, "*", SearchOption.AllDirectories);
|
||||
|
||||
string currentDir = Directory.GetCurrentDirectory();
|
||||
|
||||
foreach (string file in files)
|
||||
{
|
||||
string fileRelPath = GetRelativePath(file, updateFileFolder);
|
||||
|
||||
if (File.Exists(fileRelPath))
|
||||
{
|
||||
try
|
||||
{
|
||||
File.Delete(fileRelPath);
|
||||
}
|
||||
|
||||
//couldn't delete file, probably because it's already in use
|
||||
catch
|
||||
{
|
||||
string oldFileName = Path.Combine(currentDir, Path.GetDirectoryName(fileRelPath), "OLD_"+Path.GetFileName(fileRelPath));
|
||||
|
||||
if (File.Exists(oldFileName)) File.Delete(oldFileName);
|
||||
|
||||
File.Move(fileRelPath, oldFileName);
|
||||
}
|
||||
}
|
||||
|
||||
string directoryName = Path.GetDirectoryName(fileRelPath);
|
||||
if (!string.IsNullOrWhiteSpace(directoryName))
|
||||
{
|
||||
Directory.CreateDirectory(directoryName);
|
||||
}
|
||||
|
||||
|
||||
System.Diagnostics.Debug.WriteLine("moving: "+file+" -> "+fileRelPath);
|
||||
File.Move(file, fileRelPath);
|
||||
}
|
||||
|
||||
Directory.Delete(updateFileFolder, true);
|
||||
}
|
||||
|
||||
public static void CleanUnnecessaryFiles(List<string> filesToKeep)
|
||||
{
|
||||
string currentDir = Directory.GetCurrentDirectory();
|
||||
|
||||
string[] files = Directory.GetFiles(currentDir, "*", SearchOption.AllDirectories);
|
||||
|
||||
foreach (string file in files)
|
||||
{
|
||||
string relativePath = GetRelativePath(file, currentDir);
|
||||
|
||||
string dirRoot = relativePath.Split(Path.DirectorySeparatorChar).First();
|
||||
if (dirRoot != "Content") continue;
|
||||
|
||||
if (filesToKeep.Contains(relativePath)) continue;
|
||||
|
||||
if (Path.GetFileName(file).Split('_').First() == "OLD") continue;
|
||||
|
||||
System.Diagnostics.Debug.WriteLine("deleting file "+file);
|
||||
|
||||
try
|
||||
{
|
||||
File.Delete(file);
|
||||
}
|
||||
|
||||
catch (Exception e)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine("Could not delete file \"" + file + "\" (" + e.Message + ")");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void CleanOldFiles()
|
||||
{
|
||||
string currentDir = Directory.GetCurrentDirectory();
|
||||
|
||||
string[] files = Directory.GetFiles(currentDir, "*", SearchOption.AllDirectories);
|
||||
|
||||
foreach (string file in files)
|
||||
{
|
||||
if (Path.GetFileName(file).Split('_').First() != "OLD") continue;
|
||||
|
||||
System.Diagnostics.Debug.WriteLine("deleting file " + file);
|
||||
|
||||
try
|
||||
{
|
||||
File.Delete(file);
|
||||
}
|
||||
|
||||
catch (Exception e)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine("Could not delete file \"" + file + "\" (" + e.Message + ")");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user