Skip to content

Commit

Permalink
Revert "Refactor Ramping Event Scheduler (#592)" (#644)
Browse files Browse the repository at this point in the history
# Description
This reverts commit 910b4c3.

The PR was never tested properly, and after it was merged on deep
station, a lot of significant issues have been uncovered, including
station events appearing every 6-12 seconds regardless of the gamemode,
some RampingStationEventScheduler component fields being unused, some
CVars having misleading usages, some CVars being unused, and more.

The PR needs to be re-done and tested thoroughly before it can be
merged.

:cl:
- fix: Reverted the station event scheduler rework due to it absolutely
breaking the game.
  • Loading branch information
Mnemotechnician authored Aug 2, 2024
1 parent d25a25c commit 58a1f88
Show file tree
Hide file tree
Showing 6 changed files with 45 additions and 109 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,50 +4,38 @@
public sealed partial class RampingStationEventSchedulerComponent : Component
{
/// <summary>
/// Multiplies the End Time of the Ramping Event curve. Lower this number for shorter, hectic shifts, increase this number for longer shifts.
/// The maximum number by which the event rate will be multiplied when shift time reaches the end time.
/// </summary>
[DataField]
public float ShiftChaosModifier = 1f;
public float ChaosModifier = 3f;

/// <summary>
/// The number by which all event delays will be multiplied. Unlike chaos, remains constant throughout the shift.
/// The minimum number by which the event rate will be multiplied when the shift has just begun.
/// </summary>
[DataField]
public float EventDelayModifier = 1f;

public float StartingChaosRatio = 0.1f;

/// <summary>
/// Shift Length(in Minutes) is directly reduced by this value.
/// </summary>
[DataField]
public float ShiftLengthOffset = 0f;

/// <summary>
/// Minimum time between events is decreased by this value.
/// The number by which all event delays will be multiplied. Unlike chaos, remains constant throughout the shift.
/// </summary>
[DataField]
public float MinimumEventTimeOffset = 0f;
public float EventDelayModifier = 1f;

/// <summary>
/// Maximum time between events is decreased by this value.
/// The number by which average expected shift length is multiplied. Higher values lead to slower chaos growth.
/// </summary>

[DataField]
public float MaximumEventTimeOffset = 0f;

[DataField]
public bool IgnoreMinimumTimes = false;
public float ShiftLengthModifier = 1f;

// Everything below is overridden in the RampingStationEventSchedulerSystem based on CVars
[DataField]
[DataField("endTime"), ViewVariables(VVAccess.ReadWrite)]
public float EndTime;

[DataField]
[DataField("maxChaos"), ViewVariables(VVAccess.ReadWrite)]
public float MaxChaos;

[DataField]
[DataField("startingChaos"), ViewVariables(VVAccess.ReadWrite)]
public float StartingChaos;

[DataField]
[DataField("timeUntilNextEvent"), ViewVariables(VVAccess.ReadWrite)]
public float TimeUntilNextEvent;
}
65 changes: 23 additions & 42 deletions Content.Server/StationEvents/RampingStationEventSchedulerSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
using Content.Server.GameTicking.Rules;
using Content.Server.GameTicking.Rules.Components;
using Content.Server.StationEvents.Components;
using Content.Server.StationEvents.Events;
using Content.Shared.CCVar;
using Robust.Shared.Configuration;
using Robust.Shared.Random;
using Robust.Shared.Utility;

namespace Content.Server.StationEvents;

Expand All @@ -16,35 +16,30 @@ public sealed class RampingStationEventSchedulerSystem : GameRuleSystem<RampingS
[Dependency] private readonly EventManagerSystem _event = default!;
[Dependency] private readonly GameTicker _gameTicker = default!;

/// <summary>
/// A <see href="https://www.desmos.com/calculator/87huunvoxq">logistic curve equation</see> used to smooth out the transition between event times at shift start, vs. shift end.
/// Depending on the settings used, the end time might not necessarily be the point at which timers hit the floor.
/// It is after all, an asymptote.
/// </summary>
/// <param name="component"></param>
/// <param name="startTime"></param>
/// <param name="endTimeOffset"></param>
/// <returns></returns>
public float RampingEventTimeEquation(RampingStationEventSchedulerComponent component, float startTime, float endTimeOffset = 0)
public float GetChaosModifier(EntityUid uid, RampingStationEventSchedulerComponent component)
{
var endTime = Math.Clamp(endTimeOffset, 0.1f, startTime - 1);
var shiftLength = Math.Max(1, _cfg.GetCVar(CCVars.EventsRampingAverageEndTime) - component.ShiftLengthOffset);
return 2 * endTime
/ (1
+ MathF.Exp(_cfg.GetCVar(CCVars.EventsRampingAverageChaos)
* component.ShiftChaosModifier
/ shiftLength
* endTime
* (float) _gameTicker.RoundDuration().TotalSeconds
/ 60))
+ (startTime - endTime);
var roundTime = (float) _gameTicker.RoundDuration().TotalSeconds;
if (roundTime > component.EndTime)
return component.MaxChaos;

return component.MaxChaos / component.EndTime * roundTime + component.StartingChaos;
}

protected override void Started(EntityUid uid, RampingStationEventSchedulerComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args)
{
base.Started(uid, component, gameRule, args);

PickNextEventTime(component);
var avgChaos = _cfg.GetCVar(CCVars.EventsRampingAverageChaos) * component.ChaosModifier;
var avgTime = _cfg.GetCVar(CCVars.EventsRampingAverageEndTime) * component.ShiftLengthModifier;

// Worlds shittiest probability distribution
// Got a complaint? Send them to
component.MaxChaos = avgChaos * _random.NextFloat(0.75f, 1.25f);
// This is in minutes, so *60 for seconds (for the chaos calc)
component.EndTime = avgTime * _random.NextFloat(0.75f, 1.25f) * 60f;
component.StartingChaos = component.MaxChaos * component.StartingChaosRatio;

PickNextEventTime(uid, component);
}

public override void Update(float frameTime)
Expand All @@ -66,31 +61,17 @@ public override void Update(float frameTime)
return;
}

