| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245 |
- using Content.Shared.Light.Components;
- using Content.Shared.Light.EntitySystems;
- using Content.Shared.Maps;
- using Robust.Shared.Audio.Systems;
- using Robust.Shared.Map;
- using Robust.Shared.Map.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!;
- [Dependency] private readonly SharedMapSystem _mapSystem = default!;
- [Dependency] private readonly SharedRoofSystem _roof = default!;
- private EntityQuery<BlockWeatherComponent> _blockQuery;
- public override void Initialize()
- {
- base.Initialize();
- _blockQuery = GetEntityQuery<BlockWeatherComponent>();
- 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(EntityUid uid, MapGridComponent grid, TileRef tileRef, RoofComponent? roofComp = null)
- {
- if (tileRef.Tile.IsEmpty)
- return true;
- if (Resolve(uid, ref roofComp, false) && _roof.IsRooved((uid, grid, roofComp), tileRef.GridIndices))
- return false;
- var tileDef = (ContentTileDefinition) _tileDefManager[tileRef.Tile.TypeId];
- if (!tileDef.Weather)
- return false;
- var anchoredEntities = _mapSystem.GetAnchoredEntitiesEnumerator(uid, grid, tileRef.GridIndices);
- while (anchoredEntities.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(uid, WeatherState.Ending, comp, weather, weatherProto);
- }
- // Starting up
- else
- {
- var startTime = weather.StartTime;
- var elapsed = Timing.CurTime - startTime;
- if (elapsed < WeatherComponent.StartupTime)
- {
- SetState(uid, 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)
- {
- if (!_mapSystem.TryGetMap(mapId, out var mapUid))
- return;
- var weatherComp = EnsureComp<WeatherComponent>(mapUid.Value);
- foreach (var (eProto, weather) in weatherComp.Weather)
- {
- // if we turn off the weather, we don't want endTime = null
- if (proto == null)
- endTime ??= Timing.CurTime + WeatherComponent.ShutdownTime;
- // Reset cooldown if it's an existing one.
- if (proto is not null && eProto == proto.ID)
- {
- weather.EndTime = endTime;
- if (weather.State == WeatherState.Ending)
- weather.State = WeatherState.Running;
- Dirty(mapUid.Value, weatherComp);
- continue;
- }
- // Speedrun
- var end = Timing.CurTime + WeatherComponent.ShutdownTime;
- if (weather.EndTime == null || weather.EndTime > end)
- {
- weather.EndTime = end;
- Dirty(mapUid.Value, weatherComp);
- }
- }
- if (proto != null)
- StartWeather(mapUid.Value, 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(EntityUid uid, 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(uid, 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(EntityUid uid, WeatherState state, WeatherComponent component, WeatherData weather, WeatherPrototype weatherProto)
- {
- if (weather.State.Equals(state))
- return false;
- weather.State = state;
- Dirty(uid, component);
- return true;
- }
- [Serializable, NetSerializable]
- protected sealed class WeatherComponentState : ComponentState
- {
- public Dictionary<ProtoId<WeatherPrototype>, WeatherData> Weather;
- public WeatherComponentState(Dictionary<ProtoId<WeatherPrototype>, WeatherData> weather)
- {
- Weather = weather;
- }
- }
- }
|