Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/utility-sw/src/Hud/HudKit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ private static uint EntityIndex(uint indexOrHandle)

if (layouts.TryGetValue(slots.Layout, out Open? open))
{
if (open.EntityIndex == entity.Index)
if (HudLayoutIdentity.Same(open.Surface.Layout, open.EntityIndex, entity, entity.Index))
{
return open;
}
Expand Down
3 changes: 1 addition & 2 deletions apps/utility-sw/src/Hud/PracticeHud.cs
Original file line number Diff line number Diff line change
Expand Up @@ -690,7 +690,7 @@ private string RowValue(LineupRecord lineup, Vec3? at)
return from.Length > 0 ? $"{from} · {distance}" : distance;
}

private void ForgetHud(ulong steamId, int playerId)
private void ForgetHud(ulong steamId)
{
_hudOff.Remove(steamId);
_menus.Remove(steamId);
Expand All @@ -702,7 +702,6 @@ private void ForgetHud(ulong steamId, int playerId)
_mapChoices.Remove(steamId);
ForgetVerdicts(steamId);
ClearFilters(steamId);
_hud?.Forget(playerId);
}

[Command("menu", registerRaw: false, permission: "")]
Expand Down
1 change: 1 addition & 0 deletions apps/utility-sw/src/UtilityPractice.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@
Link="resources/gamedata/fivestack.gamedata.json"
CopyToOutputDirectory="PreserveNewest" />
<Compile Include="$(MSBuildThisFileDirectory)../../../shared/dotnet/FiveStack.Utilities/HudSteady.cs" LinkBase="Shared" />
<Compile Include="$(MSBuildThisFileDirectory)../../../shared/dotnet/FiveStack.Utilities/HudLayoutIdentity.cs" LinkBase="Shared" />
<Compile Include="$(MSBuildThisFileDirectory)../../../shared/dotnet/FiveStack.Utilities/LineupNaming.cs" LinkBase="Shared" />
<Compile Include="$(MSBuildThisFileDirectory)../../../shared/dotnet/FiveStack.Utilities/ApproachUtility.cs" LinkBase="Shared" />
<Compile Include="$(MSBuildThisFileDirectory)../../../shared/dotnet/FiveStack.Utilities/SmokeVoxelCapture.cs" LinkBase="Shared" />
Expand Down
16 changes: 15 additions & 1 deletion apps/utility-sw/src/UtilityPracticePlugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ private sealed class LibraryLoad
private EventDelegates.OnClientDisconnected? _disconnectHandler;
private EventDelegates.OnPrecacheResource? _precacheHandler;
private EventDelegates.OnClientSteamAuthorize? _authorizeHandler;
private EventDelegates.OnClientPutInServer? _putInServerHandler;
private EventDelegates.OnCustomHudClicked? _hudClickHandler;

public UtilityPracticePlugin(ISwiftlyCore core)
Expand Down Expand Up @@ -265,6 +266,7 @@ public override void Load(bool hotReload)
_occupancyDirty = true;
_prompt?.Cancel(@event.PlayerId);
_replay.ForgetViewer(@event.PlayerId);
_hud?.Forget(@event.PlayerId);

ForPlayer(
@event.PlayerId,
Expand All @@ -275,7 +277,7 @@ public override void Load(bool hotReload)
// invalidated never reaches this at all, which is why the
// drain prunes off the roster as well.
_libraryLoads.Remove(steamId);
ForgetHud(steamId, @event.PlayerId);
ForgetHud(steamId);
OnPlayerGone(steamId);
}
);
Expand All @@ -292,6 +294,13 @@ public override void Load(bool hotReload)
};
Core.Event.OnClientSteamAuthorize += _authorizeHandler;

// Only the slot: ForgetHud also clears settings that outlive a map change.
_putInServerHandler = @event =>
{
_hud?.Forget(@event.PlayerId);
};
Core.Event.OnClientPutInServer += _putInServerHandler;

InitializeConnectClientHook();
InitializeTerminateRoundHook();

Expand Down Expand Up @@ -501,6 +510,11 @@ private void TearDown()
Core.Event.OnClientSteamAuthorize -= _authorizeHandler;
}

if (_putInServerHandler != null)
{
Core.Event.OnClientPutInServer -= _putInServerHandler;
}

UninstallConnectClientHook();
UninstallTerminateRoundHook();

