public sealed partial class StencilOverlay
{
+ private List<Entity<MapGridComponent>> _grids = new();
+
private void DrawWeather(in OverlayDrawArgs args, WeatherPrototype weatherProto, float alpha, Matrix3 invMatrix)
{
var worldHandle = args.WorldHandle;
// particularly for planet maps or stations.
worldHandle.RenderInRenderTarget(_blep!, () =>
{
- var bodyQuery = _entManager.GetEntityQuery<PhysicsComponent>();
var xformQuery = _entManager.GetEntityQuery<TransformComponent>();
- var weatherIgnoreQuery = _entManager.GetEntityQuery<IgnoreWeatherComponent>();
+ _grids.Clear();
// idk if this is safe to cache in a field and clear sloth help
- var grids = new List<Entity<MapGridComponent>>();
- _mapManager.FindGridsIntersecting(mapId, worldAABB, ref grids);
+ _mapManager.FindGridsIntersecting(mapId, worldAABB, ref _grids);
- foreach (var grid in grids)
+ foreach (var grid in _grids)
{
var matrix = _transform.GetWorldMatrix(grid, xformQuery);
Matrix3.Multiply(in matrix, in invMatrix, out var matty);
foreach (var tile in grid.Comp.GetTilesIntersecting(worldAABB))
{
// Ignored tiles for stencil
- if (_weather.CanWeatherAffect(grid, tile, weatherIgnoreQuery, bodyQuery))
+ if (_weather.CanWeatherAffect(grid, tile))
{
continue;
}
using Robust.Client.Graphics;
using Robust.Client.Player;
using Robust.Shared.Audio;
+using Robust.Shared.Audio.Systems;
using Robust.Shared.GameStates;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
- private const float OcclusionLerpRate = 4f;
- private const float AlphaLerpRate = 4f;
-
public override void Initialize()
{
base.Initialize();
{
base.Run(uid, weather, weatherProto, frameTime);
- var ent = _playerManager.LocalPlayer?.ControlledEntity;
+ var ent = _playerManager.LocalEntity;
if (ent == null)
return;
// Maybe have the viewports manage this?
if (mapUid == null || entXform.MapUid != mapUid)
{
- weather.LastOcclusion = 0f;
- weather.LastAlpha = 0f;
weather.Stream = _audio.Stop(weather.Stream);
return;
}
return;
weather.Stream ??= _audio.PlayGlobal(weatherProto.Sound, Filter.Local(), true).Value.Entity;
- var volumeMod = MathF.Pow(10, weatherProto.Sound.Params.Volume / 10f);
var stream = weather.Stream.Value;
var comp = Comp<AudioComponent>(stream);
- var alpha = weather.LastAlpha;
- alpha = MathF.Pow(alpha, 2f) * volumeMod;
- // TODO: Lerp this occlusion.
var occlusion = 0f;
- // TODO: Fade-out needs to be slower
- // TODO: HELPER PLZ
// Work out tiles nearby to determine volume.
if (TryComp<MapGridComponent>(entXform.GridUid, out var grid))
frontier.Enqueue(seed);
// If we don't have a nearest node don't play any sound.
EntityCoordinates? nearestNode = null;
- var bodyQuery = GetEntityQuery<PhysicsComponent>();
- var weatherIgnoreQuery = GetEntityQuery<IgnoreWeatherComponent>();
var visited = new HashSet<Vector2i>();
while (frontier.TryDequeue(out var node))
if (!visited.Add(node.GridIndices))
continue;
- if (!CanWeatherAffect(grid, node, weatherIgnoreQuery, bodyQuery))
+ if (!CanWeatherAffect(grid, node))
{
// Add neighbors
// TODO: Ideally we pick some deterministically random direction and use that
}
nearestNode = new EntityCoordinates(entXform.GridUid.Value,
- (Vector2) node.GridIndices + (grid.TileSizeHalfVector));
+ node.GridIndices + grid.TileSizeHalfVector);
break;
}
- if (nearestNode == null)
- alpha = 0f;
+ // Get occlusion to the targeted node if it exists, otherwise set a default occlusion.
+ if (nearestNode != null)
+ {
+ var entPos = _transform.GetMapCoordinates(entXform);
+ var nodePosition = nearestNode.Value.ToMap(EntityManager, _transform).Position;
+ var delta = nodePosition - entPos.Position;
+ var distance = delta.Length();
+ occlusion = _audio.GetOcclusion(entPos, delta, distance);
+ }
else
{
- var entPos = _transform.GetWorldPosition(entXform);
- var sourceRelative = nearestNode.Value.ToMap(EntityManager).Position - entPos;
-
- if (sourceRelative.LengthSquared() > 1f)
- {
- occlusion = _physics.IntersectRayPenetration(entXform.MapID,
- new CollisionRay(entPos, sourceRelative.Normalized(), _audio.OcclusionCollisionMask),
- sourceRelative.Length(), stream);
- }
+ occlusion = 3f;
}
}
- if (MathHelper.CloseTo(weather.LastOcclusion, occlusion, 0.01f))
- weather.LastOcclusion = occlusion;
- else
- weather.LastOcclusion += (occlusion - weather.LastOcclusion) * OcclusionLerpRate * frameTime;
-
- if (MathHelper.CloseTo(weather.LastAlpha, alpha, 0.01f))
- weather.LastAlpha = alpha;
- else
- weather.LastAlpha += (alpha - weather.LastAlpha) * AlphaLerpRate * frameTime;
-
- // Full volume if not on grid
- comp.Gain = weather.LastAlpha;
- comp.Occlusion = weather.LastOcclusion;
- }
-
- protected override void EndWeather(EntityUid uid, WeatherComponent component, string proto)
- {
- base.EndWeather(uid, component, proto);
-
- if (!component.Weather.TryGetValue(proto, out var weather))
- return;
-
- weather.LastAlpha = 0f;
- weather.LastOcclusion = 0f;
+ var alpha = GetPercent(weather, uid);
+ alpha *= SharedAudioSystem.VolumeToGain(weatherProto.Sound.Params.Volume);
+ _audio.SetGain(stream, alpha, comp);
+ comp.Occlusion = occlusion;
}
protected override bool SetState(WeatherState state, WeatherComponent comp, WeatherData weather, WeatherPrototype weatherProto)
// New weather
StartWeather(component, ProtoMan.Index<WeatherPrototype>(proto), weather.EndTime);
- weather.LastAlpha = 0f;
}
}
}
[Dependency] private readonly MetaDataSystem _metadata = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
+ private EntityQuery<IgnoreWeatherComponent> _ignoreQuery;
+ private EntityQuery<PhysicsComponent> _physicsQuery;
+
public override void Initialize()
{
base.Initialize();
+ _ignoreQuery = GetEntityQuery<IgnoreWeatherComponent>();
+ _physicsQuery = GetEntityQuery<PhysicsComponent>();
SubscribeLocalEvent<WeatherComponent, EntityUnpausedEvent>(OnWeatherUnpaused);
}
public bool CanWeatherAffect(
MapGridComponent grid,
- TileRef tileRef,
- EntityQuery<IgnoreWeatherComponent> weatherIgnoreQuery,
- EntityQuery<PhysicsComponent> bodyQuery)
+ TileRef tileRef)
{
if (tileRef.Tile.IsEmpty)
return true;
while (anchoredEnts.MoveNext(out var ent))
{
- if (!weatherIgnoreQuery.HasComponent(ent.Value) &&
- bodyQuery.TryGetComponent(ent, out var body) &&
+ if (!_ignoreQuery.HasComponent(ent.Value) &&
+ _physicsQuery.TryGetComponent(ent, out var body) &&
body.Hard &&
body.CanCollide)
{