mirror of
https://github.com/WWhiteDreamProject/wwdpublic.git
synced 2026-04-17 21:48:58 +03:00
## Mirror of PR #26135: [Convert "IgnoreWeatherComponent" into "BlockWeatherComponent"](https://github.com/space-wizards/space-station-14/pull/26135) from <img src="https://avatars.githubusercontent.com/u/10567778?v=4" alt="space-wizards" width="22"/> [space-wizards](https://github.com/space-wizards)/[space-station-14](https://github.com/space-wizards/space-station-14) ###### `4aa72af574cc7a3370085fb70831fbde1df29077` PR opened by <img src="https://avatars.githubusercontent.com/u/96445749?v=4" width="16"/><a href="https://github.com/TheShuEd"> TheShuEd</a> at 2024-03-15 09:30:10 UTC --- PR changed 10 files with 12 additions and 11 deletions. The PR had the following labels: --- <details open="true"><summary><h1>Original Body</h1></summary> > ## About the PR > inverting the logic of the component. Now inversely, tagging an entity with this component will cause it to block weather if it is attached to the floor. Previously, this conversely excluded the entity from weather checking, and only applied to trees on planets. > > It now blocks rain on walls, windows, airlocks. > > ## Why / Balance > 95% of the structures in the game should not block weather. Railings, tables, chairs, fences all logically allow water to pass through. We're making a map under rainy skies, and it's annoying. >  >  >  > > this will also be useful for the visual part of expeditions or something with planets when weather is added there in the future </details> Co-authored-by: SimpleStation14 <Unknown>
240 lines
7.2 KiB
C#
240 lines
7.2 KiB
C#
using Content.Shared.Maps;
|
|
using Robust.Shared.Audio;
|
|
using Robust.Shared.Audio.Systems;
|
|
using Robust.Shared.Map;
|
|
using Robust.Shared.Map.Components;
|
|
using Robust.Shared.Physics.Components;
|
|
using Robust.Shared.Prototypes;
|
|
using Robust.Shared.Serialization;
|
|
using Robust.Shared.Timing;
|
|
|
|
namespace Content.Shared.Weather;
|
|
|
|
public abstract class SharedWeatherSystem : EntitySystem
|
|
{
|
|
[Dependency] protected readonly IGameTiming Timing = default!;
|
|
[Dependency] protected readonly IMapManager MapManager = default!;
|
|
[Dependency] protected readonly IPrototypeManager ProtoMan = default!;
|
|
[Dependency] private readonly ITileDefinitionManager _tileDefManager = default!;
|
|
[Dependency] private readonly MetaDataSystem _metadata = default!;
|
|
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
|
|
|
private EntityQuery<BlockWeatherComponent> _blockQuery;
|
|
private EntityQuery<PhysicsComponent> _physicsQuery;
|
|
|
|
public override void Initialize()
|
|
{
|
|
base.Initialize();
|
|
_blockQuery = GetEntityQuery<BlockWeatherComponent>();
|
|
_physicsQuery = GetEntityQuery<PhysicsComponent>();
|
|
SubscribeLocalEvent<WeatherComponent, EntityUnpausedEvent>(OnWeatherUnpaused);
|
|
}
|
|
|
|
private void OnWeatherUnpaused(EntityUid uid, WeatherComponent component, ref EntityUnpausedEvent args)
|
|
{
|
|
foreach (var weather in component.Weather.Values)
|
|
{
|
|
weather.StartTime += args.PausedTime;
|
|
|
|
if (weather.EndTime != null)
|
|
weather.EndTime = weather.EndTime.Value + args.PausedTime;
|
|
}
|
|
}
|
|
|
|
public bool CanWeatherAffect(
|
|
MapGridComponent grid,
|
|
TileRef tileRef)
|
|
{
|
|
if (tileRef.Tile.IsEmpty)
|
|
return true;
|
|
|
|
var tileDef = (ContentTileDefinition) _tileDefManager[tileRef.Tile.TypeId];
|
|
|
|
if (!tileDef.Weather)
|
|
return false;
|
|
|
|
var anchoredEnts = grid.GetAnchoredEntitiesEnumerator(tileRef.GridIndices);
|
|
|
|
while (anchoredEnts.MoveNext(out var ent))
|
|
{
|
|
if (_blockQuery.HasComponent(ent.Value))
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
public float GetPercent(WeatherData component, EntityUid mapUid)
|
|
{
|
|
var pauseTime = _metadata.GetPauseTime(mapUid);
|
|
var elapsed = Timing.CurTime - (component.StartTime + pauseTime);
|
|
var duration = component.Duration;
|
|
var remaining = duration - elapsed;
|
|
float alpha;
|
|
|
|
if (remaining < WeatherComponent.ShutdownTime)
|
|
{
|
|
alpha = (float) (remaining / WeatherComponent.ShutdownTime);
|
|
}
|
|
else if (elapsed < WeatherComponent.StartupTime)
|
|
{
|
|
alpha = (float) (elapsed / WeatherComponent.StartupTime);
|
|
}
|
|
else
|
|
{
|
|
alpha = 1f;
|
|
}
|
|
|
|
return alpha;
|
|
}
|
|
|
|
|
|
public override void Update(float frameTime)
|
|
{
|
|
base.Update(frameTime);
|
|
|
|
if (!Timing.IsFirstTimePredicted)
|
|
return;
|
|
|
|
var curTime = Timing.CurTime;
|
|
|
|
var query = EntityQueryEnumerator<WeatherComponent>();
|
|
while (query.MoveNext(out var uid, out var comp))
|
|
{
|
|
if (comp.Weather.Count == 0)
|
|
continue;
|
|
|
|
foreach (var (proto, weather) in comp.Weather)
|
|
{
|
|
var endTime = weather.EndTime;
|
|
|
|
// Ended
|
|
if (endTime != null && endTime < curTime)
|
|
{
|
|
EndWeather(uid, comp, proto);
|
|
continue;
|
|
}
|
|
|
|
var remainingTime = endTime - curTime;
|
|
|
|
// Admin messed up or the likes.
|
|
if (!ProtoMan.TryIndex<WeatherPrototype>(proto, out var weatherProto))
|
|
{
|
|
Log.Error($"Unable to find weather prototype for {comp.Weather}, ending!");
|
|
EndWeather(uid, comp, proto);
|
|
continue;
|
|
}
|
|
|
|
// Shutting down
|
|
if (endTime != null && remainingTime < WeatherComponent.ShutdownTime)
|
|
{
|
|
SetState(WeatherState.Ending, comp, weather, weatherProto);
|
|
}
|
|
// Starting up
|
|
else
|
|
{
|
|
var startTime = weather.StartTime;
|
|
var elapsed = Timing.CurTime - startTime;
|
|
|
|
if (elapsed < WeatherComponent.StartupTime)
|
|
{
|
|
SetState(WeatherState.Starting, comp, weather, weatherProto);
|
|
}
|
|
}
|
|
|
|
// Run whatever code we need.
|
|
Run(uid, weather, weatherProto, frameTime);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Shuts down all existing weather and starts the new one if applicable.
|
|
/// </summary>
|
|
public void SetWeather(MapId mapId, WeatherPrototype? proto, TimeSpan? endTime)
|
|
{
|
|
var mapUid = MapManager.GetMapEntityId(mapId);
|
|
var weatherComp = EnsureComp<WeatherComponent>(mapUid);
|
|
|
|
foreach (var (eProto, weather) in weatherComp.Weather)
|
|
{
|
|
// Reset cooldown if it's an existing one.
|
|
if (eProto == proto?.ID)
|
|
{
|
|
weather.EndTime = endTime;
|
|
|
|
if (weather.State == WeatherState.Ending)
|
|
weather.State = WeatherState.Running;
|
|
|
|
Dirty(mapUid, weatherComp);
|
|
continue;
|
|
}
|
|
|
|
// Speedrun
|
|
var end = Timing.CurTime + WeatherComponent.ShutdownTime;
|
|
|
|
if (weather.EndTime == null || weather.EndTime > end)
|
|
{
|
|
weather.EndTime = end;
|
|
Dirty(mapUid, weatherComp);
|
|
}
|
|
}
|
|
|
|
if (proto != null)
|
|
StartWeather(weatherComp, proto, endTime);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Run every tick when the weather is running.
|
|
/// </summary>
|
|
protected virtual void Run(EntityUid uid, WeatherData weather, WeatherPrototype weatherProto, float frameTime) {}
|
|
|
|
protected void StartWeather(WeatherComponent component, WeatherPrototype weather, TimeSpan? endTime)
|
|
{
|
|
if (component.Weather.ContainsKey(weather.ID))
|
|
return;
|
|
|
|
var data = new WeatherData()
|
|
{
|
|
StartTime = Timing.CurTime,
|
|
EndTime = endTime,
|
|
};
|
|
|
|
component.Weather.Add(weather.ID, data);
|
|
Dirty(component);
|
|
}
|
|
|
|
protected virtual void EndWeather(EntityUid uid, WeatherComponent component, string proto)
|
|
{
|
|
if (!component.Weather.TryGetValue(proto, out var data))
|
|
return;
|
|
|
|
_audio.Stop(data.Stream);
|
|
data.Stream = null;
|
|
component.Weather.Remove(proto);
|
|
Dirty(uid, component);
|
|
}
|
|
|
|
protected virtual bool SetState(WeatherState state, WeatherComponent component, WeatherData weather, WeatherPrototype weatherProto)
|
|
{
|
|
if (weather.State.Equals(state))
|
|
return false;
|
|
|
|
weather.State = state;
|
|
Dirty(component);
|
|
return true;
|
|
}
|
|
|
|
[Serializable, NetSerializable]
|
|
protected sealed class WeatherComponentState : ComponentState
|
|
{
|
|
public Dictionary<string, WeatherData> Weather;
|
|
|
|
public WeatherComponentState(Dictionary<string, WeatherData> weather)
|
|
{
|
|
Weather = weather;
|
|
}
|
|
}
|
|
}
|