Skip to content

Commit 0a1f98d

Browse files
committed
1.2.0.0-beta
OnTriggerStay instead of OnTriggerEnter. HashSets instead of Lists. Location of entered colliders every N seconds. Configurable delay for routines.
1 parent 881e314 commit 0a1f98d

File tree

6 files changed

+93
-39
lines changed

6 files changed

+93
-39
lines changed

Config.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
public partial class Config : IRocketPluginConfiguration
88
{
99
public bool DebugInformation = true;
10+
public float DefaultLocateDelay = 1.5f, DefaultUpdateDelay = 0.2f;
1011
public List<Zone> Zones = new();
1112
public void LoadDefaults()
1213
{

Controllers/CustomZoneController.cs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,18 @@ public void SetNodes(IEnumerable<Vector3> nodes)
1919
protected readonly List<Vector3> nodes = new();
2020
public IReadOnlyCollection<Vector3> Nodes => nodes;
2121

22-
private readonly List<Collider> colliders = new();
22+
private readonly HashSet<Collider> colliders = new();
2323

2424
protected new bool SetEnterState(Collider other, bool state)
2525
{
26-
if (state != colliders.Contains(other))
27-
{
28-
if (state) colliders.Add(other);
29-
else colliders.Remove(other);
30-
}
26+
var inside = colliders.Contains(other);
27+
if (state == inside) return true;
28+
if (state) colliders.Add(other);
29+
else colliders.Remove(other);
3130
state = IsPositionInside(other);
3231
return base.SetEnterState(other, state);
3332
}
34-
protected override void OnTriggerEnter(Collider other) => SetEnterState(other, true);
33+
protected override void OnTriggerStay(Collider other) => SetEnterState(other, true);
3534
protected override void OnTriggerExit(Collider other) => SetEnterState(other, false);
3635

3736
public override bool IsInside(Vector3 point)

Controllers/ZoneController.cs

Lines changed: 43 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
namespace SZones;
1+
using UnityEngine;
2+
3+
namespace SZones;
24

35
public abstract partial class ZoneController : UnityBehaviour
46
{
@@ -18,16 +20,16 @@ internal void Initialize(Zone zone)
1820
}
1921

2022
#region Entered State
21-
protected readonly List<Collider> enteredColliders = new();
23+
protected readonly HashSet<Collider> enteredColliders = new();
2224
public virtual IReadOnlyCollection<Collider> EnteredColliders => enteredColliders;
23-
public virtual IReadOnlyCollection<GameObject> EnteredObjects => enteredColliders.Select(x => x.gameObject).ToList();
25+
public virtual IReadOnlyCollection<GameObject> EnteredObjects => enteredColliders.Select(x => x?.gameObject).Where(x => x).ToList();
2426
protected virtual bool SetEnterState(Collider other, bool state)
2527
{
26-
if (!other) return state;
27-
var @object = other.gameObject;
28-
2928
var entered = enteredColliders.Contains(other);
3029
if (state == entered) return state;
30+
if (!other) return state;
31+
32+
var @object = other.gameObject;
3133

3234
bool Set<T>(Func<T, bool, bool> func) => state = func(@object.GetComponent<T>(), state);
3335
Set<Player>(SetEnterState);
@@ -51,10 +53,10 @@ protected virtual bool UpdateEnterState(Collider other)
5153
return SetEnterState(other, state);
5254
}
5355
protected virtual bool UpdateEnterState(UnityComponent component) => UpdateEnterState(component?.GetComponent<Collider>());
54-
protected virtual void OnTriggerEnter(Collider other) => SetEnterState(other, true);
56+
protected virtual void OnTriggerStay(Collider other) => SetEnterState(other, true);
5557
protected virtual void OnTriggerExit(Collider other) => SetEnterState(other, false);
5658

57-
protected readonly List<CSteamID> enteredPlayers = new();
59+
protected readonly HashSet<CSteamID> enteredPlayers = new();
5860
public virtual IReadOnlyCollection<CSteamID> EnteredPlayers => enteredPlayers;
5961

6062
protected bool SetEnterState(SPlayer target, bool state) => SetEnterState(target?.player, state);
@@ -71,7 +73,7 @@ protected bool TrySetEnterState(CSteamID id, bool state)
7173
if (IsInside(id) == state) return false;
7274

7375
if (state) enteredPlayers.Add(id);
74-
else enteredPlayers.RemoveAll(x => x == id);
76+
else enteredPlayers.Remove(id);
7577

7678
return true;
7779
}
@@ -107,16 +109,18 @@ protected void InvokeEventsSafe<T>(T value, bool state, StateUpdateHandler<T> en
107109
catch { }
108110
}
109111

110-
protected virtual float UpdateCollidersDelay { get; } = 0.2f;
111-
protected void UpdateStates(IList<Collider> colliders)
112+
protected virtual float UpdateCollidersDelay { get; } = conf.DefaultUpdateDelay;
113+
protected virtual float LocateCollidersDelay { get; } = conf.DefaultLocateDelay;
114+
protected void UpdateStates(ICollection<Collider> colliders)
112115
{
113116
List<UnityComponent> other = new();
114117
for (int i = 0; i < colliders.Count; i++)
115118
{
116119
var collider = colliders.ElementAt(i);
117120
if (!collider)
118121
{
119-
colliders.RemoveAt(i--);
122+
colliders.Remove(collider);
123+
--i;
120124
continue;
121125
}
122126

@@ -136,18 +140,14 @@ protected void UpdateStates(IList<Collider> colliders)
136140
foreach (var component in other.Distinct())
137141
UpdateEnterState(component);
138142
}
139-
protected void UpdateStates(IList<CSteamID> playersIds)
143+
protected void UpdateStates(ICollection<CSteamID> playersIds)
140144
{
141145
var ids = playersIds.ToList();
142146
foreach(var id in ids)
143147
{
144148
var player = PlayerTool.getPlayer(id);
145-
if (!player) goto notEntered;
146-
if (!(IsPositionInside(player) || IsPositionInside(player.GetComponent<Collider>()))) goto notEntered;
147-
148-
continue;
149-
notEntered:
150-
TrySetEnterState(id, false);
149+
if (!player) TrySetEnterState(id, false);
150+
else UpdateEnterState(player);
151151
}
152152
}
153153
protected virtual void UpdateStates()
@@ -163,6 +163,29 @@ protected virtual IEnumerator UpdateEnteredCollidersRoutine()
163163
UpdateStates();
164164
}
165165
}
166+
protected virtual IEnumerator LocateEnteredCollidersRoutine()
167+
{
168+
while (true)
169+
{
170+
yield return new WaitForSeconds(LocateCollidersDelay);
171+
LocateEnteredColliders();
172+
}
173+
}
174+
protected virtual void LocateEnteredColliders()
175+
{
176+
if (Provider.clients is null) return;
177+
if (VehicleManager.vehicles is null) return;
178+
179+
var colliders =
180+
Provider.clients.Select(x => x?.model?.GetComponent<Collider>())
181+
.Concat(VehicleManager.vehicles.Select(x => x?.GetComponent<Collider>()))
182+
.ToArray();
183+
foreach(var collider in colliders)
184+
{
185+
if (!collider) continue;
186+
UpdateEnterState(collider);
187+
}
188+
}
166189
#endregion
167190