Expand Down
1 change: 1 addition & 0 deletions apps/utility-sw/test/FiveStack.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
<Compile Include="$(MSBuildThisFileDirectory)../../../shared/dotnet/FiveStack.Utilities/UtilityTargetCluster.cs" LinkBase="Shared" />
<Compile Include="$(MSBuildThisFileDirectory)../../../shared/dotnet/FiveStack.Utilities/RadarMaps.cs" LinkBase="Shared" />
<Compile Include="$(MSBuildThisFileDirectory)../../../shared/dotnet/FiveStack.Utilities/HudSteady.cs" LinkBase="Shared" />
<Compile Include="$(MSBuildThisFileDirectory)../../../shared/dotnet/FiveStack.Utilities/HudLayoutIdentity.cs" LinkBase="Shared" />
<Compile Include="$(MSBuildThisFileDirectory)../../../shared/dotnet/FiveStack.Utilities/LineupNaming.cs" LinkBase="Shared" />
<Compile Include="$(MSBuildThisFileDirectory)../../../shared/dotnet/FiveStack.Utilities/ApproachUtility.cs" LinkBase="Shared" />
<Compile Include="$(MSBuildThisFileDirectory)../../../shared/dotnet/FiveStack.Utilities/SmokeVoxelCapture.cs" LinkBase="Shared" />
Expand Down
117 changes: 117 additions & 0 deletions apps/utility-sw/test/HudSlotResetTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
using System.Text.RegularExpressions;
using FiveStack.Utilities;
using Xunit;

public class HudSlotResetTests
{
private const uint Index = 412;

// Comments out first: a call that has been commented out is not a call.
private static string Code(params string[] path)
{
DirectoryInfo? directory = new DirectoryInfo(AppContext.BaseDirectory);

while (directory != null)
{
string candidate = Path.Combine(
new[] { directory.FullName, "apps", "utility-sw", "src" }.Concat(path).ToArray()
);

if (File.Exists(candidate))
{
return Regex.Replace(File.ReadAllText(candidate), @"//[^\n]*", "");
}

directory = directory.Parent;
}

throw new FileNotFoundException($"{path[^1]} was not found above the test output");
}

private static string Hook(string start, string end)
{
string source = Code("UtilityPracticePlugin.cs");
int from = source.IndexOf(start, StringComparison.Ordinal);

Assert.True(from >= 0, $"{start} is gone");

int to = source.IndexOf(end, from, StringComparison.Ordinal);

Assert.True(to >= 0, $"{end} is gone");

return source[from..to];
}

[Fact]
public void TheSameEntityKeepsItsSurface()
{
object layout = new();

Assert.True(HudLayoutIdentity.Same(layout, Index, layout, Index));
}

[Fact]
public void ALayoutRespawnedOnTheFreedIndexIsANewLayout()
{
Assert.False(HudLayoutIdentity.Same(new object(), Index, new object(), Index));
}

[Fact]
public void ALayoutOnAnotherIndexIsANewLayout()
{
object layout = new();

Assert.False(HudLayoutIdentity.Same(layout, Index, layout, Index + 1));
}

[Fact]
public void ADisconnectForgetsTheSlotWithoutResolvingTheLeaver()
{
string beforeResolving = Hook("_disconnectHandler = @event =>", "ForPlayer(");

Assert.Contains("_hud?.Forget(@event.PlayerId);", beforeResolving);
Assert.Contains(
"Core.Event.OnClientDisconnected += _disconnectHandler;",
Code("UtilityPracticePlugin.cs")
);
}

[Fact]
public void AnArrivalForgetsWhateverTheSlotWasHolding()
{
string hook = Hook("_putInServerHandler = @event =>", "};");

Assert.Contains("_hud?.Forget(@event.PlayerId);", hook);
Assert.Contains(
"Core.Event.OnClientPutInServer += _putInServerHandler;",
Code("UtilityPracticePlugin.cs")
);
}

[Fact]
public void TheArrivalHookIsLetGoOnUnload()
{
Assert.Contains(
"Core.Event.OnClientPutInServer -= _putInServerHandler;",
Code("UtilityPracticePlugin.cs")
);
}

[Fact]
public void AnArrivalLeavesAPlayersOwnHudSettingsAlone()
{
Assert.DoesNotContain("ForgetHud", Hook("_putInServerHandler = @event =>", "};"));
}

[Fact]
public void TheKitAsksTheIdentityRuleBeforeKeepingASurface()
{
string kit = Code("Hud", "HudKit.cs");

Assert.Contains(
"HudLayoutIdentity.Same(open.Surface.Layout, open.EntityIndex, entity, entity.Index)",
kit
);
Assert.DoesNotContain("open.EntityIndex == entity.Index", kit);
}
}
12 changes: 12 additions & 0 deletions shared/dotnet/FiveStack.Utilities/HudLayoutIdentity.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace FiveStack.Utilities;

// Whether a surface can still be used on the layout entity in hand. A respawned
// entity can be given the index the old one freed, and what was sent to the old
// one is gone with it, so the index alone does not say the client holds anything.
public static class HudLayoutIdentity
{
public static bool Same(object held, uint heldIndex, object current, uint currentIndex)
{
return heldIndex == currentIndex && ReferenceEquals(held, current);
}
}
Loading