diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs index 496dce9..92e5415 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs @@ -26,21 +26,19 @@ */ using System; -using System.Reflection; using System.Collections.Generic; +using System.Linq; using OpenMetaverse; using OpenSim.Framework; -using log4net; +//using log4net; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; -using OpenSim.Region.ScriptEngine.Shared; -using OpenSim.Region.ScriptEngine.Shared.Api; namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins { public class SensorRepeat { -// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + //private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); /// <summary> /// Used by one-off and repeated sensors @@ -55,13 +53,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins public string name; public UUID keyID; public int type; - public double range; - public double arc; + public float range; + public float arc; public SceneObjectPart host; public SensorInfo Clone() { - return (SensorInfo)this.MemberwiseClone(); + return (SensorInfo)MemberwiseClone(); } } @@ -81,14 +79,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins public SensorRepeat(AsyncCommandManager CmdManager) { m_CmdManager = CmdManager; - maximumRange = CmdManager.m_ScriptEngine.Config.GetDouble("SensorMaxRange", 96.0d); + maximumRange = CmdManager.m_ScriptEngine.Config.GetFloat("SensorMaxRange", 96.0f); maximumToReturn = CmdManager.m_ScriptEngine.Config.GetInt("SensorMaxResults", 16); m_npcModule = m_CmdManager.m_ScriptEngine.World.RequestModuleInterface<INPCModule>(); } - private INPCModule m_npcModule; + private readonly INPCModule m_npcModule; - private readonly object SenseLock = new object(); + private readonly object SenseLock = new(); private const int AGENT = 1; private const int AGENT_BY_USERNAME = 0x10; @@ -97,43 +95,39 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins private const int PASSIVE = 4; private const int SCRIPTED = 8; - private double maximumRange = 96.0; - private int maximumToReturn = 16; + private readonly float maximumRange = 96.0f; + private readonly int maximumToReturn = 16; // // Sensed entity // private class SensedEntity : IComparable { - public SensedEntity(double detectedDistance, UUID detectedID) + public SensedEntity(float detectedDistance, UUID detectedID) { distance = detectedDistance; itemID = detectedID; } public int CompareTo(object obj) { - if (!(obj is SensedEntity)) throw new InvalidOperationException(); - SensedEntity ent = (SensedEntity)obj; - if (ent == null || ent.distance < distance) return 1; + if (obj is not SensedEntity ent) + throw new InvalidOperationException(); + if (ent.distance < distance) return 1; if (ent.distance > distance) return -1; return 0; } public UUID itemID; - public double distance; + public float distance; } /// <summary> /// Sensors to process. /// </summary> /// <remarks> - /// Do not add or remove sensors from this list directly. Instead, copy the list and substitute the updated - /// copy. This is to avoid locking the list for the duration of the sensor sweep, which increases the danger - /// of deadlocks with future code updates. - /// /// Always lock SenseRepeatListLock when updating this list. /// </remarks> - private List<SensorInfo> SenseRepeaters = new List<SensorInfo>(); - private readonly object SenseRepeatListLock = new object(); + private List<SensorInfo> SenseRepeaters = new(); + private readonly object SenseRepeatListLock = new(); public void SetSenseRepeatEvent(uint m_localID, UUID m_itemID, string name, UUID keyID, int type, double range, @@ -144,39 +138,28 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins if (sec == 0) // Disabling timer return; - + float frange = (float)range; // Add to timer - SensorInfo ts = new SensorInfo + SensorInfo ts = new() { localID = m_localID, itemID = m_itemID, interval = sec, + next = DateTime.UtcNow.AddSeconds(sec), name = name, keyID = keyID, - type = type + type = type, + range = frange >= maximumRange ? maximumRange : frange, + arc = (float)arc, + host = host }; - if (range > maximumRange) - ts.range = maximumRange; - else - ts.range = range; - ts.arc = arc; - ts.host = host; - - ts.next = DateTime.UtcNow.AddSeconds(ts.interval); - AddSenseRepeater(ts); } private void AddSenseRepeater(SensorInfo senseRepeater) { lock (SenseRepeatListLock) - { - List<SensorInfo> newSenseRepeaters = new List<SensorInfo>(SenseRepeaters) - { - senseRepeater - }; - SenseRepeaters = newSenseRepeaters; - } + SenseRepeaters.Add(senseRepeater); } public void UnSetSenseRepeaterEvents(uint m_localID, UUID m_itemID) @@ -184,10 +167,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins // Remove from timer lock (SenseRepeatListLock) { - List<SensorInfo> newSenseRepeaters = new List<SensorInfo>(); + List<SensorInfo> newSenseRepeaters = new(SenseRepeaters.Count); foreach (SensorInfo ts in SenseRepeaters) { - if (ts.localID != m_localID || ts.itemID != m_itemID) + if (ts.localID != m_localID || ts.itemID.NotEqual(m_itemID)) { newSenseRepeaters.Add(ts); } @@ -208,8 +191,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins DateTime now = DateTime.UtcNow; foreach (SensorInfo ts in curSensors) { + if(ts.interval == 0) + { + SensorSweep(ts); + lock (SenseRepeatListLock) + SenseRepeaters.Remove(ts); + } // Time has passed? - if (ts.next < now) + else if (ts.next < now) { SensorSweep(ts); // set next interval @@ -222,33 +211,29 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins string name, UUID keyID, int type, double range, double arc, SceneObjectPart host) { + float frange = (float)range; // Add to timer - SensorInfo ts = new SensorInfo + SensorInfo ts = new() { localID = m_localID, itemID = m_itemID, interval = 0, name = name, keyID = keyID, - type = type + type = type, + range = frange >= maximumRange ? maximumRange : frange, + arc = (float)arc, + host = host }; - if (range > maximumRange) - ts.range = maximumRange; - else - ts.range = range; - ts.arc = arc; - ts.host = host; - SensorSweep(ts); + AddSenseRepeater(ts); } private void SensorSweep(SensorInfo ts) { - if (ts.host == null) - { + if (ts.host is null) return; - } - List<SensedEntity> sensedEntities = new List<SensedEntity>(); + List<SensedEntity> sensedEntities = new(); // Is the sensor type is AGENT and not SCRIPTED then include agents if ((ts.type & (AGENT | AGENT_BY_USERNAME | NPC)) != 0 && (ts.type & SCRIPTED) == 0) @@ -269,8 +254,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins // send a "no_sensor" // Add it to queue m_CmdManager.m_ScriptEngine.PostScriptEvent(ts.itemID, - new EventParams("no_sensor", new Object[0], - new DetectParams[0])); + new EventParams("no_sensor", Array.Empty<object>(), + Array.Empty<DetectParams>())); } else { @@ -278,12 +263,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins sensedEntities.Sort(); int count = sensedEntities.Count; int idx; - List<DetectParams> detected = new List<DetectParams>(); + List<DetectParams> detected = new(); for (idx = 0; idx < count; idx++) { try { - DetectParams detect = new DetectParams + DetectParams detect = new() { Key = sensedEntities[idx].itemID }; @@ -305,8 +290,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins // like the object being deleted or the avatar leaving to have caused some // difficulty during the Populate above so fire a no_sensor event m_CmdManager.m_ScriptEngine.PostScriptEvent(ts.itemID, - new EventParams("no_sensor", new Object[0], - new DetectParams[0])); + new EventParams("no_sensor", Array.Empty<object>(), + Array.Empty<DetectParams>())); } else { @@ -322,40 +307,33 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins private List<SensedEntity> doObjectSensor(SensorInfo ts) { List<EntityBase> Entities; - List<SensedEntity> sensedEntities = new List<SensedEntity>(); + List<SensedEntity> sensedEntities = new(); // If this is an object sense by key try to get it directly // rather than getting a list to scan through if (ts.keyID.IsNotZero()) { m_CmdManager.m_ScriptEngine.World.Entities.TryGetValue(ts.keyID, out EntityBase e); - if (e == null) + if (e is null) return sensedEntities; - Entities = new List<EntityBase> - { - e - }; + Entities = new List<EntityBase> { e }; } else { Entities = new List<EntityBase>(m_CmdManager.m_ScriptEngine.World.GetEntities()); } - SceneObjectPart SensePoint = ts.host; - Vector3 fromRegionPos = SensePoint.GetWorldPosition(); + SceneObjectPart sensorPart = ts.host; + bool doarc = ts.arc < MathF.PI; // pre define some things to avoid repeated definitions in the loop body - Vector3 toRegionPos; - double dis; + float dis; int objtype; SceneObjectPart part; - float dx; - float dy; - float dz; -// Quaternion q = SensePoint.RotationOffset; - Quaternion q = SensePoint.GetWorldRotation(); // non-attached prim Sensor *always* uses World rotation! - if (SensePoint.ParentGroup.IsAttachment) + Vector3 fromRegionPos; + Quaternion q; + if (sensorPart.ParentGroup.IsAttachment) { // In attachments, rotate the sensor cone with the // avatar rotation. This may include a nonzero elevation if @@ -367,120 +345,114 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins // avatar rotation and position. // Position of a sensor in a child prim attached to an avatar // will be still wrong. - ScenePresence avatar = m_CmdManager.m_ScriptEngine.World.GetScenePresence(SensePoint.ParentGroup.AttachedAvatar); - - // Don't proceed if the avatar for this attachment has since been removed from the scene. - if (avatar == null) + ScenePresence avatar = m_CmdManager.m_ScriptEngine.World.GetScenePresence(sensorPart.ParentGroup.AttachedAvatar); + if (avatar is null) return sensedEntities; fromRegionPos = avatar.AbsolutePosition; - q = avatar.Rotation; + q = doarc ? Quaternion.Identity : avatar.Rotation; + } + else + { + fromRegionPos = sensorPart.GetWorldPosition(); + q = doarc ? Quaternion.Identity : sensorPart.GetWorldRotation(); // non-attached prim Sensor *always* uses World rotation! } - LSL_Types.Quaternion r = new LSL_Types.Quaternion(q); - LSL_Types.Vector3 forward_dir = (new LSL_Types.Vector3(1, 0, 0) * r); - double mag_fwd = LSL_Types.Vector3.Mag(forward_dir); + Vector3 forward_dir; + float mag_fwd; + if (doarc) + { + forward_dir = Vector3.UnitXRotated(q); + mag_fwd = forward_dir.LengthSquared(); + } + else + { + forward_dir = Vector3.Zero; + mag_fwd = 1; + } - Vector3 ZeroVector = new Vector3(0, 0, 0); + float rangeSQ = ts.range * ts.range; bool nameSearch = !string.IsNullOrEmpty(ts.name); foreach (EntityBase ent in Entities) { - bool keep = true; + if (ent.IsDeleted) // taken so long to do this it has gone from the scene + continue; - if (nameSearch && ent.Name != ts.name) // Wrong name and it is a named search + if (ent is not SceneObjectGroup sog) // dont bother if it is a pesky avatar continue; - if (ent.IsDeleted) // taken so long to do this it has gone from the scene + if (sog.IsAttachment) // Attached so ignore continue; - if (!(ent is SceneObjectGroup)) // dont bother if it is a pesky avatar + if (sensorPart.UUID.Equals(ent.UUID)) continue; - toRegionPos = ent.AbsolutePosition; - - // Calculation is in line for speed - dx = toRegionPos.X - fromRegionPos.X; - dy = toRegionPos.Y - fromRegionPos.Y; - dz = toRegionPos.Z - fromRegionPos.Z; - - // Weed out those that will not fit in a cube the size of the range - // no point calculating if they are within a sphere the size of the range - // if they arent even in the cube - if (Math.Abs(dx) > ts.range || Math.Abs(dy) > ts.range || Math.Abs(dz) > ts.range) - dis = ts.range + 1.0; - else - dis = Math.Sqrt(dx * dx + dy * dy + dz * dz); - if (keep && dis <= ts.range && ts.host.UUID != ent.UUID) - { - // In Range and not the object containing the script, is it the right Type ? - objtype = 0; + if (nameSearch && !ent.Name.Equals(ts.name)) + continue; - part = ((SceneObjectGroup)ent).RootPart; - if (part.ParentGroup.RootPart.Shape.PCode != (byte)PCode.Tree && - part.ParentGroup.RootPart.Shape.PCode != (byte)PCode.NewTree && - part.ParentGroup.AttachmentPoint != 0) // Attached so ignore - continue; + Vector3 diff = ent.AbsolutePosition - fromRegionPos; + dis = diff.LengthSquared(); + if(dis > rangeSQ) + continue; - if (part.Inventory.ContainsScripts()) + part = sog.RootPart; + objtype = 0; + if (part.Inventory.ContainsScripts()) + { + objtype |= ACTIVE | SCRIPTED; // Scripted and active. It COULD have one hidden ... + } + else + { + if (ent.Velocity.IsZero()) { - objtype |= ACTIVE | SCRIPTED; // Scripted and active. It COULD have one hidden ... + objtype |= PASSIVE; // Passive non-moving } else { - if (ent.Velocity.IsZero()) - { - objtype |= PASSIVE; // Passive non-moving - } - else - { - objtype |= ACTIVE; // moving so active - } + objtype |= ACTIVE; // moving so active } + } - // If any of the objects attributes match any in the requested scan type - if (((ts.type & objtype) != 0)) - { - // Right type too, what about the other params , key and name ? - if (ts.arc < Math.PI) - { - // not omni-directional. Can you see it ? - // vec forward_dir = llRot2Fwd(llGetRot()) - // vec obj_dir = toRegionPos-fromRegionPos - // dot=dot(forward_dir,obj_dir) - // mag_fwd = mag(forward_dir) - // mag_obj = mag(obj_dir) - // ang = acos(dot /(mag_fwd*mag_obj)) - double ang_obj = 0; - try - { - Vector3 diff = toRegionPos - fromRegionPos; - double dot = LSL_Types.Vector3.Dot(forward_dir, diff); - double mag_obj = LSL_Types.Vector3.Mag(diff); - ang_obj = Math.Acos(dot / (mag_fwd * mag_obj)); - } - catch - { - } - - if (ang_obj > ts.arc) keep = false; - } + if ((ts.type & objtype) == 0) + continue; - if (keep == true) - { - // add distance for sorting purposes later - sensedEntities.Add(new SensedEntity(dis, ent.UUID)); - } + // Right type too, what about the other params , key and name ? + if (doarc) + { + // not omni-directional. Can you see it ? + // vec forward_dir = llRot2Fwd(llGetRot()) + // vec obj_dir = toRegionPos-fromRegionPos + // dot=dot(forward_dir,obj_dir) + // mag_fwd = mag(forward_dir) + // mag_obj = mag(obj_dir) + // ang = acos(dot /(mag_fwd*mag_obj)) + float ang_obj; + try + { + float mag_corr = MathF.Sqrt(mag_fwd * dis); + float dot = Vector3.Dot(forward_dir, diff); + ang_obj = MathF.Acos(dot / mag_corr); } + catch + { + continue; + } + + if (ang_obj > ts.arc) + continue; } + + // add distance for sorting purposes later + sensedEntities.Add(new SensedEntity(dis, ent.UUID)); } return sensedEntities; } private List<SensedEntity> doAgentSensor(SensorInfo ts) { - List<SensedEntity> sensedEntities = new List<SensedEntity>(); + List<SensedEntity> sensedEntities = new(); // If nobody about quit fast if (m_CmdManager.m_ScriptEngine.World.GetRootAgentCount() == 0) @@ -489,7 +461,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins SceneObjectPart SensePoint = ts.host; Vector3 fromRegionPos = SensePoint.GetWorldPosition(); - Quaternion q = SensePoint.GetWorldRotation(); + Quaternion q; if (SensePoint.ParentGroup.IsAttachment) { // In attachments, rotate the sensor cone with the @@ -505,33 +477,34 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins ScenePresence avatar = m_CmdManager.m_ScriptEngine.World.GetScenePresence(SensePoint.ParentGroup.AttachedAvatar); // Don't proceed if the avatar for this attachment has since been removed from the scene. - if (avatar == null) + if (avatar is null) return sensedEntities; fromRegionPos = avatar.AbsolutePosition; q = avatar.Rotation; } + else + q = SensePoint.GetWorldRotation(); + + Vector3 forward_dir = Vector3.UnitXRotated(q); + float mag_fwd = forward_dir.LengthSquared(); - LSL_Types.Quaternion r = new LSL_Types.Quaternion(q); - LSL_Types.Vector3 forward_dir = (new LSL_Types.Vector3(1, 0, 0) * r); - double mag_fwd = LSL_Types.Vector3.Mag(forward_dir); bool attached = (SensePoint.ParentGroup.AttachmentPoint != 0); Vector3 toRegionPos; - double dis; - Action<ScenePresence> senseEntity = new Action<ScenePresence>(presence => + Action<ScenePresence> senseEntity = new(presence => { -// m_log.DebugFormat( -// "[SENSOR REPEAT]: Inspecting scene presence {0}, type {1} on sensor sweep for {2}, type {3}", -// presence.Name, presence.PresenceType, ts.name, ts.type); + //m_log.DebugFormat( + // "[SENSOR REPEAT]: Inspecting scene presence {0}, type {1} on sensor sweep for {2}, type {3}", + // presence.Name, presence.PresenceType, ts.name, ts.type); if ((ts.type & NPC) == 0 && presence.PresenceType == PresenceType.Npc) { INPC npcData = m_npcModule.GetNPC(presence.UUID, presence.Scene); - if (npcData == null || !npcData.SenseAsAgent) + if (npcData is null || !npcData.SenseAsAgent) { -// m_log.DebugFormat( -// "[SENSOR REPEAT]: Discarding NPC {0} from agent sense sweep for script item id {1}", -// presence.Name, ts.itemID); + //m_log.DebugFormat( + // "[SENSOR REPEAT]: Discarding NPC {0} from agent sense sweep for script item id {1}", + // presence.Name, ts.itemID); return; } } @@ -545,11 +518,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins else { INPC npcData = m_npcModule.GetNPC(presence.UUID, presence.Scene); - if (npcData != null && npcData.SenseAsAgent) + if (npcData is not null && npcData.SenseAsAgent) { -// m_log.DebugFormat( -// "[SENSOR REPEAT]: Discarding NPC {0} from non-agent sense sweep for script item id {1}", -// presence.Name, ts.itemID); + //m_log.DebugFormat( + // "[SENSOR REPEAT]: Discarding NPC {0} from non-agent sense sweep for script item id {1}", + // presence.Name, ts.itemID); return; } } @@ -564,13 +537,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins return; toRegionPos = presence.AbsolutePosition; - dis = Vector3.Distance(toRegionPos, fromRegionPos); - if (presence.IsSatOnObject && presence.ParentPart != null && - presence.ParentPart.ParentGroup != null && - presence.ParentPart.ParentGroup.RootPart != null) + float dis = Vector3.Distance(toRegionPos, fromRegionPos); + if (presence.IsSatOnObject && presence.ParentPart is not null && + presence.ParentPart.ParentGroup is not null && + presence.ParentPart.ParentGroup.RootPart is not null) { Vector3 rpos = presence.ParentPart.ParentGroup.RootPart.AbsolutePosition; - double dis2 = Vector3.Distance(rpos, fromRegionPos); + float dis2 = Vector3.Distance(rpos, fromRegionPos); if (dis > dis2) dis = dis2; } @@ -578,18 +551,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins // Disabled for now since all osNpc* methods check for appropriate ownership permission. // Perhaps could be re-enabled as an NPC setting at some point since being able to make NPCs not // sensed might be useful. -// if (presence.PresenceType == PresenceType.Npc && npcModule != null) -// { -// UUID npcOwner = npcModule.GetOwner(presence.UUID); -// if (npcOwner != UUID.Zero && npcOwner != SensePoint.OwnerID) -// return; -// } + //if (presence.PresenceType == PresenceType.Npc && npcModule != null) + //{ + // UUID npcOwner = npcModule.GetOwner(presence.UUID); + // if (npcOwner != UUID.Zero && npcOwner != SensePoint.OwnerID) + // return; + //} // are they in range if (dis <= ts.range) { // Are they in the required angle of view - if (ts.arc < Math.PI) + if (ts.arc < MathF.PI) { // not omni-directional. Can you see it ? // vec forward_dir = llRot2Fwd(llGetRot()) @@ -598,14 +571,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins // mag_fwd = mag(forward_dir) // mag_obj = mag(obj_dir) // ang = acos(dot /(mag_fwd*mag_obj)) - double ang_obj = 0; + float ang_obj = 0; try { - LSL_Types.Vector3 obj_dir = new LSL_Types.Vector3( - toRegionPos - fromRegionPos); - double dot = LSL_Types.Vector3.Dot(forward_dir, obj_dir); - double mag_obj = LSL_Types.Vector3.Mag(obj_dir); - ang_obj = Math.Acos(dot / (mag_fwd * mag_obj)); + Vector3 obj_dir = toRegionPos - fromRegionPos; + float dot = Vector3.Dot(forward_dir, obj_dir); + float mag_corr = MathF.Sqrt( mag_fwd * obj_dir.LengthSquared()); + ang_obj = MathF.Acos(dot / mag_corr); } catch { @@ -664,11 +636,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins public Object[] GetSerializationData(UUID itemID) { - List<Object> data = new List<Object>(); + List<Object> data = new(); foreach (SensorInfo ts in SenseRepeaters) { - if (ts.itemID == itemID) + if (ts.itemID.Equals(itemID)) { data.Add(ts.interval); data.Add(ts.name); @@ -682,21 +654,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins return data.ToArray(); } - public void CreateFromData(uint localID, UUID itemID, UUID objectID, - Object[] data) + public void CreateFromData(uint localID, UUID itemID, UUID objectID, object[] data) { - SceneObjectPart part = - m_CmdManager.m_ScriptEngine.World.GetSceneObjectPart( - objectID); + SceneObjectPart part = m_CmdManager.m_ScriptEngine.World.GetSceneObjectPart(objectID); - if (part == null) + if (part is null) return; int idx = 0; while (idx < data.Length) { - SensorInfo ts = new SensorInfo + SensorInfo ts = new() { localID = localID, itemID = itemID, @@ -705,13 +674,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins name = (string)data[idx + 1], keyID = (UUID)data[idx + 2], type = (int)data[idx + 3], - range = (double)data[idx + 4], - arc = (double)data[idx + 5], + range = (float)data[idx + 4], + arc = (float)data[idx + 5], host = part }; - ts.next = - DateTime.Now.ToUniversalTime().AddSeconds(ts.interval); + ts.next = DateTime.UtcNow.AddSeconds(ts.interval); AddSenseRepeater(ts); @@ -721,7 +689,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins public List<SensorInfo> GetSensorInfo() { - List<SensorInfo> retList = new List<SensorInfo>(); + List<SensorInfo> retList = new(); lock (SenseRepeatListLock) {