168191
#region Entities
@@ -222,6 +245,7 @@ public virtual void Dispose()
222245
protected virtual void Awake()
223246
{
224247
StartCoroutine(UpdateEnteredCollidersRoutine());
248+
StartCoroutine(LocateEnteredCollidersRoutine());
225249
}
226250
#endregion
227251
}

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# SZones
2+
3+
### Smart zone system based on Unity collision for Unturned plugins.
4+
Warning! Repository still in beta, most of builds is not fully tested, and may contain bugs, please report about them in the issues.

SZones.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<TargetFrameworks>net472</TargetFrameworks>
66
<AssemblyName>SZones</AssemblyName>
77
<RootNamespace>SZones</RootNamespace>
8-
<Version>1.1.4.2</Version>
8+
<Version>1.2.0.0-beta</Version>
99
<NoWarn>$(NoWarn);CS0436</NoWarn>
1010
<RunPostBuildEvent>Always</RunPostBuildEvent>
1111
<Nullable>annotations</Nullable>

Utilities/Utils.cs

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@
5050
global using Storage = SDG.Unturned.InteractableStorage;
5151
global using InventoryPage = SDG.Unturned.Items;
5252
global using static SZones.Utils;
53+
using System.Net;
54+
using System.Drawing;
5355

5456
namespace SZones;
5557

