Skip to content

Commit

Permalink
Merge pull request #3 from BigBang1112/dev
Browse files Browse the repository at this point in the history
  • Loading branch information
BigBang1112 authored Dec 12, 2022
2 parents 16fe285 + 5beb128 commit 378468a
Show file tree
Hide file tree
Showing 15 changed files with 184 additions and 70 deletions.
76 changes: 61 additions & 15 deletions Src/RandomizerTMF.Logic/RandomizerEngine.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
using GBX.NET;
using GBX.NET.Engines.Game;
using GBX.NET.Exceptions;
using Microsoft.Extensions.Logging;
using RandomizerTMF.Logic.Exceptions;
using RandomizerTMF.Logic.TypeConverters;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Net;
using System.Text.RegularExpressions;
using TmEssentials;
using YamlDotNet.Serialization;

namespace RandomizerTMF.Logic;

public static class RandomizerEngine
public static partial class RandomizerEngine
{
private static readonly int requestMaxAttempts = 10;
private static int requestAttempt;
Expand Down Expand Up @@ -109,6 +111,9 @@ private set
public static StreamWriter LogWriter { get; private set; }
public static StreamWriter? CurrentSessionLogWriter { get; private set; }
public static bool SessionEnding { get; private set; }

[GeneratedRegex("[^a-zA-Z0-9_.]+")]
private static partial Regex SpecialCharRegex();

static RandomizerEngine()
{
Expand Down Expand Up @@ -292,8 +297,8 @@ private static void UpdateSessionDataFromAutosave(string fullPath, SessionMap ma
_ => ""
} + replay.Time.ToTmString(useHundredths: true, useApostrophe: true);

var mapName = TextFormatter.Deformat(map.Map.MapName).Trim();
var mapName = SpecialCharRegex().Replace(TextFormatter.Deformat(map.Map.MapName).Trim(), "_");

var replayFileFormat = string.IsNullOrWhiteSpace(Config.ReplayFileFormat)
? Constants.DefaultReplayFileFormat
: Config.ReplayFileFormat;
Expand Down Expand Up @@ -541,9 +546,13 @@ public static bool ScanAutosaves()

anythingChanged = true;
}
catch
catch (NotAGbxException)
{
// Errors get lost currently
// do nothing
}
catch (Exception ex)
{
Logger.LogWarning(ex, "Gbx error found in the Autosaves folder when reading the header.");
}
}

Expand Down Expand Up @@ -775,22 +784,57 @@ public static void ValidateRules()
throw new RuleValidationException("Time limit cannot be above 9:59:59");
}

if (Config.Rules.RequestRules.PrimaryType is EPrimaryType.Platform
&& (Config.Rules.RequestRules.Site.HasFlag(ESite.TMNF) || Config.Rules.RequestRules.Site.HasFlag(ESite.Nations)))
foreach (var primaryType in Enum.GetValues<EPrimaryType>())
{
throw new RuleValidationException("Platform is not valid with TMNF or Nations Exchange");
if (primaryType is EPrimaryType.Race)
{
continue;
}

if (Config.Rules.RequestRules.PrimaryType == primaryType
&& (Config.Rules.RequestRules.Site == ESite.Any
|| Config.Rules.RequestRules.Site.HasFlag(ESite.TMNF) || Config.Rules.RequestRules.Site.HasFlag(ESite.Nations)))
{
throw new RuleValidationException($"{primaryType} is not valid with TMNF or Nations Exchange");
}
}

if (Config.Rules.RequestRules.PrimaryType is EPrimaryType.Stunts
&& (Config.Rules.RequestRules.Site.HasFlag(ESite.TMNF) || Config.Rules.RequestRules.Site.HasFlag(ESite.Nations)))
if (Config.Rules.RequestRules.Environment is not null || Config.Rules.RequestRules.Vehicle is not null)
{
throw new RuleValidationException("Stunts is not valid with TMNF or Nations Exchange");
foreach (var env in Enum.GetValues<EEnvironment>())
{
if (env is EEnvironment.Stadium)
{
continue;
}

if (Config.Rules.RequestRules.Site != ESite.Any && !Config.Rules.RequestRules.Site.HasFlag(ESite.TMNF) && !Config.Rules.RequestRules.Site.HasFlag(ESite.Nations))
{
continue;
}

if (Config.Rules.RequestRules.Environment?.Contains(env) == true)
{
throw new RuleValidationException($"{env} is not valid with TMNF or Nations Exchange");
}

if (Config.Rules.RequestRules.Vehicle?.Contains(env) == true)
{
throw new RuleValidationException($"{env}Car is not valid with TMNF or Nations Exchange");
}
}
}

