Skip to content

Commit

Permalink
Fixed negative numbers counting as command flags, added distance prop…
Browse files Browse the repository at this point in the history
…erties to world icon effects.
  • Loading branch information
DanielWillett committed Dec 22, 2024
1 parent cf6829d commit 3481306
Show file tree
Hide file tree
Showing 6 changed files with 176 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ public UniTask ExecuteAsync(CancellationToken token)
Context.TryGet(0, out float lifetime);
if (!Context.TryGet(1, out float tickSpeed))
tickSpeed = WorldIconManager.DefaultTickSpeed;
if (!Context.TryGet(2, out float distance))
distance = float.MaxValue;

WorldIconInfo info;
if (raycast.transform.gameObject.layer == (int)ELayerMask.GROUND)
Expand All @@ -44,6 +46,11 @@ public UniTask ExecuteAsync(CancellationToken token)
}

info.TickSpeed = tickSpeed;
if (distance < 0)
info.RelevanceRegions = (byte)Math.Round(-distance);
else
info.RelevanceDistance = distance;


_iconManager.CreateIcon(info);
return UniTask.CompletedTask;
Expand Down
9 changes: 6 additions & 3 deletions UncreatedWarfare/Interaction/Commands/CommandParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ private static ReadOnlySpan<char> GetNextArg(ref ReadOnlySpan<char> args, ReadOn
while (firstNonFlag < args.Length && flagPrefixes[flagPrefix] == args[firstNonFlag])
++firstNonFlag;

if (firstNonFlag is 1 or 2)
if (firstNonFlag is 1 or 2 && firstNonFlag < args.Length && !char.IsDigit(args[firstNonFlag]) && args[firstNonFlag] != '.' && args[firstNonFlag] != ',')
{
args = args[firstNonFlag..];
ReadOnlySpan<char> span = GetNextArg(ref args, startArgChars, endArgChars, flagPrefixes, out isEmpty, out flagDashCt);
Expand Down Expand Up @@ -334,8 +334,11 @@ private static bool IsFlag(string str)
return false;

ReadOnlySpan<char> flagPrefixes = [ '-', '–', '—', '−' ];
if (flagPrefixes.IndexOf(str[0]) < 0)
return false;



if (flagPrefixes.IndexOf(str[0]) < 0 || char.IsDigit(str[1]) || str[1] == '.' || str[1] == ',')
return false; // prevents negative numbers ^ counting as flags

return str.Length < 2 && flagPrefixes.IndexOf(str[1]) >= 0 || flagPrefixes.IndexOf(str[1]) < 0 || flagPrefixes.IndexOf(str[2]) < 0;
}
Expand Down
164 changes: 140 additions & 24 deletions UncreatedWarfare/Interaction/Icons/WorldIconInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,15 @@ namespace Uncreated.Warfare.Interaction.Icons;
/// </summary>
public class WorldIconInfo : ITransformObject, IDisposable
{
private Vector3 _prevSpawnPosition;
private bool _needsRespawn = true;
internal Vector3 LastSpawnPosition;
internal float LastSpawnRealtime;
internal float LastPositionUpdateRealtime;
internal float FirstSpawnRealtime;

// used when distance is specified to clear from players who have left the area
private List<WarfarePlayer>? _previousPlayers;

private Vector3 _position;

private Color32 _color = new Color32(255, 255, 255, 0);
Expand Down Expand Up @@ -143,6 +146,18 @@ public Color32 Color

public bool Alive { get; internal set; }

/// <summary>
/// Radius in regions this effect should be shown. Takes the minimum of this <see cref="RelevanceDistance"/>.
/// </summary>
public byte RelevanceRegions { get; set; } = byte.MaxValue;

/// <summary>
/// Radius in distance this effect should be shown. Takes the minimum of this <see cref="RelevanceRegions"/>.
/// </summary>
public float RelevanceDistance { get; set; } = float.MaxValue;

public bool IsDistanceLimited => RelevanceDistance <= 32768f || RelevanceRegions != byte.MaxValue;

public WorldIconInfo(Transform transform, IAssetLink<EffectAsset> effect, Team? targetTeam = null, WarfarePlayer? targetPlayer = null, Func<WarfarePlayer, bool>? playerSelector = null, float lifetimeSec = 0)
: this(effect, targetTeam, targetPlayer, playerSelector, lifetimeSec)
{
Expand Down Expand Up @@ -185,32 +200,54 @@ public void KeepAliveFor(float seconds)
LifetimeSeconds = FirstSpawnRealtime == 0 ? seconds : Time.realtimeSinceStartup - FirstSpawnRealtime + seconds;
}

internal void UpdateRelevantPlayers(IPlayerService playerService, ref PooledTransportConnectionList? list, ref ITransportConnection? single, HashSet<ITransportConnection> workingHashSetCache)
internal void UpdateRelevantPlayers(IPlayerService playerService, ref PooledTransportConnectionList? list, ref ITransportConnection? single, in Vector3 spawnPosition, HashSet<ITransportConnection> workingHashSetCache)
{
bool distanceLimited = IsDistanceLimited;
Vector3 pos = default;
if (TargetPlayer != null)
{
Add(TargetPlayer.Connection, ref list, ref single, workingHashSetCache);
if (distanceLimited)
pos = TargetPlayer.Position;
if (!distanceLimited || CheckPositionRelevant(in pos, in spawnPosition))
Add(TargetPlayer.Connection, ref list, ref single, workingHashSetCache);
}
else if (TargetTeam is not null)
{
foreach (WarfarePlayer player in playerService.OnlinePlayersOnTeam(TargetTeam))
{
Add(player.Connection, ref list, ref single, workingHashSetCache);
if (distanceLimited)
pos = player.Position;
if (!distanceLimited || CheckPositionRelevant(in pos, in spawnPosition))
Add(player.Connection, ref list, ref single, workingHashSetCache);
}
}
else if (PlayerSelector != null)
{
foreach (WarfarePlayer player in playerService.OnlinePlayers)
{
if (PlayerSelector(player))
if (distanceLimited)
pos = player.Position;
if ((!distanceLimited || CheckPositionRelevant(in pos, in spawnPosition)) && PlayerSelector(player))
Add(player.Connection, ref list, ref single, workingHashSetCache);
}
}
else
{
foreach (WarfarePlayer player in playerService.OnlinePlayers)
{
Add(player.Connection, ref list, ref single, workingHashSetCache);
if (distanceLimited)
pos = player.Position;
if (!distanceLimited || CheckPositionRelevant(in pos, in spawnPosition))
Add(player.Connection, ref list, ref single, workingHashSetCache);
}
}

if ((distanceLimited || PlayerSelector != null) && _previousPlayers != null)
{
foreach (WarfarePlayer player in _previousPlayers)
{
if (player.IsOnline)
Add(player.Connection, ref list, ref single, workingHashSetCache);
}
}

Expand All @@ -236,7 +273,7 @@ static void Add(ITransportConnection connection, ref PooledTransportConnectionLi
}
}

internal bool ShouldPlayerSeeIcon(WarfarePlayer player)
internal bool ShouldPlayerSeeIcon(WarfarePlayer player, in Vector3 spawnPosition)
{
if (TargetPlayer != null && !TargetPlayer.Equals(player))
return false;
Expand All @@ -247,7 +284,31 @@ internal bool ShouldPlayerSeeIcon(WarfarePlayer player)
if (PlayerSelector != null && !PlayerSelector(player))
return false;

return true;
return CheckPositionRelevant(player.Position, in spawnPosition);
}

private bool CheckPositionRelevant(in Vector3 sendPos, in Vector3 spawnPos)
{
float dist = RelevanceDistance;
int area = RelevanceRegions;
if (dist > 32768f && area == byte.MaxValue)
return true;

byte regionSize = Regions.REGION_SIZE;
if ((area + 0.5f) * regionSize > dist)
{
return MathUtility.SquaredDistance(in sendPos, in spawnPos, true) <= dist * dist;
}

if (area == byte.MaxValue)
return true;

int sendX = (int)Math.Floor((sendPos.x + 4096f) / regionSize);
int sendY = (int)Math.Floor((sendPos.z + 4096f) / regionSize);
int spawnX = (int)Math.Floor((spawnPos.x + 4096f) / regionSize);
int spawnY = (int)Math.Floor((spawnPos.z + 4096f) / regionSize);
return sendX >= spawnX - area && sendY >= spawnY - area &&
sendX <= spawnX + area && sendY <= spawnY + area;
}

private static void GetColoredEffectForward(Color32 c, out Vector3 forward, out float scale)
Expand All @@ -270,15 +331,15 @@ internal bool TryGetSpawnPosition(out Vector3 position)
Vector3 v3;
if (TransformableObject != null)
{
v3 = TransformableObject.Position + Offset;
v3 = TransformableObject.Position;
}
else if (UnityObject is null)
{
v3 = _position;
}
else if (UnityObject != null)
{
v3 = UnityObject.position + Offset;
v3 = UnityObject.position;
}
else
{
Expand Down Expand Up @@ -321,6 +382,9 @@ internal void SpawnEffect(IPlayerService playerService, float rt, bool updatePos
return;
}

bool distanceLimited = IsDistanceLimited;
bool hasMutablePlayerSelector = distanceLimited || PlayerSelector != null;

Vector3 pos;
if (updatePosition)
{
Expand All @@ -329,7 +393,7 @@ internal void SpawnEffect(IPlayerService playerService, float rt, bool updatePos
return;
}

if (_prevSpawnPosition.IsNearlyEqual(pos) && !_needsRespawn && (!_canTrackLifetime || rt - LastSpawnRealtime < _minimumLifetime))
if (LastSpawnPosition.IsNearlyEqual(pos) && !(_needsRespawn || hasMutablePlayerSelector) && (!_canTrackLifetime || rt - LastSpawnRealtime < _minimumLifetime))
{
return;
}
Expand All @@ -338,7 +402,7 @@ internal void SpawnEffect(IPlayerService playerService, float rt, bool updatePos
}
else
{
pos = _prevSpawnPosition;
pos = LastSpawnPosition;
}

TriggerEffectParameters parameters = new TriggerEffectParameters(effect);
Expand All @@ -355,18 +419,49 @@ internal void SpawnEffect(IPlayerService playerService, float rt, bool updatePos
parameters.SetUniformScale(_colorScale);
}

_prevSpawnPosition = pos;
LastSpawnPosition = pos;
_needsRespawn = false;


if (hasMutablePlayerSelector)
{
if (_previousPlayers == null)
_previousPlayers = new List<WarfarePlayer>(4);
else
_previousPlayers.Clear();
}

Vector3 sendPos = default;
if (forPlayer != null)
{
parameters.SetRelevantPlayer(forPlayer.Connection);
if (distanceLimited)
sendPos = forPlayer.Position;
if (!distanceLimited || CheckPositionRelevant(in sendPos, in pos))
{
parameters.SetRelevantPlayer(forPlayer.Connection);
if (hasMutablePlayerSelector)
_previousPlayers!.Add(forPlayer);
}
else
{
return;
}
}
else if (TargetPlayer != null)
{
if (TargetPlayer.IsOnline && (TargetTeam is null || TargetPlayer.Team == TargetTeam) && (PlayerSelector == null || PlayerSelector(TargetPlayer)))
if (TargetPlayer.IsOnline)
{
parameters.SetRelevantPlayer(TargetPlayer.Connection);
if (distanceLimited)
sendPos = TargetPlayer.Position;
if ((TargetTeam is null || TargetPlayer.Team == TargetTeam) && (!distanceLimited || CheckPositionRelevant(in sendPos, in pos)) && (PlayerSelector == null || PlayerSelector(TargetPlayer)))
{
parameters.SetRelevantPlayer(TargetPlayer.Connection);
if (hasMutablePlayerSelector)
_previousPlayers!.Add(TargetPlayer);
}
else
{
return;
}
}
else
{
Expand All @@ -379,8 +474,17 @@ internal void SpawnEffect(IPlayerService playerService, float rt, bool updatePos

foreach (WarfarePlayer player in playerService.OnlinePlayers)
{
if (player.Team == TargetTeam && (PlayerSelector == null || PlayerSelector(player)))
if (distanceLimited)
sendPos = player.Position;

if (player.Team == TargetTeam
&& (!distanceLimited || CheckPositionRelevant(in sendPos, in pos))
&& (PlayerSelector == null || PlayerSelector(player)))
{
list.Add(player.Connection);
if (hasMutablePlayerSelector)
_previousPlayers!.Add(player);
}
}

if (list.Count == 0)
Expand All @@ -397,14 +501,29 @@ internal void SpawnEffect(IPlayerService playerService, float rt, bool updatePos
if (list.Capacity < playerService.OnlinePlayers.Count)
list.Capacity = playerService.OnlinePlayers.Count;
foreach (WarfarePlayer player in playerService.OnlinePlayers)
list.Add(player.Connection);
{
if (distanceLimited)
sendPos = player.Position;
if (!distanceLimited || CheckPositionRelevant(in sendPos, in pos))
{
list.Add(player.Connection);
if (hasMutablePlayerSelector)
_previousPlayers!.Add(player);
}
}
}
else
{
foreach (WarfarePlayer player in playerService.OnlinePlayers)
{
if (PlayerSelector(player))
if (distanceLimited)
sendPos = player.Position;
if ((!distanceLimited || CheckPositionRelevant(in sendPos, in pos)) && PlayerSelector(player))
{
list.Add(player.Connection);
if (hasMutablePlayerSelector)
_previousPlayers!.Add(player);
}
}
}

Expand All @@ -430,10 +549,7 @@ Vector3 ITransformObject.Position
TryGetSpawnPosition(out Vector3 position);
return position;
}
set
{
EffectPosition = value - Offset;
}
set => EffectPosition = value - Offset;
}

Quaternion ITransformObject.Rotation
Expand Down
Loading

0 comments on commit 3481306

Please sign in to comment.