@@ -145,30 +147,54 @@ public static List<Animal> GetAnimals(Func<Vector3, bool> isInside)
145147
return result;
146148
}
147149

150+
148151
public static List<RegionCoordinate> GetRegions(this Bounds bounds)
149152
{
150153
List<RegionCoordinate> result = new();
151154
var center = bounds.center;
152155
var extents = bounds.extents;
153156
Vector3 startPoint = new(center.x - extents.x, center.y, center.z - extents.z);
154157
Vector3 endPoint = new(center.x + extents.x, center.y, center.z + extents.z);
155-
getUnsafeCoordinates(startPoint, out var x1, out var y1);
156-
getUnsafeCoordinates(endPoint, out var x2, out var y2);
157-
if (x1 >= Regions.WORLD_SIZE || y1 >= Regions.WORLD_SIZE || x2 < 0 || y2 < 0)
158+
Vector2Int
159+
startRegion = GetRegionCoordinates(startPoint),
160+
endRegion = GetRegionCoordinates(endPoint);
161+
162+
if (startRegion.x >= Regions.WORLD_SIZE || startRegion.y >= Regions.WORLD_SIZE || endRegion.x < 0 || endRegion.y < 0)
158163
return result;
159-
x1 = Mathf.Max(x1, 0);
160-
x2 = Mathf.Max(x2, 0);
161-
y1 = Mathf.Min(y1, Regions.WORLD_SIZE - 1);
162-
y2 = Mathf.Min(y2, Regions.WORLD_SIZE - 1);
163-
for (byte x = (byte)x1; x <= x2; x++)
164-
for (byte y = (byte)y1; y <= y2; y++)
164+
165+
startRegion.x = Mathf.Max(startRegion.x, 0);
166+
endRegion.x = Mathf.Max(endRegion.x, 0);
167+
startRegion.y = Mathf.Min(startRegion.y, Regions.WORLD_SIZE - 1);
168+
endRegion.y = Mathf.Min(endRegion.y, Regions.WORLD_SIZE - 1);
169+
for (byte x = (byte)startPoint.x; x <= endPoint.x; x++)
170+
for (byte y = (byte)startPoint.y; y <= endPoint.y; y++)
165171
result.Add(new(x, y));
166172
return result;
167173
}
174+
public static bool IsInsideAnyRegion(this Vector3 position, IEnumerable<RegionCoordinate> regions) =>
175+
regions.Any(x =>
176+
{
177+
var start = GetRegionStart(x.ToVec2Int());
178+
var end = GetRegionStart(x.x + 1, x.y + 1);
179+
return position.x <= end.x && position.y <= end.y &&
180+
position.x >= start.x && position.y >= end.y;
181+
});
168182

169-
private static void getUnsafeCoordinates(Vector3 point, out int x, out int y)
183+
public static void GetRegionCoordinates(this Vector3 point, out int x, out int y)
184+
{
185+
x = Mathf.FloorToInt((point.x + RegionConstant) / Regions.REGION_SIZE);
186+
y = Mathf.FloorToInt((point.z + RegionConstant) / Regions.REGION_SIZE);
187+
}
188+
public static Vector2Int GetRegionCoordinates(this Vector3 point)
170189
{
171-
x = Mathf.FloorToInt((point.x + 4096f) / Regions.REGION_SIZE);
172-
y = Mathf.FloorToInt((point.z + 4096f) / Regions.REGION_SIZE);
190+
GetRegionCoordinates(point, out var x, out var y);
191+
return new(x, y);
173192
}
193+
public static Vector3 GetRegionStart(int x, int y) => new(
194+
x * Regions.REGION_SIZE - RegionConstant,
195+
y * Regions.REGION_SIZE - RegionConstant
196+
);
197+
public static Vector3 GetRegionStart(Vector2Int coordinate) => GetRegionStart(coordinate.x, coordinate.y);
198+
public static Vector2Int ToVec2Int(this RegionCoordinate coordinate) => new(coordinate.x, coordinate.y);
199+
public const float RegionConstant = 4096f;
174200
}

0 commit comments

Comments
 (0)