PickNextEventTime(scheduler);
PickNextEventTime(uid, scheduler);
_event.RunRandomEvent();
}
}

private void PickNextEventTime(RampingStationEventSchedulerComponent component)
private void PickNextEventTime(EntityUid uid, RampingStationEventSchedulerComponent component)
{
// In case of server hosts being silly and setting maximum time to be lower than minimum time, sanity check the scheduler inputs and sort them by Min/Max
var minimumTime = MathF.Min(_cfg.GetCVar(CCVars.GameEventsRampingMinimumTime)
- _cfg.GetCVar(CCVars.GameEventsRampingMinimumTimeOffset)
- component.MinimumEventTimeOffset, _cfg.GetCVar(CCVars.GameEventsRampingMaximumTime)
- _cfg.GetCVar(CCVars.GameEventsRampingMaximumTimeOffset)
- component.MaximumEventTimeOffset);

var maximumTime = MathF.Max(_cfg.GetCVar(CCVars.GameEventsRampingMinimumTime)
- _cfg.GetCVar(CCVars.GameEventsRampingMinimumTimeOffset)
- component.MinimumEventTimeOffset, _cfg.GetCVar(CCVars.GameEventsRampingMaximumTime)
- _cfg.GetCVar(CCVars.GameEventsRampingMaximumTimeOffset)
- component.MaximumEventTimeOffset);

// Just in case someone messed up their math, set it to between 6 and 12 seconds. This absolutely isn't ideal
component.TimeUntilNextEvent = _random.NextFloat(
RampingEventTimeEquation(component, MathF.Max(0.1f, minimumTime)),
RampingEventTimeEquation(component, MathF.Max(0.2f, maximumTime)));
_cfg.GetCVar(CCVars.GameEventsRampingMinimumTime),
_cfg.GetCVar(CCVars.GameEventsRampingMaximumTime));

