Faction Test 100.4.0.0
This commit is contained in:
@@ -104,6 +104,8 @@ namespace Barotrauma
|
||||
(float)Math.Floor(value / div) * div;
|
||||
}
|
||||
|
||||
public static int RoundToInt(float v) => (int)MathF.Round(v);
|
||||
|
||||
public static float RoundTowardsClosest(float value, float div)
|
||||
{
|
||||
return (float)Math.Round(value / div) * div;
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
[NetworkSerialize]
|
||||
public readonly record struct NetCollection<T>(ImmutableArray<T> Array) : INetSerializableStruct, IEnumerable<T>
|
||||
{
|
||||
public static readonly NetCollection<T> Empty = new(ImmutableArray<T>.Empty);
|
||||
|
||||
public NetCollection(params T[] elements) : this(elements.ToImmutableArray()) { }
|
||||
|
||||
IEnumerator<T> IEnumerable<T>.GetEnumerator() => ((IEnumerable<T>)Array).GetEnumerator();
|
||||
IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)Array).GetEnumerator();
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@ namespace Barotrauma
|
||||
|
||||
#if OSX
|
||||
//"/*user*/Library/Application Support/Daedalic Entertainment GmbH/" on Mac
|
||||
public static readonly string SaveFolder = Path.Combine(
|
||||
public static readonly string DefaultSaveFolder = Path.Combine(
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.Personal),
|
||||
"Library",
|
||||
"Application Support",
|
||||
@@ -27,13 +27,13 @@ namespace Barotrauma
|
||||
#else
|
||||
//"C:/Users/*user*/AppData/Local/Daedalic Entertainment GmbH/" on Windows
|
||||
//"/home/*user*/.local/share/Daedalic Entertainment GmbH/" on Linux
|
||||
public static readonly string SaveFolder = Path.Combine(
|
||||
public static readonly string DefaultSaveFolder = Path.Combine(
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
|
||||
"Daedalic Entertainment GmbH",
|
||||
"Barotrauma");
|
||||
#endif
|
||||
|
||||
public static string MultiplayerSaveFolder = Path.Combine(SaveFolder, "Multiplayer");
|
||||
public static string DefaultMultiplayerSaveFolder = Path.Combine(DefaultSaveFolder, "Multiplayer");
|
||||
|
||||
public static readonly string SubmarineDownloadFolder = Path.Combine("Submarines", "Downloaded");
|
||||
public static readonly string CampaignDownloadFolder = Path.Combine("Data", "Saves", "Multiplayer_Downloaded");
|
||||
@@ -43,9 +43,9 @@ namespace Barotrauma
|
||||
public static string TempPath
|
||||
{
|
||||
#if SERVER
|
||||
get { return Path.Combine(SaveFolder, "temp_server"); }
|
||||
get { return Path.Combine(GetSaveFolder(SaveType.Singleplayer), "temp_server"); }
|
||||
#else
|
||||
get { return Path.Combine(SaveFolder, "temp"); }
|
||||
get { return Path.Combine(GetSaveFolder(SaveType.Singleplayer), "temp"); }
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -198,7 +198,10 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
//deleting a multiplayer save file -> also delete character data
|
||||
if (Path.GetFullPath(Path.GetDirectoryName(filePath)).Equals(Path.GetFullPath(MultiplayerSaveFolder)))
|
||||
var fullPath = Path.GetFullPath(Path.GetDirectoryName(filePath));
|
||||
|
||||
if (fullPath.Equals(Path.GetFullPath(DefaultMultiplayerSaveFolder)) ||
|
||||
fullPath == Path.GetFullPath(GetSaveFolder(SaveType.Multiplayer)))
|
||||
{
|
||||
string characterDataSavePath = MultiPlayerCampaign.GetCharacterDataSavePath(filePath);
|
||||
if (File.Exists(characterDataSavePath))
|
||||
@@ -215,35 +218,70 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetSavePath(SaveType saveType, string saveName)
|
||||
public static string GetSaveFolder(SaveType saveType)
|
||||
{
|
||||
string folder = saveType == SaveType.Singleplayer ? SaveFolder : MultiplayerSaveFolder;
|
||||
return Path.Combine(folder, saveName);
|
||||
string folder = string.Empty;
|
||||
|
||||
if (!string.IsNullOrEmpty(GameSettings.CurrentConfig.SavePath))
|
||||
{
|
||||
folder = GameSettings.CurrentConfig.SavePath;
|
||||
if (saveType == SaveType.Multiplayer)
|
||||
{
|
||||
folder = Path.Combine(folder, "Multiplayer");
|
||||
}
|
||||
if (!Directory.Exists(folder))
|
||||
{
|
||||
DebugConsole.AddWarning($"Could not find the custom save folder \"{folder}\", creating the folder...");
|
||||
try
|
||||
{
|
||||
Directory.CreateDirectory(folder);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError($"Could not find the custom save folder \"{folder}\". Using the default save path instead.", e);
|
||||
folder = string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (string.IsNullOrEmpty(folder))
|
||||
{
|
||||
folder = saveType == SaveType.Singleplayer ? DefaultSaveFolder : DefaultMultiplayerSaveFolder;
|
||||
}
|
||||
return folder;
|
||||
}
|
||||
|
||||
public static IReadOnlyList<CampaignMode.SaveInfo> GetSaveFiles(SaveType saveType, bool includeInCompatible = true)
|
||||
{
|
||||
string folder = saveType == SaveType.Singleplayer ? SaveFolder : MultiplayerSaveFolder;
|
||||
if (!Directory.Exists(folder))
|
||||
string defaultFolder = saveType == SaveType.Singleplayer ? DefaultSaveFolder : DefaultMultiplayerSaveFolder;
|
||||
if (!Directory.Exists(defaultFolder))
|
||||
{
|
||||
DebugConsole.Log("Save folder \"" + folder + " not found! Attempting to create a new folder...");
|
||||
DebugConsole.Log("Save folder \"" + defaultFolder + " not found! Attempting to create a new folder...");
|
||||
try
|
||||
{
|
||||
Directory.CreateDirectory(folder);
|
||||
Directory.CreateDirectory(defaultFolder);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to create the folder \"" + folder + "\"!", e);
|
||||
DebugConsole.ThrowError("Failed to create the folder \"" + defaultFolder + "\"!", e);
|
||||
}
|
||||
}
|
||||
|
||||
List<string> files = Directory.GetFiles(folder, "*.save", System.IO.SearchOption.TopDirectoryOnly).ToList();
|
||||
List<string> files = Directory.GetFiles(defaultFolder, "*.save", System.IO.SearchOption.TopDirectoryOnly).ToList();
|
||||
|
||||
var folder = GetSaveFolder(saveType);
|
||||
if (!string.IsNullOrEmpty(folder) && Directory.Exists(folder))
|
||||
{
|
||||
files.AddRange(Directory.GetFiles(folder, "*.save", System.IO.SearchOption.TopDirectoryOnly));
|
||||
}
|
||||
|
||||
string legacyFolder = saveType == SaveType.Singleplayer ? LegacySaveFolder : LegacyMultiplayerSaveFolder;
|
||||
if (Directory.Exists(legacyFolder))
|
||||
{
|
||||
files.AddRange(Directory.GetFiles(legacyFolder, "*.save", System.IO.SearchOption.TopDirectoryOnly));
|
||||
}
|
||||
|
||||
files = files.Distinct().ToList();
|
||||
|
||||
List<CampaignMode.SaveInfo> saveInfos = new List<CampaignMode.SaveInfo>();
|
||||
foreach (string file in files)
|
||||
{
|
||||
@@ -305,7 +343,7 @@ namespace Barotrauma
|
||||
{
|
||||
fileName = ToolBox.RemoveInvalidFileNameChars(fileName);
|
||||
|
||||
string folder = saveType == SaveType.Singleplayer ? SaveFolder : MultiplayerSaveFolder;
|
||||
string folder = GetSaveFolder(saveType);
|
||||
if (fileName == "Save_Default")
|
||||
{
|
||||
fileName = TextManager.Get("SaveFile.DefaultName").Value;
|
||||
|
||||
@@ -3,6 +3,7 @@ using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Barotrauma.IO;
|
||||
using System.Linq;
|
||||
@@ -101,7 +102,7 @@ namespace Barotrauma
|
||||
|
||||
string startPath = directory ?? "";
|
||||
|
||||
string saveFolder = SaveUtil.SaveFolder.Replace('\\', '/');
|
||||
string saveFolder = SaveUtil.DefaultSaveFolder.Replace('\\', '/');
|
||||
if (originalFilename.Replace('\\', '/').StartsWith(saveFolder))
|
||||
{
|
||||
//paths that lead to the save folder might have incorrect case,
|
||||
@@ -721,5 +722,119 @@ namespace Barotrauma
|
||||
{
|
||||
return TextManager.GetWithVariable("percentageformat", "[value]", ((int)MathF.Round(v * 100)).ToString()).Value;
|
||||
}
|
||||
|
||||
private static readonly ImmutableHashSet<char> affectedCharacters = ImmutableHashSet.Create('%', '+', '%');
|
||||
|
||||
/// <summary>
|
||||
/// Extends % and + characters to color tags in talent name tooltips to make them look nicer.
|
||||
/// This obviously does not work in languages like French where a non breaking space is used
|
||||
/// so it's just a a bit extra for the languages it works with.
|
||||
/// </summary>
|
||||
/// <param name="original"></param>
|
||||
/// <returns></returns>
|
||||
public static string ExtendColorToPercentageSigns(string original)
|
||||
{
|
||||
const string colorEnd = "‖color:end‖",
|
||||
colorStart = "‖color:";
|
||||
|
||||
const char definitionIndicator = '‖';
|
||||
|
||||
char[] chars = original.ToCharArray();
|
||||
|
||||
for (int i = 0; i < chars.Length; i++)
|
||||
{
|
||||
if (!TryGetAt(i, chars, out char currentChar) || !affectedCharacters.Contains(currentChar)) { continue; }
|
||||
|
||||
// look behind
|
||||
if (TryGetAt(i - 1, chars, out char c) && c is definitionIndicator)
|
||||
{
|
||||
int offset = colorEnd.Length;
|
||||
|
||||
if (MatchesSequence(i - offset, colorEnd, chars))
|
||||
{
|
||||
// push the color end tag forwards until the character is within the tag
|
||||
char prev = currentChar;
|
||||
for (int k = i - offset; k <= i; k++)
|
||||
{
|
||||
if (!TryGetAt(k, chars, out c)) { continue; }
|
||||
|
||||
chars[k] = prev;
|
||||
prev = c;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// look ahead
|
||||
if (TryGetAt(i + 1, chars, out c) && c is definitionIndicator)
|
||||
{
|
||||
if (!MatchesSequence(i + 1, colorStart, chars)) { continue; }
|
||||
|
||||
int offset = FindNextDefinitionOffset(i, colorStart.Length, chars);
|
||||
|
||||
// we probably reached the end of the string
|
||||
if (offset > chars.Length) { continue; }
|
||||
|
||||
// push the color start tag back until the character is within the tag
|
||||
char prev = currentChar;
|
||||
for (int k = i + offset; k >= i; k--)
|
||||
{
|
||||
if (!TryGetAt(k, chars, out c)) { continue; }
|
||||
|
||||
chars[k] = prev;
|
||||
prev = c;
|
||||
}
|
||||
|
||||
// skip needlessly checking this section again since we already know what's ahead
|
||||
i += offset;
|
||||
}
|
||||
}
|
||||
|
||||
static int FindNextDefinitionOffset(int index, int initialOffset, char[] chars)
|
||||
{
|
||||
int offset = initialOffset;
|
||||
while (TryGetAt(index + offset, chars, out char c) && c is not definitionIndicator) { offset++; }
|
||||
return offset;
|
||||
}
|
||||
|
||||
static bool MatchesSequence(int index, string sequence, char[] chars)
|
||||
{
|
||||
for (int i = 0; i < sequence.Length; i++)
|
||||
{
|
||||
if (!TryGetAt(index + i, chars, out char c) || c != sequence[i]) { return false; }
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool TryGetAt(int i, char[] chars, out char c)
|
||||
{
|
||||
if (i >= 0 && i < chars.Length)
|
||||
{
|
||||
c = chars[i];
|
||||
return true;
|
||||
}
|
||||
|
||||
c = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
return new string(chars);
|
||||
}
|
||||
|
||||
public static bool StatIdentifierMatches(Identifier original, Identifier match)
|
||||
{
|
||||
if (original == match) { return true; }
|
||||
|
||||
for (int i = 0; i < match.Value.Length; i++)
|
||||
{
|
||||
if (i >= original.Value.Length) { return match[i] is '~'; }
|
||||
if (!CharEquals(original[i], match[i])) { return false; }
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
static bool CharEquals(char a, char b) => char.ToLowerInvariant(a) == char.ToLowerInvariant(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user