refac the "speedrun" mode

By not detecting new saves correctly before, players were sent all moons while still being in cap kingdom.
Having those moons made the game crash if the cutscenes from cap to cascade were skipped.

Changes:
- Rename: `speedrun => `disableShineSync`.
- Correctly detect new saves by scenario 1 instead of 0.
- Let all stages that are not cap in scenario 1 enable shine sync again (e.g. for switching back to an older save).
- Only disable shine sync once and not on every stage change (e.g. when entering cap overworld again and again).
- Disable shine bag clearing by default, option to enable it again via `Shines/ClearOnNewSaves` (for speedruns).
- Persist shines after clearing (otherwise a server crash/restart might load old moons from a previous run and sync them).
- Clear only once per player till reaching cascade (otherwise collected moons might be cleared mid-run).
- Reduce delay from 15s to 2s (even w/o a delay I couldn't reproduce a crash, but keeping it feels safer).
- Only enable shine sync again after the delay, the delay was circumvented before by other tasks triggering shine sync earlier.
This commit is contained in:
Robin C. Ladiges 2023-09-23 00:12:16 +02:00
parent 61e6fcf2a3
commit f4eaf381e3
No known key found for this signature in database
GPG Key ID: B494D3DF92661B99
2 changed files with 22 additions and 16 deletions

View File

@ -66,13 +66,13 @@ server.ClientJoined += (c, _) => {
c.Metadata["loadedSave"] = false;
c.Metadata["scenario"] = (byte?) 0;
c.Metadata["2d"] = false;
c.Metadata["speedrun"] = false;
c.Metadata["disableShineSync"] = false;
};
async Task ClientSyncShineBag(Client client) {
if (!Settings.Instance.Shines.Enabled) return;
try {
if ((bool?) client.Metadata["speedrun"] ?? false) return;
if ((bool?) client.Metadata["disableShineSync"] ?? false) return;
ConcurrentBag<int> clientBag = (ConcurrentBag<int>) (client.Metadata["shineSync"] ??= new ConcurrentBag<int>());
foreach (int shine in shineBag.Except(clientBag).Except(Settings.Instance.Shines.Excluded).ToArray()) {
if (!client.Connected) return;
@ -139,21 +139,28 @@ server.PacketHandler = (c, p) => {
c.Metadata["lastGamePacket"] = gamePacket;
switch (gamePacket.Stage) {
case "CapWorldHomeStage" when gamePacket.ScenarioNum == 0:
c.Metadata["speedrun"] = true;
((ConcurrentBag<int>) (c.Metadata["shineSync"] ??= new ConcurrentBag<int>())).Clear();
shineBag.Clear();
c.Logger.Info("Entered Cap on new save, preventing moon sync until Cascade");
case "CapWorldHomeStage" when gamePacket.ScenarioNum == 1:
case "CapWorldTowerStage" when gamePacket.ScenarioNum == 1:
if (!((bool?) c.Metadata["disableShineSync"] ?? false)) {
c.Metadata["disableShineSync"] = true;
((ConcurrentBag<int>) (c.Metadata["shineSync"] ??= new ConcurrentBag<int>())).Clear();
c.Logger.Info("Entered Cap on new save, preventing moon sync until Cascade");
if (Settings.Instance.Shines.ClearOnNewSaves) {
shineBag.Clear();
c.Logger.Info("Cleared shine bags");
Task.Run(PersistShines);
}
}
break;
case "WaterfallWorldHomeStage":
bool wasSpeedrun = (bool) c.Metadata["speedrun"]!;
c.Metadata["speedrun"] = false;
if (wasSpeedrun)
default:
if ((bool?) c.Metadata["disableShineSync"] ?? false) {
Task.Run(async () => {
c.Logger.Info("Entered Cascade with moon sync disabled, enabling moon sync");
await Task.Delay(15000);
c.Logger.Info("Entered Cascade or later with moon sync disabled, enabling moon sync again");
await Task.Delay(2000);
c.Metadata["disableShineSync"] = false;
await ClientSyncShineBag(c);
});
}
break;
}
@ -574,9 +581,7 @@ CommandHandler.RegisterCommand("shine", args => {
);
case "clear" when args.Length == 1:
shineBag.Clear();
Task.Run(async () => {
await PersistShines();
});
Task.Run(PersistShines);
foreach (ConcurrentBag<int> playerBag in server.Clients.Select(serverClient =>
(ConcurrentBag<int>)serverClient.Metadata["shineSync"]!)) playerBag?.Clear();

View File

@ -81,6 +81,7 @@ public class Settings {
public class ShineTable {
public bool Enabled { get; set; } = true;
public ISet<int> Excluded { get; set; } = new SortedSet<int> { 496 };
public bool ClearOnNewSaves { get; set; } = false;
}
public class PersistShinesTable