component.TimeUntilNextEvent *= component.EventDelayModifier;
component.TimeUntilNextEvent *= component.EventDelayModifier / GetChaosModifier(uid, component);
}
}
27 changes: 7 additions & 20 deletions Content.Shared/CCVar/CCVars.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ public static readonly CVarDef<float>
/// Max chaos chosen for a round will deviate from this
/// </summary>
public static readonly CVarDef<float>
EventsRampingAverageChaos = CVarDef.Create("events.ramping_average_chaos", 0.8f, CVar.ARCHIVE | CVar.SERVERONLY);
EventsRampingAverageChaos = CVarDef.Create("events.ramping_average_chaos", 6f, CVar.ARCHIVE | CVar.SERVERONLY);

/*
* Game
Expand Down Expand Up @@ -186,29 +186,16 @@ public static readonly CVarDef<int> // 25 Minutes
GameEventsBasicMaximumTime = CVarDef.Create("game.events_basic_maximum_time", 1500, CVar.SERVERONLY);

/// <summary>
/// Minimum time between Ramping station events in minutes
/// Minimum time between Ramping station events in seconds
/// </summary>
public static readonly CVarDef<float> // 8 Minutes
GameEventsRampingMinimumTime = CVarDef.Create("game.events_ramping_minimum_time", 8f, CVar.SERVERONLY);
public static readonly CVarDef<int> // 4 Minutes
GameEventsRampingMinimumTime = CVarDef.Create("game.events_ramping_minimum_time", 240, CVar.SERVERONLY);

/// <summary>
/// After the shift's desired "Endpoint" is reached, the minimum time between events is RampingMinimumTime - Offset.
/// Maximum time between Ramping station events in seconds
/// </summary>

public static readonly CVarDef<float>
GameEventsRampingMinimumTimeOffset = CVarDef.Create("game.events_ramping_minimum_time_offset", 6f, CVar.SERVERONLY);

/// <summary>
/// Maximum time between Ramping station events in minutes
/// </summary>
public static readonly CVarDef<float> // 16 Minutes
GameEventsRampingMaximumTime = CVarDef.Create("game.events_ramping_maximum_time", 16f, CVar.SERVERONLY);

/// <summary>
/// After the shift's desired "Endpoint" is reached, the maximum time between events is RampingMaximumTime - Offset.
/// </summary>
public static readonly CVarDef<float>
GameEventsRampingMaximumTimeOffset = CVarDef.Create("game.events_ramping_maximum_time_offset", 10f, CVar.SERVERONLY);
public static readonly CVarDef<int> // 12 Minutes
GameEventsRampingMaximumTime = CVarDef.Create("game.events_ramping_maximum_time", 720, CVar.SERVERONLY);

/// <summary>
///
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,3 @@ survival-description = No internal threats, but how long can the station survive
hellshift-title = Hellshift
hellshift-description = The station rolled a "one" in a luck check. Can the crew make it to the end?
longsurvival-title = Long Survival
longsurvival-description = Survival, but two hours longer. Event growth is stretched over a vastly greater length of time.
12 changes: 3 additions & 9 deletions Resources/Prototypes/GameRules/roundstart.yml
Original file line number Diff line number Diff line change
Expand Up @@ -132,21 +132,15 @@
components:
- type: RampingStationEventScheduler

- type: entity
id: LongSurvivalStationEventScheduler
parent: BaseGameRule
noSpawn: true
components:
- type: RampingStationEventScheduler
shiftLengthOffset: -120

- type: entity
id: HellshiftStationEventScheduler
parent: BaseGameRule
noSpawn: true
components:
- type: RampingStationEventScheduler
shiftChaosModifier: 4 #30 minute HELL SHIFT
chaosModifier: 4 # By default, one event each 30-10 seconds after two hours. Changing CVars will cause this to deviate.
startingChaosRatio: 0.025 # Starts as slow as survival, but quickly ramps up
shiftLengthModifier: 2.5

# variation passes
- type: entity
Expand Down
11 changes: 0 additions & 11 deletions Resources/Prototypes/game_presets.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,6 @@
- HellshiftStationEventScheduler
- BasicRoundstartVariation

- type: gamePreset
id: SurvivalLonger
alias:
- longsurvival
showInVote: true
name: longsurvival-title
description: longsurvival-description
rules:
- LongSurvivalStationEventScheduler
- BasicRoundstartVariation

- type: gamePreset
id: AllAtOnce
name: all-at-once-title
Expand Down

0 comments on commit 58a1f88

Please sign in to comment.