if (Config.Rules.RequestRules.EqualEnvironmentDistribution
&& Config.Rules.RequestRules.Site.HasFlag(ESite.TMNF) || Config.Rules.RequestRules.Site.HasFlag(ESite.Nations))
{
throw new RuleValidationException($"Equal environment distribution is not valid with TMNF or Nations Exchange");
}

if (Config.Rules.RequestRules.PrimaryType is EPrimaryType.Puzzle
&& (Config.Rules.RequestRules.Site.HasFlag(ESite.TMNF) || Config.Rules.RequestRules.Site.HasFlag(ESite.Nations)))
if (Config.Rules.RequestRules.EqualVehicleDistribution
&& Config.Rules.RequestRules.Site.HasFlag(ESite.TMNF) || Config.Rules.RequestRules.Site.HasFlag(ESite.Nations))
{
throw new RuleValidationException("Puzzle is not valid with TMNF or Nations Exchange");
throw new RuleValidationException($"Equal vehicle distribution is not valid with TMNF or Nations Exchange");
}
}

Expand Down Expand Up @@ -848,7 +892,7 @@ private static void SetReadOnlySessionYml()
private static async Task PrepareNewMapAsync(CancellationToken cancellationToken)
{
Status("Fetching random track...");

// Randomized URL is constructed with the ToUrl() method.
var requestUrl = Config.Rules.RequestRules.ToUrl();

Expand Down Expand Up @@ -993,6 +1037,8 @@ private static async Task PrepareNewMapAsync(CancellationToken cancellationToken
SaveSessionData(); // May not be super necessary?
}



/// <summary>
/// Handles the play loop of a map. Throws cancellation exception on session end (not the map end).
/// </summary>
Expand Down
2 changes: 1 addition & 1 deletion Src/RandomizerTMF.Logic/RandomizerTMF.Logic.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<Version>1.0.1</Version>
<Version>1.0.2</Version>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
Expand Down
50 changes: 46 additions & 4 deletions Src/RandomizerTMF.Logic/RequestRules.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
using System.Collections;
using System.Diagnostics;
using System.Reflection;
using System.Text;
using TmEssentials;

namespace RandomizerTMF.Logic;

public class RequestRules
{
private static readonly ESite[] siteValues = Enum.GetValues<ESite>();
private static readonly EEnvironment[] envValues = Enum.GetValues<EEnvironment>();

// Custom rules that are not part of the official API

public required ESite Site { get; set; }
public bool EqualEnvironmentDistribution { get; set; }
public bool EqualVehicleDistribution { get; set; }

public string? Author { get; set; }
public HashSet<EEnvironment>? Environment { get; set; }
Expand Down Expand Up @@ -40,12 +48,12 @@ public string ToUrl() // Not very efficient but does the job done fast enough
{
var b = new StringBuilder("https://");

var matchingSites = Enum.GetValues<ESite>()
var matchingSites = siteValues
.Where(x => x != ESite.Any && (Site & x) == x)
.ToArray();

var siteUrl = GetSiteUrl(matchingSites.Length == 0
? Enum.GetValues<ESite>().Where(x => x is not ESite.Any).ToArray()
? siteValues.Where(x => x is not ESite.Any).ToArray()
: matchingSites);

b.Append(siteUrl);
Expand All @@ -54,9 +62,21 @@ public string ToUrl() // Not very efficient but does the job done fast enough

var first = true;

foreach (var prop in GetType().GetProperties().Where(x => x.Name != nameof(Site)))
foreach (var prop in GetType().GetProperties().Where(DoesNotSkip))
{
if (prop.GetValue(this) is not object val || val is null || (val is IEnumerable enumerable && !enumerable.Cast<object>().Any()))
var val = prop.GetValue(this);

if (EqualEnvironmentDistribution && prop.Name == nameof(Environment))
{
val = GetRandomEnvironmentThroughSet(Environment);
}

if (EqualVehicleDistribution && prop.Name == nameof(Vehicle))
{
val = GetRandomEnvironmentThroughSet(Vehicle);
}

if (val is null || (val is IEnumerable enumerable && !enumerable.Cast<object>().Any()))
{
continue;
}
Expand Down Expand Up @@ -89,6 +109,28 @@ public string ToUrl() // Not very efficient but does the job done fast enough
return b.ToString();
}

private bool DoesNotSkip(PropertyInfo prop)
{
return prop.Name is not nameof(Site)
and not nameof(EqualEnvironmentDistribution)
and not nameof(EqualVehicleDistribution);
}

private static EEnvironment GetRandomEnvironment(HashSet<EEnvironment>? container)
{
if (container is null || container.Count == 0)
{
return (EEnvironment)Random.Shared.Next(0, envValues.Length); // Safe in case of EEnvironment
}

return container.ElementAt(Random.Shared.Next(0, container.Count));
}

private static HashSet<EEnvironment> GetRandomEnvironmentThroughSet(HashSet<EEnvironment>? container)
{
return new HashSet<EEnvironment>() { GetRandomEnvironment(container) };
}

private static string GetSiteUrl(ESite[] matchingSites)
{
var randomSite = matchingSites[Random.Shared.Next(matchingSites.Length)];
Expand Down
6 changes: 1 addition & 5 deletions Src/RandomizerTMF/Models/SessionDataMapModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,6 @@ public SessionDataMapModel(SessionDataMap map)

public void TmxClick()
{
Process.Start(new ProcessStartInfo
{
FileName = Map.TmxLink,
UseShellExecute = true
});
ProcessUtils.OpenUrl(Map.TmxLink);
}
}
2 changes: 1 addition & 1 deletion Src/RandomizerTMF/Models/SessionDataReplayModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public SessionDataReplayModel(SessionDataReplay replay, string sessionStr, bool
Replay = replay;

var path = Path.Combine(Constants.Sessions, sessionStr, Constants.Replays, replay.FileName);
var node = GameBox.ParseNode<CGameCtnReplayRecord>(path.Replace("\uFEFF", ""));
var node = GameBox.ParseNode<CGameCtnReplayRecord>(path);

if (first)
{
Expand Down
25 changes: 25 additions & 0 deletions Src/RandomizerTMF/ProcessUtils.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System.Diagnostics;

namespace RandomizerTMF;

public static class ProcessUtils
{
public static void OpenUrl(string url)
{
Process.Start(new ProcessStartInfo
{
FileName = url,
UseShellExecute = true
});
}

public static void OpenDir(string dirPath)
{
Process.Start(new ProcessStartInfo()
{
FileName = dirPath,
UseShellExecute = true,
Verb = "open"
});
}
}
2 changes: 1 addition & 1 deletion Src/RandomizerTMF/RandomizerTMF.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
</PropertyGroup>

<PropertyGroup>
<Version>1.0.1</Version>
<Version>1.0.2</Version>
<PublishSingleFile>true</PublishSingleFile>
<EnableCompressionInSingleFile>true</EnableCompressionInSingleFile>
</PropertyGroup>
Expand Down
6 changes: 1 addition & 5 deletions Src/RandomizerTMF/ViewModels/AboutWindowViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,6 @@ public void UpdateClick()

private void OpenWeb(string site)
{
Process.Start(new ProcessStartInfo
{
FileName = site,
UseShellExecute = true
});
ProcessUtils.OpenUrl(site);
}
}
14 changes: 2 additions & 12 deletions Src/RandomizerTMF/ViewModels/DashboardWindowViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -274,25 +274,15 @@ public void OpenDownloadedMapsFolderClick()
{
if (RandomizerEngine.DownloadedDirectoryPath is not null)
{
OpenFolder(RandomizerEngine.DownloadedDirectoryPath + Path.DirectorySeparatorChar);
ProcessUtils.OpenDir(RandomizerEngine.DownloadedDirectoryPath + Path.DirectorySeparatorChar);
}
}

public void OpenSessionsFolderClick()
{
if (RandomizerEngine.SessionsDirectoryPath is not null)
{
OpenFolder(RandomizerEngine.SessionsDirectoryPath + Path.DirectorySeparatorChar);
ProcessUtils.OpenDir(RandomizerEngine.SessionsDirectoryPath + Path.DirectorySeparatorChar);
}
}

private static void OpenFolder(string folderPath)
{
Process.Start(new ProcessStartInfo()
{
FileName = folderPath,
UseShellExecute = true,
Verb = "open"
});
}
}
26 changes: 26 additions & 0 deletions Src/RandomizerTMF/ViewModels/RequestRulesControlViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -926,5 +926,31 @@ public DateTimeOffset? UploadedBefore
}
}

public bool EqualEnvDistribution
{
get => RandomizerEngine.Config.Rules.RequestRules.EqualEnvironmentDistribution;
set
{
RandomizerEngine.Config.Rules.RequestRules.EqualEnvironmentDistribution = value;

this.RaisePropertyChanged(nameof(EqualEnvDistribution));

RandomizerEngine.SaveConfig();
}
}

public bool EqualVehicleDistribution
{
get => RandomizerEngine.Config.Rules.RequestRules.EqualVehicleDistribution;
set
{
RandomizerEngine.Config.Rules.RequestRules.EqualVehicleDistribution = value;

this.RaisePropertyChanged(nameof(EqualVehicleDistribution));

RandomizerEngine.SaveConfig();
}
}

public void UploadedBeforeReset() => UploadedBefore = null;
}
Loading

0 comments on commit 378468a

Please sign in to comment.