Build 1.1.4.0

This commit is contained in:
Markus Isberg
2023-03-31 18:40:44 +03:00
parent efba17e0ff
commit 9470edead3
483 changed files with 17487 additions and 8548 deletions
@@ -25,7 +25,7 @@ namespace Barotrauma
if (!Done) { Mre.WaitOne(); }
}
}
private static List<Task> enqueuedTasks;
private static readonly List<Task> enqueuedTasks;
static CrossThread() { enqueuedTasks = new List<Task>(); }
@@ -155,7 +155,6 @@ namespace Barotrauma
public static float CurveAngle(float from, float to, float step)
{
from = WrapAngleTwoPi(from);
to = WrapAngleTwoPi(to);
@@ -189,13 +188,7 @@ namespace Barotrauma
{
return 0.0f;
}
while (angle < 0)
angle += MathHelper.TwoPi;
while (angle >= MathHelper.TwoPi)
angle -= MathHelper.TwoPi;
return angle;
return PositiveModulo(angle, MathHelper.TwoPi);
}
/// <summary>
@@ -207,13 +200,9 @@ namespace Barotrauma
{
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;
float min = -MathHelper.Pi;
float diffFromMin = angle - min;
return diffFromMin - (MathF.Floor(diffFromMin / MathHelper.TwoPi) * MathHelper.TwoPi) + min;
}
public static float GetShortestAngle(float from, float to)
@@ -342,13 +331,13 @@ namespace Barotrauma
if (axisAligned1.Y < axisAligned2.Y)
{
if (y < axisAligned1.Y) return false;
if (y > axisAligned2.Y) return false;
if (y < axisAligned1.Y) { return false; }
if (y > axisAligned2.Y) { return false; }
}
else
{
if (y > axisAligned1.Y) return false;
if (y < axisAligned2.Y) return false;
if (y > axisAligned1.Y) { return false; }
if (y < axisAligned2.Y) { return false; }
}
intersection = new Vector2(axisAligned1.X, y);
@@ -364,13 +353,13 @@ namespace Barotrauma
if (axisAligned1.X < axisAligned2.X)
{
if (x < axisAligned1.X) return false;
if (x > axisAligned2.X) return false;
if (x < axisAligned1.X) { return false; }
if (x > axisAligned2.X) { return false; }
}
else
{
if (x > axisAligned1.X) return false;
if (x < axisAligned2.X) return false;
if (x > axisAligned1.X) { return false; }
if (x < axisAligned2.X) { return false; }
}
intersection = new Vector2(x, axisAligned1.Y);
@@ -901,23 +890,30 @@ namespace Barotrauma
// 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
//shortcut, handles infinities
return true;
}
else if (a == 0 || b == 0 || diff < float.Epsilon)
if (a == 0 || b == 0)
{
// a or b is zero or both are extremely close to it
// relative error is less meaningful here
return diff < epsilon;
//if a or b is zero, relative error is less meaningful
return Math.Abs(a - b) < epsilon;
}
else
float absA = Math.Abs(a);
float absB = Math.Abs(b);
float absAB = absA + absB;
if (absAB < epsilon)
{
// use relative error
return diff / (Math.Abs(a) + Math.Abs(b)) < epsilon;
// a and b extremely close to zero, relative error is less meaningful
return true;
}
float diff = Math.Abs(a - b);
// use relative error
return diff / absAB < epsilon;
}
/// <summary>
@@ -1,9 +1,7 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
using Barotrauma.IO;
using System;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
@@ -12,52 +10,6 @@ namespace Barotrauma
{
public class Md5Hash
{
public static class Cache
{
private const string cachePath = "Data/hashcache.txt";
private readonly static List<(string Path, Md5Hash Hash, DateTime DateTime)> Entries
= new List<(string Path, Md5Hash Hash, DateTime DateTime)>();
public static void Load()
{
if (!File.Exists(cachePath)) { return; }
var lines = File.ReadAllLines(cachePath);
if (Version.TryParse(lines[0], out var cacheVersion) && cacheVersion == GameMain.Version)
{
for (int i = 1; i < lines.Length; i++)
{
string[] split = lines[i].Split('|');
string path = split[0].CleanUpPathCrossPlatform();
Md5Hash hash = Md5Hash.StringAsHash(split[1]);
DateTime? dateTime = null;
if (long.TryParse(split[2], out long dateTimeUlong))
{
dateTime = DateTime.FromBinary(dateTimeUlong);
}
if (File.Exists(path) && dateTime.HasValue && dateTime >= File.GetLastWriteTime(path))
{
Entries.Add((path, hash, dateTime.Value));
}
}
}
}
public static void Add(string path, Md5Hash hash, DateTime dateTime)
{
path = path.CleanUpPathCrossPlatform();
Remove(path);
Entries.Add((path, hash, dateTime));
}
public static void Remove(string path)
{
path = path.CleanUpPathCrossPlatform();
Entries.RemoveAll(e => e.Path == path);
}
}
public static readonly Md5Hash Blank = new Md5Hash(new string('0', 32));
private static string RemoveWhitespace(string s)
@@ -1,17 +0,0 @@
namespace Barotrauma
{
public sealed class None<T> : Option<T>
{
private None() { }
public static Option<T> Create() => new None<T>();
public override Option<T> Fallback(Option<T> fallback) => fallback;
public override T Fallback(T fallback) => fallback;
public override bool ValueEquals(T value) => false;
public override string ToString()
=> $"None<{typeof(T).Name}>";
}
}
@@ -1,60 +1,83 @@
#nullable enable
using System;
using System.Diagnostics.CodeAnalysis;
namespace Barotrauma
{
/// <summary>
/// Implementation of <a href="https://en.wikipedia.org/wiki/Option_type">Option type</a>.
/// </summary>
/// <remarks>
/// Credit <a href="https://github.com/Jlobblet/FunctionalStuff/tree/main/src/FunctionalStuff/Option">Jlobblet</a>
/// </remarks>
public abstract class Option<T>
public readonly struct Option<T> where T : notnull
{
public static Option<T> Some(T value) => Some<T>.Create(value);
public static Option<T> None() => None<T>.Create();
public bool IsNone() => this is None<T>;
public bool IsSome() => this is Some<T>;
private readonly bool hasValue;
private readonly T? value;
public bool TryUnwrap(out T outValue) => TryUnwrap<T>(out outValue);
public bool TryUnwrap<T1>(out T1 outValue) where T1 : T
private Option(bool hasValue, T? value)
{
switch (this)
{
case Some<T> { Value: T1 value }:
outValue = value;
return true;
default:
outValue = default!;
return false;
}
this.hasValue = hasValue;
this.value = value;
}
public Option<TType> Select<TType>(Func<T, TType> selector) =>
this switch
public bool IsSome() => hasValue;
public bool IsNone() => !IsSome();
public bool TryUnwrap<T1>([NotNullWhen(returnValue: true)] out T1? outValue) where T1 : T
{
bool hasValueOfGivenType = false;
outValue = default;
if (hasValue && value is T1 t1)
{
Some<T> { Value: var value } => Option<TType>.Some(selector.Invoke(value)),
None<T> _ => Option<TType>.None(),
_ => throw new ArgumentOutOfRangeException()
hasValueOfGivenType = true;
outValue = t1;
}
return hasValueOfGivenType;
}
public bool TryUnwrap([NotNullWhen(returnValue: true)] out T? outValue)
=> TryUnwrap<T>(out outValue);
public Option<TType> Select<TType>(Func<T, TType> selector) where TType : notnull
=> TryUnwrap(out T? selfValue) ? Option.Some(selector(selfValue)) : Option.None;
public Option<TType> Bind<TType>(Func<T, Option<TType>> binder) where TType : notnull
=> TryUnwrap(out T? selfValue) ? binder(selfValue) : Option.None;
public T Fallback(T fallback)
=> TryUnwrap(out var v) ? v : fallback;
public Option<T> Fallback(Option<T> fallback)
=> IsSome() ? this : fallback;
public static Option<T> Some(T value)
=> typeof(T) switch
{
var t when t == typeof(bool)
=> throw new Exception("Option type rejects booleans"),
{IsConstructedGenericType: true} t when t.GetGenericTypeDefinition() == typeof(Option<>)
=> throw new Exception("Option type rejects nested Option"),
{IsConstructedGenericType: true} t when t.GetGenericTypeDefinition() == typeof(Nullable<>)
=> throw new Exception("Option type rejects Nullable"),
_
=> new Option<T>(hasValue: true, value: value ?? throw new Exception("Option type rejects null"))
};
public abstract Option<T> Fallback(Option<T> fallback);
public abstract T Fallback(T fallback);
public abstract bool ValueEquals(T value);
public override bool Equals(object? obj)
=> obj switch
{
Some<T> { Value: var value } => this is Some<T> { Value: { } selfValue } && selfValue.Equals(value),
None<T> _ => IsNone(),
T value => this is Some<T> { Value: { } selfValue } && selfValue.Equals(value),
_ => false
Option<T> otherOption when otherOption.IsNone()
=> IsNone(),
Option<T> otherOption when otherOption.TryUnwrap(out var otherValue)
=> ValueEquals(otherValue),
T otherValue
=> ValueEquals(otherValue),
_
=> false
};
public bool ValueEquals(T otherValue)
=> TryUnwrap(out T? selfValue) && selfValue.Equals(otherValue);
public override int GetHashCode()
=> this is Some<T> { Value: { } value } ? value.GetHashCode() : 0;
=> TryUnwrap(out T? selfValue) ? selfValue.GetHashCode() : 0;
public static bool operator ==(Option<T> a, Option<T> b)
=> a.Equals(b);
@@ -62,22 +85,28 @@ namespace Barotrauma
public static bool operator !=(Option<T> a, Option<T> b)
=> !(a == b);
public abstract override string ToString();
public static implicit operator Option<T>(Option.UnspecifiedNone _)
public static Option<T> None()
=> default;
public static implicit operator Option<T>(in Option.UnspecifiedNone _)
=> None();
public override string ToString()
=> TryUnwrap(out var selfValue)
? $"Some<{typeof(T).Name}>({selfValue})"
: $"None<{typeof(T).Name}>";
}
public static class Option
{
public sealed class UnspecifiedNone
public static Option<T> Some<T>(T value) where T : notnull
=> Option<T>.Some(value);
public static UnspecifiedNone None
=> default;
public readonly ref struct UnspecifiedNone
{
private UnspecifiedNone() { }
internal static readonly UnspecifiedNone Instance = new();
}
public static UnspecifiedNone None => UnspecifiedNone.Instance;
public static Option<T> Some<T>(T value) => Option<T>.Some(value);
}
}
@@ -1,25 +0,0 @@
using System;
namespace Barotrauma
{
public sealed class Some<T> : Option<T>
{
public readonly T Value;
private Some(T value)
{
if (value is null) { throw new ArgumentNullException(nameof(value), "Some<T> cannot contain null"); }
Value = value;
}
public static Option<T> Create(T value) => new Some<T>(value);
public override Option<T> Fallback(Option<T> fallback) => this;
public override T Fallback(T fallback) => Value;
public override bool ValueEquals(T value) => Value.Equals(value);
public override string ToString()
=> $"Some<{typeof(T).Name}>({Value})";
}
}
@@ -23,7 +23,7 @@ namespace Barotrauma
return cachedNonAbstractTypes[assembly].Where(t => t.IsSubclassOf(typeof(T)));
}
public static Option<TBase> ParseDerived<TBase, TInput>(TInput input) where TInput : notnull
public static Option<TBase> ParseDerived<TBase, TInput>(TInput input) where TInput : notnull where TBase : notnull
{
static Option<TBase> none() => Option<TBase>.None();
@@ -54,10 +54,10 @@ namespace Barotrauma
f.Method.GetGenericMethodDefinition().MakeGenericMethod(genericArgs);
return constructedConverter.Invoke(null, new[] { parseFunc.Invoke(null, new object[] { input }) })
as Option<TBase> ?? none();
as Option<TBase>? ?? none();
}
return derivedTypes.Select(parseOfType).FirstOrDefault(t => t.IsSome()) ?? none();
return derivedTypes.Select(parseOfType).FirstOrDefault(t => t.IsSome());
}
public static string NameWithGenerics(this Type t)
@@ -141,9 +141,8 @@ namespace Barotrauma
public SerializableDateTime ToLocal()
=> new SerializableDateTime(
DateTime.SpecifyKind(
value - TimeZone.Value + SerializableTimeZone.LocalTimeZone.Value,
DateTimeKind.Local));
new DateTime(ticks: value.Ticks) - TimeZone.Value + SerializableTimeZone.LocalTimeZone.Value,
SerializableTimeZone.LocalTimeZone);
public long Ticks => value.Ticks;
@@ -394,7 +394,6 @@ namespace Barotrauma
return SelectWeightedRandom(objects, weightMethod, Rand.GetRNG(randSync));
}
public static T SelectWeightedRandom<T>(IEnumerable<T> objects, Func<T, float> weightMethod, Random random)
{
List<T> objectList = objects.ToList();
@@ -409,7 +408,7 @@ namespace Barotrauma
public static T SelectWeightedRandom<T>(IList<T> objects, IList<float> weights, Random random)
{
if (objects.Count == 0) return default(T);
if (objects.Count == 0) { return default(T); }
if (objects.Count != weights.Count)
{