Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Patch for UndercaveMapComponent (pit gate) #470

Merged
merged 1 commit into from
Jul 14, 2024
Merged
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
60 changes: 60 additions & 0 deletions Source/Client/Patches/Determinism.cs
Original file line number Diff line number Diff line change
@@ -524,4 +524,64 @@ static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> inst
}
}

[HarmonyPatch(typeof(UndercaveMapComponent), nameof(UndercaveMapComponent.MapComponentTick))]
static class DeterministicUndercaveRockCollapse
{
static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instr)
{
var target = MethodOf.Lambda(Rand.MTBEventOccurs);

foreach (var ci in instr)
{
yield return ci;

// Add "& false" to any call to Rand.MTBEventOccurs.
// We'll handle those calls in our postfix.
if (ci.Calls(target))
{
yield return new CodeInstruction(OpCodes.Ldc_I4_0);
yield return new CodeInstruction(OpCodes.And);
}
}
}

static void Prefix() => Rand.PushState();

static void Postfix(UndercaveMapComponent __instance)
{
// Pop the RNG state from the prefix
Rand.PopState();

// Make sure the pit gate is collapsing
if (__instance.pitGate is not { IsCollapsing: true })
return;

// Check if the rocks should collapse
var mtb = UndercaveMapComponent.HoursToShakeMTBTicksCurve.Evaluate(__instance.pitGate.TicksUntilCollapse / 2500f);
if (!Rand.MTBEventOccurs(mtb, 1, 1))
return;

// Since the number of RNG calls will depend on numDustEffecters argument, we need to push/pop the RNG state.
// The RNG calls related to simulation will happen first, followed by the one determined by amount of
// effecters - it would not be MP safe, but since it happens last it will be fine once we pop the state.
Rand.PushState();

// If not looking at the map, trigger the collapse without shake/effecters (since it's not needed for current player).
// The call to play a sound is handled by RW itself, since it targets a specific map already.
if (Find.CurrentMap != __instance.map)
{
// Progress the RNG state, matching the RandomInRange call in other two cases
Rand.RangeInclusive(0, 100);
__instance.TriggerCollapseFX(0, 0);
}
// Else, follow vanilla shake/effecter rules
else if (__instance.pitGate.CollapseStage == 1)
__instance.TriggerCollapseFX(UndercaveMapComponent.StageOneShakeAmount, UndercaveMapComponent.StageOneNumCollapseEffects.RandomInRange);
else
__instance.TriggerCollapseFX(UndercaveMapComponent.StageTwoShakeAmount, UndercaveMapComponent.StageTwoNumCollapseEffects.RandomInRange);

Rand.PopState();
}
}

}

Unchanged files with check annotations Beta

base.WriteLong(val);
}
public override void WritePrefixedBytes(byte[] bytes)

Check warning on line 51 in Source/Common/Syncing/Logger/LoggingByteWriter.cs

GitHub Actions / Builds

Nullability of type of parameter 'bytes' doesn't match overridden member (possibly because of nullability attributes).
{
Log.Enter("byte[]");
base.WritePrefixedBytes(bytes);
Log.Exit();
}
public override ByteWriter WriteString(string s)

Check warning on line 58 in Source/Common/Syncing/Logger/LoggingByteWriter.cs

GitHub Actions / Builds

Nullability of type of parameter 's' doesn't match overridden member (possibly because of nullability attributes).
{
Log.Enter("string: " + s);
base.WriteString(s);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static void TheLinuxWay() => mono_dllmap_insert_linux(IntPtr.Zero, MonoWindows, null, MonoLinux, null);

Check warning on line 36 in Source/Common/Native.cs

GitHub Actions / Builds

Cannot convert null literal to non-nullable reference type.

Check warning on line 36 in Source/Common/Native.cs

GitHub Actions / Builds

Cannot convert null literal to non-nullable reference type.
[MethodImpl(MethodImplOptions.NoInlining)]
static void TheOSXWay() => mono_dllmap_insert_osx(IntPtr.Zero, MonoWindows, null, MonoOSX, null);

Check warning on line 39 in Source/Common/Native.cs

GitHub Actions / Builds

Cannot convert null literal to non-nullable reference type.

Check warning on line 39 in Source/Common/Native.cs

GitHub Actions / Builds

Cannot convert null literal to non-nullable reference type.
[MethodImpl(MethodImplOptions.NoInlining)]
private static void EarlyInitInternal()
{
public bool requiresHost;
public MultiplayerServer Server => MultiplayerServer.instance;

Check warning on line 7 in Source/Common/ChatCommands.cs

GitHub Actions / Builds

Possible null reference return.
public abstract void Handle(IChatSource source, string[] args);
{
public class ServerLog : INetLogger
{
public static Action<string> info;

Check warning on line 8 in Source/Common/Util/ServerLog.cs

GitHub Actions / Builds

Non-nullable field 'info' must contain a non-null value when exiting constructor. Consider declaring the field as nullable.
public static Action<string> error;

Check warning on line 9 in Source/Common/Util/ServerLog.cs

GitHub Actions / Builds

Non-nullable field 'error' must contain a non-null value when exiting constructor. Consider declaring the field as nullable.
public static bool detailEnabled;
public static bool verboseEnabled;
}
public bool CanUseDevMode(ServerPlayer player) =>
server.settings.debugMode && server.settings.devModeScope switch

Check warning on line 82 in Source/Common/CommandHandler.cs

GitHub Actions / Builds

The switch expression does not handle some values of its input type (it is not exhaustive) involving an unnamed enum value. For example, the pattern '(Multiplayer.Common.DevModeScope)2' is not covered.
{
DevModeScope.Everyone => true,
DevModeScope.HostOnly => player.IsHost