mirror of
https://github.com/space-wizards/space-station-14.git
synced 2026-02-14 19:29:53 +01:00
PredictedRandom Helpers (#42797)
* PredictedRandom Helpers * fixxxx * documentation!!! * pram --------- Co-authored-by: Princess Cheeseballs <66055347+Pronana@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
c0f691a142
commit
41f042b8f9
@@ -197,16 +197,13 @@ public abstract class SharedBloodstreamSystem : EntitySystem
|
||||
var totalFloat = total.Float();
|
||||
TryModifyBleedAmount(ent.AsNullable(), totalFloat);
|
||||
|
||||
/// Critical hit. Causes target to lose blood, using the bleed rate modifier of the weapon, currently divided by 5
|
||||
/// The crit chance is currently the bleed rate modifier divided by 25.
|
||||
/// Higher damage weapons have a higher chance to crit!
|
||||
// Critical hit. Causes target to lose blood, using the bleed rate modifier of the weapon, currently divided by 5
|
||||
// The crit chance is currently the bleed rate modifier divided by 25.
|
||||
// Higher damage weapons have a higher chance to crit!
|
||||
|
||||
// TODO: Replace with RandomPredicted once the engine PR is merged
|
||||
// Use both the receiver and the damage causing entity for the seed so that we have different results for multiple attacks in the same tick
|
||||
var seed = SharedRandomExtensions.HashCodeCombine((int)_timing.CurTick.Value, GetNetEntity(ent).Id, GetNetEntity(args.Origin)?.Id ?? 0 );
|
||||
var rand = new System.Random(seed);
|
||||
var prob = Math.Clamp(totalFloat / 25, 0, 1);
|
||||
if (totalFloat > 0 && rand.Prob(prob))
|
||||
if (totalFloat > 0 && SharedRandomExtensions.PredictedProb(_timing, prob, GetNetEntity(ent), GetNetEntity(args.Origin)))
|
||||
{
|
||||
TryBleedOut(ent.AsNullable(), total / 5);
|
||||
_audio.PlayPredicted(ent.Comp.InstantBloodSound, ent, args.Origin);
|
||||
|
||||
@@ -4,6 +4,7 @@ using Content.Shared.Damage.Systems;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Shared.Movement.Systems;
|
||||
using Content.Shared.Random.Helpers;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
@@ -61,7 +62,7 @@ public abstract class SharedCursedMaskSystem : EntitySystem
|
||||
|
||||
protected void RandomizeCursedMask(Entity<CursedMaskComponent> ent, EntityUid wearer)
|
||||
{
|
||||
var random = new System.Random((int) _timing.CurTick.Value);
|
||||
var random = SharedRandomExtensions.PredictedRandom(_timing, GetNetEntity(ent));
|
||||
ent.Comp.CurrentState = random.Pick(Enum.GetValues<CursedMaskExpression>());
|
||||
_appearance.SetData(ent, CursedMaskVisuals.State, ent.Comp.CurrentState);
|
||||
_movementSpeedModifier.RefreshMovementSpeedModifiers(wearer);
|
||||
|
||||
@@ -48,10 +48,7 @@ public sealed class ClumsySystem : EntitySystem
|
||||
if (!ent.Comp.ClumsyHypo)
|
||||
return;
|
||||
|
||||
// TODO: Replace with RandomPredicted once the engine PR is merged
|
||||
var seed = SharedRandomExtensions.HashCodeCombine((int)_timing.CurTick.Value, GetNetEntity(ent).Id);
|
||||
var rand = new System.Random(seed);
|
||||
if (!rand.Prob(ent.Comp.ClumsyDefaultCheck))
|
||||
if (!SharedRandomExtensions.PredictedProb(_timing, ent.Comp.ClumsyDefaultCheck, GetNetEntity(ent)))
|
||||
return;
|
||||
|
||||
args.TargetGettingInjected = args.EntityUsingInjector;
|
||||
@@ -67,10 +64,7 @@ public sealed class ClumsySystem : EntitySystem
|
||||
if (!ent.Comp.ClumsyDefib)
|
||||
return;
|
||||
|
||||
// TODO: Replace with RandomPredicted once the engine PR is merged
|
||||
var seed = SharedRandomExtensions.HashCodeCombine((int)_timing.CurTick.Value, GetNetEntity(ent).Id);
|
||||
var rand = new System.Random(seed);
|
||||
if (!rand.Prob(ent.Comp.ClumsyDefaultCheck))
|
||||
if (!SharedRandomExtensions.PredictedProb(_timing, ent.Comp.ClumsyDefaultCheck, GetNetEntity(ent)))
|
||||
return;
|
||||
|
||||
args.DefibTarget = args.EntityUsingDefib;
|
||||
@@ -86,10 +80,7 @@ public sealed class ClumsySystem : EntitySystem
|
||||
if (!ent.Comp.ClumsyCatching)
|
||||
return;
|
||||
|
||||
// TODO: Replace with RandomPredicted once the engine PR is merged
|
||||
var seed = SharedRandomExtensions.HashCodeCombine((int)_timing.CurTick.Value, GetNetEntity(args.Item).Id);
|
||||
var rand = new System.Random(seed);
|
||||
if (!rand.Prob(ent.Comp.ClumsyDefaultCheck))
|
||||
if (!SharedRandomExtensions.PredictedProb(_timing, ent.Comp.ClumsyDefaultCheck, GetNetEntity(ent)))
|
||||
return;
|
||||
|
||||
args.Cancelled = true; // fail to catch
|
||||
@@ -120,10 +111,7 @@ public sealed class ClumsySystem : EntitySystem
|
||||
if (args.Gun.Comp.ClumsyProof)
|
||||
return;
|
||||
|
||||
// TODO: Replace with RandomPredicted once the engine PR is merged
|
||||
var seed = SharedRandomExtensions.HashCodeCombine((int)_timing.CurTick.Value, GetNetEntity(args.Gun).Id);
|
||||
var rand = new System.Random(seed);
|
||||
if (!rand.Prob(ent.Comp.ClumsyDefaultCheck))
|
||||
if (!SharedRandomExtensions.PredictedProb(_timing, ent.Comp.ClumsyDefaultCheck, GetNetEntity(ent)))
|
||||
return;
|
||||
|
||||
if (ent.Comp.GunShootFailDamage != null)
|
||||
@@ -145,10 +133,8 @@ public sealed class ClumsySystem : EntitySystem
|
||||
if (!ent.Comp.ClumsyVaulting)
|
||||
return;
|
||||
|
||||
// TODO: Replace with RandomPredicted once the engine PR is merged
|
||||
var seed = SharedRandomExtensions.HashCodeCombine((int)_timing.CurTick.Value, GetNetEntity(ent).Id);
|
||||
var rand = new System.Random(seed);
|
||||
if (!_cfg.GetCVar(CCVars.GameTableBonk) && !rand.Prob(ent.Comp.ClumsyDefaultCheck))
|
||||
if (!_cfg.GetCVar(CCVars.GameTableBonk)
|
||||
&& !SharedRandomExtensions.PredictedProb(_timing, ent.Comp.ClumsyDefaultCheck, GetNetEntity(ent)))
|
||||
return;
|
||||
|
||||
HitHeadClumsy(ent, args.BeingClimbedOn);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Interaction.Events;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Random.Helpers;
|
||||
using Content.Shared.Throwing;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Timing;
|
||||
@@ -72,7 +73,7 @@ public abstract class SharedDiceSystem : EntitySystem
|
||||
|
||||
private void Roll(Entity<DiceComponent> entity, EntityUid? user = null)
|
||||
{
|
||||
var rand = new System.Random((int)_timing.CurTick.Value);
|
||||
var rand = SharedRandomExtensions.PredictedRandom(_timing, GetNetEntity(entity));
|
||||
|
||||
var roll = rand.Next(1, entity.Comp.Sides + 1);
|
||||
SetCurrentSide(entity, roll);
|
||||
|
||||
@@ -4,7 +4,6 @@ using Content.Shared.Chemistry.Reaction;
|
||||
using Content.Shared.EntityConditions;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.Random.Helpers;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Shared.EntityEffects;
|
||||
@@ -95,13 +94,8 @@ public sealed partial class SharedEntityEffectsSystem : EntitySystem, IEntityEff
|
||||
return false;
|
||||
|
||||
// TODO: Replace with proper random prediciton when it exists.
|
||||
if (effect.Probability <= 1f)
|
||||
{
|
||||
var seed = SharedRandomExtensions.HashCodeCombine((int)_timing.CurTick.Value, GetNetEntity(target).Id, 0);
|
||||
var rand = new System.Random(seed);
|
||||
if (!rand.Prob(effect.Probability))
|
||||
if (effect.Probability <= 1f && !SharedRandomExtensions.PredictedProb(_timing, effect.Probability, GetNetEntity(target), GetNetEntity(user)))
|
||||
return false;
|
||||
}
|
||||
|
||||
// See if conditions apply
|
||||
if (!_condition.TryConditions(target, effect.Conditions))
|
||||
|
||||
@@ -205,10 +205,7 @@ public abstract class SharedFlashSystem : EntitySystem
|
||||
_entityLookup.GetEntitiesInRange(transform.Coordinates, range, _entSet);
|
||||
foreach (var entity in _entSet)
|
||||
{
|
||||
// TODO: Use RandomPredicted https://github.com/space-wizards/RobustToolbox/pull/5849
|
||||
var seed = SharedRandomExtensions.HashCodeCombine((int)_timing.CurTick.Value, GetNetEntity(entity).Id);
|
||||
var rand = new System.Random(seed);
|
||||
if (!rand.Prob(probability))
|
||||
if (!SharedRandomExtensions.PredictedProb(_timing, probability, GetNetEntity(entity)))
|
||||
continue;
|
||||
|
||||
// Is the entity affected by the flash either through status effects or by taking damage?
|
||||
|
||||
@@ -246,10 +246,7 @@ public sealed class DrainSystem : EntitySystem
|
||||
if (args.Target == null)
|
||||
return;
|
||||
|
||||
// TODO: Replace with RandomPredicted once the engine PR is merged
|
||||
var seed = SharedRandomExtensions.HashCodeCombine((int)_timing.CurTick.Value, ent.Owner.GetHashCode());
|
||||
var rand = new System.Random(seed);
|
||||
if (!rand.Prob(ent.Comp.UnclogProbability))
|
||||
if (!SharedRandomExtensions.PredictedProb(_timing, ent.Comp.UnclogProbability, GetNetEntity(ent)))
|
||||
{
|
||||
_popup.PopupPredicted(Loc.GetString("drain-component-unclog-fail", ("object", args.Target.Value)), args.Target.Value, args.User);
|
||||
return;
|
||||
|
||||
@@ -48,9 +48,7 @@ public sealed class GhostSpriteStateSystem : EntitySystem
|
||||
|
||||
var highestType = damageTypesSorted.First().Key; // We only need 1 of the values
|
||||
|
||||
// TODO: Replace with RandomPredicted once the engine PR is merged
|
||||
var seed = SharedRandomExtensions.HashCodeCombine((int)_timing.CurTick.Value, GetNetEntity(ent).Id);
|
||||
var rand = new System.Random(seed);
|
||||
var rand = SharedRandomExtensions.PredictedRandom(_timing, GetNetEntity(ent));
|
||||
|
||||
ProtoId<DamageTypePrototype>? spriteState = null;
|
||||
|
||||
|
||||
@@ -290,10 +290,7 @@ public sealed class SharedKitchenSpikeSystem : EntitySystem
|
||||
PopupType.MediumCaution);
|
||||
|
||||
// Get a random entry to spawn.
|
||||
// TODO: Replace with RandomPredicted once the engine PR is merged
|
||||
var seed = SharedRandomExtensions.HashCodeCombine((int)_gameTiming.CurTick.Value, GetNetEntity(ent).Id);
|
||||
var rand = new System.Random(seed);
|
||||
|
||||
var rand = SharedRandomExtensions.PredictedRandom(_gameTiming, GetNetEntity(ent));
|
||||
var index = rand.Next(butcherable.SpawnedEntities.Count);
|
||||
var entry = butcherable.SpawnedEntities[index];
|
||||
|
||||
|
||||
@@ -65,11 +65,7 @@ public sealed partial class IngestionSystem
|
||||
if (!Resolve(entity, ref entity.Comp))
|
||||
return;
|
||||
|
||||
// TODO: Once we have predicted randomness delete this for something sane...
|
||||
var seed = SharedRandomExtensions.HashCodeCombine((int)_timing.CurTick.Value, GetNetEntity(entity).Id, GetNetEntity(userUid).Id);
|
||||
var rand = new System.Random(seed);
|
||||
|
||||
if (!rand.Prob(entity.Comp.BreakChance))
|
||||
if (!SharedRandomExtensions.PredictedProb(_timing, entity.Comp.BreakChance, GetNetEntity(entity), GetNetEntity(userUid)))
|
||||
return;
|
||||
|
||||
_audio.PlayPredicted(entity.Comp.BreakSound, userUid, userUid, AudioParams.Default.WithVolume(-2f));
|
||||
|
||||
@@ -37,10 +37,7 @@ public sealed class MessyDrinkerSystem : EntitySystem
|
||||
if (proto == null || !ent.Comp.SpillableTypes.Contains(proto.Value))
|
||||
return;
|
||||
|
||||
// TODO: Replace with RandomPredicted once the engine PR is merged
|
||||
var seed = SharedRandomExtensions.HashCodeCombine((int)_timing.CurTick.Value, GetNetEntity(ent).Id);
|
||||
var rand = new System.Random(seed);
|
||||
if (!rand.Prob(ent.Comp.SpillChance))
|
||||
if (!SharedRandomExtensions.PredictedProb(_timing, ent.Comp.SpillChance, GetNetEntity(ent)))
|
||||
return;
|
||||
|
||||
if (ent.Comp.SpillMessagePopup != null)
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Linq;
|
||||
using Content.Shared.Dataset;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Shared.Random.Helpers
|
||||
{
|
||||
@@ -210,5 +211,34 @@ namespace Content.Shared.Random.Helpers
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
// TODO: REPLACE ALL OF THIS WITH PREDICTED RANDOM WHEN ENGINE PR IS MERGED
|
||||
/// <summary>
|
||||
/// Creates an instance of System.Random that will be the same for both the server and client.
|
||||
/// This allows for the client and server to roll the same results when determining things randomly, preventing mispredictions.
|
||||
/// We generate a unique seed by getting 2-3 unique but predictable integers into a Hashcode.
|
||||
/// </summary>
|
||||
/// <param name="timing">An instance if IGameTiming.
|
||||
/// We use the integer value of the current tick to ensure a different seed every tick.</param>
|
||||
/// <param name="netEnt">The relevant net entity to our seed.
|
||||
/// This allows different entities to have different seeds and therefore different results on the same game-tick.</param>
|
||||
/// <param name="netEnt2">An optional relevant net entity to our seed.
|
||||
/// Typically used if we have an entity checking random potentially multiple times per tick, to ensure we get a unique seed each time.
|
||||
/// This entity should not be the same entity as <see cref="netEnt"/>.</param>
|
||||
public static System.Random PredictedRandom(IGameTiming timing, NetEntity netEnt, NetEntity? netEnt2 = null)
|
||||
{
|
||||
var seed = HashCodeCombine((int)timing.CurTick.Value, netEnt.Id, netEnt2?.Id ?? 0);
|
||||
return new System.Random(seed);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks a probability against a <see cref="PredictedRandom"/> instance.
|
||||
/// Returns true if the amount rolled is below the probability.
|
||||
/// </summary>
|
||||
public static bool PredictedProb(IGameTiming timing, float probability, NetEntity netEnt1, NetEntity? netEnt2 = null)
|
||||
{
|
||||
var rand = PredictedRandom(timing, netEnt1, netEnt2);
|
||||
return rand.Prob(probability);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,10 +55,7 @@ public sealed partial class CatchableSystem : EntitySystem
|
||||
if (attemptEv.Cancelled)
|
||||
return;
|
||||
|
||||
// TODO: Replace with RandomPredicted once the engine PR is merged
|
||||
var seed = SharedRandomExtensions.HashCodeCombine((int)_timing.CurTick.Value, GetNetEntity(ent).Id);
|
||||
var rand = new System.Random(seed);
|
||||
if (!rand.Prob(ent.Comp.CatchChance))
|
||||
if (!SharedRandomExtensions.PredictedProb(_timing, ent.Comp.CatchChance, GetNetEntity(ent)))
|
||||
return;
|
||||
|
||||
// Try to catch!
|
||||
|
||||
@@ -52,9 +52,7 @@ public sealed class NarcolepsySystem : EntitySystem
|
||||
if (narcolepsy.NextIncidentTime > _timing.CurTime)
|
||||
continue;
|
||||
|
||||
// TODO: Replace with RandomPredicted once the engine PR is merged
|
||||
var seed = SharedRandomExtensions.HashCodeCombine((int)_timing.CurTick.Value, GetNetEntity(uid).Id);
|
||||
var rand = new System.Random(seed);
|
||||
var rand = SharedRandomExtensions.PredictedRandom(_timing, GetNetEntity(uid));
|
||||
|
||||
var duration = narcolepsy.MinDurationOfIncident + (narcolepsy.MaxDurationOfIncident - narcolepsy.MinDurationOfIncident) * rand.NextDouble();
|
||||
|
||||
|
||||
@@ -13,16 +13,7 @@ public sealed class RandomTriggerOnTriggerSystem : XOnTriggerSystem<RandomTrigge
|
||||
|
||||
protected override void OnTrigger(Entity<RandomTriggerOnTriggerComponent> ent, EntityUid target, ref TriggerEvent args)
|
||||
{
|
||||
// TODO: Replace with RandomPredicted once the engine PR is merged
|
||||
var hash = new List<int>
|
||||
{
|
||||
(int)_timing.CurTick.Value,
|
||||
GetNetEntity(ent).Id,
|
||||
args.User == null ? 0 : GetNetEntity(args.User.Value).Id,
|
||||
};
|
||||
var seed = SharedRandomExtensions.HashCodeCombine(hash);
|
||||
var rand = new System.Random(seed);
|
||||
|
||||
var rand = SharedRandomExtensions.PredictedRandom(_timing, GetNetEntity(ent), GetNetEntity(args.User));
|
||||
var keyOut = _prototypeManager.Index(ent.Comp.RandomKeyOut).Pick(rand);
|
||||
|
||||
// Prevent recursive triggers
|
||||
|
||||
@@ -70,17 +70,8 @@ public sealed partial class TriggerSystem
|
||||
if (args.Key != null && !ent.Comp.Keys.Contains(args.Key))
|
||||
return;
|
||||
|
||||
// TODO: Replace with RandomPredicted once the engine PR is merged
|
||||
var hash = new List<int>
|
||||
{
|
||||
(int)_timing.CurTick.Value,
|
||||
GetNetEntity(ent).Id,
|
||||
args.User == null ? 0 : GetNetEntity(args.User.Value).Id,
|
||||
};
|
||||
var seed = SharedRandomExtensions.HashCodeCombine(hash);
|
||||
var rand = new System.Random(seed);
|
||||
|
||||
args.Cancelled |= !rand.Prob(ent.Comp.SuccessChance); // When not successful, Cancelled = true
|
||||
// When not successful, Cancelled = true
|
||||
args.Cancelled |= !SharedRandomExtensions.PredictedProb(_timing, ent.Comp.SuccessChance, GetNetEntity(ent), GetNetEntity(args.User));
|
||||
}
|
||||
private void OnMindRoleTriggerAttempt(Entity<MindRoleTriggerConditionComponent> ent, ref AttemptTriggerEvent args)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user