diff --git a/LibreMetaverse.StructuredData/LibreMetaverse.StructuredData.csproj b/LibreMetaverse.StructuredData/LibreMetaverse.StructuredData.csproj index 4c70caa..0a5147c 100644 --- a/LibreMetaverse.StructuredData/LibreMetaverse.StructuredData.csproj +++ b/LibreMetaverse.StructuredData/LibreMetaverse.StructuredData.csproj @@ -3,7 +3,7 @@ LibreMetaverse.StructuredData LibreMetaverse structured data library LibreMetaverse.StructuredData - net48;netstandard2.1;net6.0;net7.0 + net7.0 Library LibreMetaverse.StructuredData true diff --git a/LibreMetaverse.Types/LibreMetaverse.Types.csproj b/LibreMetaverse.Types/LibreMetaverse.Types.csproj index a78282b..10954f2 100644 --- a/LibreMetaverse.Types/LibreMetaverse.Types.csproj +++ b/LibreMetaverse.Types/LibreMetaverse.Types.csproj @@ -3,7 +3,7 @@ LibreMetaverse.Types LibreMetaverse.Types LibreMetaverse type library - net48;netstandard2.1;net6.0;net7.0 + net7.0 Library LibreMetaverse true diff --git a/LibreMetaverse.Types/Utils.cs b/LibreMetaverse.Types/Utils.cs index 14443d1..2c5ea4a 100644 --- a/LibreMetaverse.Types/Utils.cs +++ b/LibreMetaverse.Types/Utils.cs @@ -366,7 +366,7 @@ namespace OpenMetaverse public static string MD5(string str) { StringBuilder digest = new StringBuilder(32); - byte[] hash = MD5(Encoding.Default.GetBytes(str)); + byte[] hash = MD5(Encoding.UTF8.GetBytes(str)); // Convert the hash to a hex string foreach (byte b in hash) @@ -399,7 +399,7 @@ namespace OpenMetaverse /// The PBKDF2 hash of the supplied string public static string PBKDF2(string str) { - var derivebytes = new Rfc2898DeriveBytes(str, 32) {IterationCount = 10000}; + var derivebytes = new Rfc2898DeriveBytes(str, 32, 10000, HashAlgorithmName.SHA1); byte[] hash = derivebytes.GetBytes(20); byte[] salt = derivebytes.Salt; return Convert.ToBase64String(salt) + "|" + Convert.ToBase64String(hash); diff --git a/LibreMetaverse/AgentManager.cs b/LibreMetaverse/AgentManager.cs index f71b509..27e6555 100644 --- a/LibreMetaverse/AgentManager.cs +++ b/LibreMetaverse/AgentManager.cs @@ -910,7 +910,7 @@ namespace OpenMetaverse /// Thread sync lock object private readonly object m_InstantMessageLock = new object(); - /// Raised when an ImprovedInstantMessage packet is recieved from the simulator, this is used for everything from + /// Raised when an ImprovedInstantMessage packet is received from the simulator, this is used for everything from /// private messaging to friendship offers. The Dialog field defines what type of message has arrived public event EventHandler IM { @@ -1104,8 +1104,7 @@ namespace OpenMetaverse protected virtual void OnCameraConstraint(CameraConstraintEventArgs e) { EventHandler handler = m_CameraConstraint; - if (handler != null) - handler(this, e); + handler?.Invoke(this, e); } /// Thread sync lock object @@ -1128,8 +1127,7 @@ namespace OpenMetaverse protected virtual void OnScriptSensorReply(ScriptSensorReplyEventArgs e) { EventHandler handler = m_ScriptSensorReply; - if (handler != null) - handler(this, e); + handler?.Invoke(this, e); } /// Thread sync lock object @@ -1151,8 +1149,7 @@ namespace OpenMetaverse protected virtual void OnAvatarSitResponse(AvatarSitResponseEventArgs e) { EventHandler handler = m_AvatarSitResponse; - if (handler != null) - handler(this, e); + handler?.Invoke(this, e); } /// Thread sync lock object @@ -1478,7 +1475,7 @@ namespace OpenMetaverse private HomeInfo home; private string fullName; - private TeleportStatus teleportStat = TeleportStatus.None; + private TeleportStatus teleportStatus = TeleportStatus.None; private ManualResetEvent teleportEvent = new ManualResetEvent(false); private uint heightWidthGenCounter; private Dictionary gestureCache = new Dictionary(); @@ -2966,7 +2963,13 @@ namespace OpenMetaverse /// true on success, false on failure public bool Teleport(UUID landmark) { - teleportStat = TeleportStatus.None; + if (teleportStatus == TeleportStatus.Progress) + { + Logger.Log("Teleport already in progress while attempting to teleport.", Helpers.LogLevel.Info, Client); + return false; + } + + teleportStatus = TeleportStatus.None; teleportEvent.Reset(); TeleportLandmarkRequestPacket p = new TeleportLandmarkRequestPacket { @@ -2981,15 +2984,15 @@ namespace OpenMetaverse teleportEvent.WaitOne(Client.Settings.TELEPORT_TIMEOUT, false); - if (teleportStat == TeleportStatus.None || - teleportStat == TeleportStatus.Start || - teleportStat == TeleportStatus.Progress) + if (teleportStatus == TeleportStatus.None || + teleportStatus == TeleportStatus.Start || + teleportStatus == TeleportStatus.Progress) { TeleportMessage = "Teleport timed out."; - teleportStat = TeleportStatus.Failed; + teleportStatus = TeleportStatus.Failed; } - return (teleportStat == TeleportStatus.Finished); + return (teleportStatus == TeleportStatus.Finished); } /// @@ -3018,7 +3021,14 @@ namespace OpenMetaverse { if (Client.Network.CurrentSim == null) { return false; } - teleportStat = TeleportStatus.None; + if (teleportStatus == TeleportStatus.Progress) + { + Logger.Log($"Teleport already in progress while attempting to teleport to {simName}.", + Helpers.LogLevel.Info, Client); + return false; + } + + teleportStatus = TeleportStatus.None; if (simName != Client.Network.CurrentSim.Name) { @@ -3030,7 +3040,7 @@ namespace OpenMetaverse else { TeleportMessage = $"Unable to resolve simulator named: {simName}"; - teleportStat = TeleportStatus.Failed; + teleportStatus = TeleportStatus.Failed; return false; } } @@ -3063,40 +3073,46 @@ namespace OpenMetaverse /// This call is blocking public bool Teleport(ulong regionHandle, Vector3 position, Vector3 lookAt) { + if (teleportStatus == TeleportStatus.Progress) + { + Logger.Log("Teleport already in progress while attempting to teleport.", + Helpers.LogLevel.Info, Client); + return false; + } + if (Client.Network.CurrentSim == null || Client.Network.CurrentSim.Caps == null || !Client.Network.CurrentSim.Caps.IsEventQueueRunning) { // Wait a bit to see if the event queue comes online AutoResetEvent queueEvent = new AutoResetEvent(false); - EventHandler queueCallback = - delegate(object sender, EventQueueRunningEventArgs e) - { - if (e.Simulator == Client.Network.CurrentSim) - queueEvent.Set(); - }; - Client.Network.EventQueueRunning += queueCallback; + void QueueCallback(object sender, EventQueueRunningEventArgs e) + { + if (e.Simulator == Client.Network.CurrentSim) { queueEvent.Set(); } + } + + Client.Network.EventQueueRunning += QueueCallback; queueEvent.WaitOne(10 * 1000, false); - Client.Network.EventQueueRunning -= queueCallback; + Client.Network.EventQueueRunning -= QueueCallback; } - teleportStat = TeleportStatus.None; + teleportStatus = TeleportStatus.None; teleportEvent.Reset(); RequestTeleport(regionHandle, position, lookAt); teleportEvent.WaitOne(Client.Settings.TELEPORT_TIMEOUT, false); - if (teleportStat == TeleportStatus.None || - teleportStat == TeleportStatus.Start || - teleportStat == TeleportStatus.Progress) + if (teleportStatus == TeleportStatus.None || + teleportStatus == TeleportStatus.Start || + teleportStatus == TeleportStatus.Progress) { TeleportMessage = "Teleport timed out."; - teleportStat = TeleportStatus.Failed; + teleportStatus = TeleportStatus.Failed; } - return (teleportStat == TeleportStatus.Finished); + return (teleportStatus == TeleportStatus.Finished); } /// @@ -3117,8 +3133,7 @@ namespace OpenMetaverse /// direction in destination sim agent will look at public void RequestTeleport(ulong regionHandle, Vector3 position, Vector3 lookAt) { - if (Client.Network.CurrentSim != null && - Client.Network.CurrentSim.Caps != null && + if (Client.Network?.CurrentSim?.Caps != null && Client.Network.CurrentSim.Caps.IsEventQueueRunning) { TeleportLocationRequestPacket teleport = new TeleportLocationRequestPacket @@ -3144,7 +3159,7 @@ namespace OpenMetaverse { TeleportMessage = "CAPS event queue is not running"; teleportEvent.Set(); - teleportStat = TeleportStatus.Failed; + teleportStatus = TeleportStatus.Failed; } } @@ -3251,7 +3266,7 @@ namespace OpenMetaverse } public void SendTeleportLureRequest(UUID targetID) { - SendTeleportLureRequest(targetID, "Hi there I would like to teleport to you"); + SendTeleportLureRequest(targetID, "Let me join you in your location"); } #endregion Teleporting @@ -4302,7 +4317,9 @@ namespace OpenMetaverse SimAccess = (byte) msg.SimAccess, SimIP = Utils.IPToUInt(msg.IP), SimPort = (ushort) msg.Port, - TeleportFlags = (uint) msg.Flags + TeleportFlags = (uint) msg.Flags, + RegionSizeX = msg.RegionSizeX, + RegionSizeY = msg.RegionSizeY } }; // FIXME: Check This @@ -4328,7 +4345,7 @@ namespace OpenMetaverse TeleportMessage = "Teleport started"; flags = (TeleportFlags)start.Info.TeleportFlags; - teleportStat = TeleportStatus.Start; + teleportStatus = TeleportStatus.Start; Logger.DebugLog($"TeleportStart received, Flags: {flags}", Client); } @@ -4338,7 +4355,7 @@ namespace OpenMetaverse TeleportMessage = Utils.BytesToString(progress.Info.Message); flags = (TeleportFlags)progress.Info.TeleportFlags; - teleportStat = TeleportStatus.Progress; + teleportStatus = TeleportStatus.Progress; Logger.DebugLog($"TeleportProgress received, Message: {TeleportMessage}, Flags: {flags}", Client); } @@ -4347,7 +4364,7 @@ namespace OpenMetaverse TeleportFailedPacket failed = (TeleportFailedPacket)packet; TeleportMessage = Utils.BytesToString(failed.Info.Reason); - teleportStat = TeleportStatus.Failed; + teleportStatus = TeleportStatus.Failed; finished = true; Logger.DebugLog($"TeleportFailed received, Reason: {TeleportMessage}", Client); @@ -4365,19 +4382,20 @@ namespace OpenMetaverse // Connect to the new sim Client.Network.CurrentSim.AgentMovementComplete = false; // we're not there anymore Simulator newSimulator = Client.Network.Connect(new IPAddress(finish.Info.SimIP), - finish.Info.SimPort, finish.Info.RegionHandle, true, seedcaps); + finish.Info.SimPort, finish.Info.RegionHandle, true, seedcaps, + finish.Info.RegionSizeX, finish.Info.RegionSizeY); if (newSimulator != null) { TeleportMessage = "Teleport finished"; - teleportStat = TeleportStatus.Finished; + teleportStatus = TeleportStatus.Finished; - Logger.Log($"Moved to new sim {newSimulator}", Helpers.LogLevel.Info, Client); + Logger.Log($"Moved to {newSimulator}", Helpers.LogLevel.Info, Client); } else { - TeleportMessage = "Failed to connect to the new sim after a teleport"; - teleportStat = TeleportStatus.Failed; + TeleportMessage = $"Failed to connect to {newSimulator} after teleport"; + teleportStatus = TeleportStatus.Failed; // We're going to get disconnected now Logger.Log(TeleportMessage, Helpers.LogLevel.Error, Client); @@ -4388,7 +4406,7 @@ namespace OpenMetaverse //TeleportCancelPacket cancel = (TeleportCancelPacket)packet; TeleportMessage = "Cancelled"; - teleportStat = TeleportStatus.Cancelled; + teleportStatus = TeleportStatus.Cancelled; finished = true; Logger.DebugLog($"TeleportCancel received from {simulator}", Client); @@ -4399,7 +4417,7 @@ namespace OpenMetaverse TeleportMessage = "Teleport finished"; flags = (TeleportFlags)local.Info.TeleportFlags; - teleportStat = TeleportStatus.Finished; + teleportStatus = TeleportStatus.Finished; relativePosition = local.Info.Position; Movement.Camera.LookDirection(local.Info.LookAt); // This field is apparently not used for anything @@ -4411,7 +4429,7 @@ namespace OpenMetaverse if (m_Teleport != null) { - OnTeleport(new TeleportEventArgs(TeleportMessage, teleportStat, flags)); + OnTeleport(new TeleportEventArgs(TeleportMessage, teleportStatus, flags)); } if (finished) { teleportEvent.Set(); } @@ -4541,7 +4559,8 @@ namespace OpenMetaverse Logger.DebugLog($"Crossed in to new region area, attempting to connect to {endPoint}", Client); Simulator oldSim = Client.Network.CurrentSim; - Simulator newSim = Client.Network.Connect(endPoint, crossed.RegionHandle, true, crossed.SeedCapability); + Simulator newSim = Client.Network.Connect(endPoint, crossed.RegionHandle, true, crossed.SeedCapability, + crossed.RegionSizeX, crossed.RegionSizeY); if (newSim != null) { diff --git a/LibreMetaverse/AgentManagerMovement.cs b/LibreMetaverse/AgentManagerMovement.cs index d16f227..08bc45c 100644 --- a/LibreMetaverse/AgentManagerMovement.cs +++ b/LibreMetaverse/AgentManagerMovement.cs @@ -393,18 +393,12 @@ namespace OpenMetaverse { if (value > 0) { - if (updateTimer != null) - { - updateTimer.Change(value, value); - } + updateTimer?.Change(value, value); updateInterval = value; } else { - if (updateTimer != null) - { - updateTimer.Change(Timeout.Infinite, Timeout.Infinite); - } + updateTimer?.Change(Timeout.Infinite, Timeout.Infinite); updateInterval = 0; } } diff --git a/LibreMetaverse/AssetCache.cs b/LibreMetaverse/AssetCache.cs index 9c19fd8..731aebf 100644 --- a/LibreMetaverse/AssetCache.cs +++ b/LibreMetaverse/AssetCache.cs @@ -219,7 +219,7 @@ namespace OpenMetaverse /// /// UUID of the asset /// Raw bytes the asset consists of - /// Weather the operation was successfull + /// Whether the operation was successful public bool SaveAssetToCache(UUID assetID, byte[] assetData) { if (!Operational()) diff --git a/LibreMetaverse/AssetManager.cs b/LibreMetaverse/AssetManager.cs index 4d287a2..f0c7ca1 100644 --- a/LibreMetaverse/AssetManager.cs +++ b/LibreMetaverse/AssetManager.cs @@ -319,8 +319,7 @@ namespace OpenMetaverse protected virtual void OnXferReceived(XferReceivedEventArgs e) { EventHandler handler = m_XferReceivedEvent; - if (handler != null) - handler(this, e); + handler?.Invoke(this, e); } /// Thread sync lock object @@ -344,8 +343,7 @@ namespace OpenMetaverse protected virtual void OnAssetUploaded(AssetUploadEventArgs e) { EventHandler handler = m_AssetUploadedEvent; - if (handler != null) - handler(this, e); + handler?.Invoke(this, e); } /// Thread sync lock object @@ -369,8 +367,7 @@ namespace OpenMetaverse protected virtual void OnUploadProgress(AssetUploadEventArgs e) { EventHandler handler = m_UploadProgressEvent; - if (handler != null) - handler(this, e); + handler?.Invoke(this, e); } /// Thread sync lock object @@ -394,8 +391,7 @@ namespace OpenMetaverse protected virtual void OnInitiateDownload(InitiateDownloadEventArgs e) { EventHandler handler = m_InitiateDownloadEvent; - if (handler != null) - handler(this, e); + handler?.Invoke(this, e); } /// Thread sync lock object @@ -419,8 +415,7 @@ namespace OpenMetaverse protected virtual void OnImageReceiveProgress(ImageReceiveProgressEventArgs e) { EventHandler handler = m_ImageReceiveProgressEvent; - if (handler != null) - handler(this, e); + handler?.Invoke(this, e); } /// Thread sync lock object @@ -640,8 +635,7 @@ namespace OpenMetaverse } // If ViewerAsset capability exists, use that, if not, fallback to UDP (which is obsoleted on Second Life.) - if (Client.Network.CurrentSim.Caps != null - && Client.Network.CurrentSim.Caps.CapabilityURI("ViewerAsset") != null) + if (Client.Network.CurrentSim?.Caps?.CapabilityURI("ViewerAsset") != null) { RequestAssetHTTP(assetID, transfer, callback); } @@ -827,10 +821,20 @@ namespace OpenMetaverse } // If ViewerAsset capability exists, use that, if not, fallback to UDP - if (Client.Network.CurrentSim.Caps != null - && Client.Network.CurrentSim.Caps.CapabilityURI("ViewerAsset") != null) + if (Client.Network.CurrentSim?.Caps?.CapabilityURI("ViewerAsset") != null) { - RequestInventoryAssetHTTP(assetID, transfer, callback); + RequestInventoryAssetHTTP(assetID, transfer, + (AssetDownload transferResult, Asset assetResult) => + { + if (transferResult.Success == false) + { + Logger.Log($"HTTP transfer has failed trying UDP", Helpers.LogLevel.Warning, Client); + RequestInventoryAssetUDP(assetID, itemID, taskID, ownerID, transfer, callback); + return; + } + callback(transferResult, assetResult); + } + ); } else { @@ -849,6 +853,7 @@ namespace OpenMetaverse /// private void RequestInventoryAssetHTTP(UUID assetID, AssetDownload transfer, AssetReceivedCallback callback) { + int attempts = 0; DownloadRequest req = new DownloadRequest( BuildFetchRequestUri(transfer.AssetType, assetID), null, @@ -873,6 +878,7 @@ namespace OpenMetaverse } else // download failed { + attempts++; Logger.Log($"Failed to fetch asset {assetID}: {((error == null) ? "" : error.Message)}", Helpers.LogLevel.Warning, Client); if (callback != null) @@ -880,6 +886,10 @@ namespace OpenMetaverse transfer.Success = false; transfer.Status = StatusCode.Error; } + if (attempts == 5) + { + callback(transfer, null); + } } } @@ -1213,8 +1223,7 @@ namespace OpenMetaverse if (meshID == UUID.Zero || callback == null) return; - if (Client.Network.CurrentSim.Caps != null && - Client.Network.CurrentSim.Caps.GetMeshCapURI() != null) + if (Client.Network.CurrentSim?.Caps?.GetMeshCapURI() != null) { // Do we have this mesh asset in the cache? if (Client.Assets.Cache.HasAsset(meshID)) @@ -1329,8 +1338,7 @@ namespace OpenMetaverse uint packetStart, TextureDownloadCallback callback, bool progress) { if (Client.Settings.USE_HTTP_TEXTURES - && Client.Network.CurrentSim.Caps != null - && Client.Network.CurrentSim.Caps.GetTextureCapURI() != null) + && Client.Network.CurrentSim?.Caps?.GetTextureCapURI() != null) { HttpRequestTexture(textureID, imageType, priority, discardLevel, packetStart, callback, progress); } diff --git a/LibreMetaverse/Assets/Archiving/OarFile.cs b/LibreMetaverse/Assets/Archiving/OarFile.cs index 99eb2a5..fc8d57f 100644 --- a/LibreMetaverse/Assets/Archiving/OarFile.cs +++ b/LibreMetaverse/Assets/Archiving/OarFile.cs @@ -206,6 +206,7 @@ namespace OpenMetaverse.Assets private static bool LoadTerrain(string filePath, byte[] data, TerrainLoadedCallback terrainCallback, long bytesRead, long totalBytes) { + // TODO: This needs to be re-written to read data from a saved varregion (sizeX != 256) float[,] terrain = new float[256, 256]; bool loaded = false; @@ -350,10 +351,10 @@ namespace OpenMetaverse.Assets BinaryWriter bs = new BinaryWriter(s); int y; - for (y = 0; y < 256; y++) + for (y = 0; y < sim.SizeY; y++) { int x; - for (x = 0; x < 256; x++) + for (x = 0; x < sim.SizeX; x++) { float height; sim.TerrainHeightAtPoint(x, y, out height); diff --git a/LibreMetaverse/AvatarManager.cs b/LibreMetaverse/AvatarManager.cs index d7d5b16..f0bfeaa 100644 --- a/LibreMetaverse/AvatarManager.cs +++ b/LibreMetaverse/AvatarManager.cs @@ -689,9 +689,7 @@ namespace OpenMetaverse /// True if Display name functionality is available public bool DisplayNamesAvailable() { - return (Client.Network.CurrentSim != null - && Client.Network.CurrentSim.Caps != null) - && Client.Network.CurrentSim.Caps.CapabilityURI("GetDisplayNames") != null; + return Client.Network.CurrentSim?.Caps?.CapabilityURI("GetDisplayNames") != null; } /// diff --git a/LibreMetaverse/Capabilities/CapsBase.cs b/LibreMetaverse/Capabilities/CapsBase.cs index c83649e..61b079b 100644 --- a/LibreMetaverse/Capabilities/CapsBase.cs +++ b/LibreMetaverse/Capabilities/CapsBase.cs @@ -296,8 +296,7 @@ namespace OpenMetaverse.Http } // Fire the download progress callback for each chunk of received data - if (state.DownloadProgressCallback != null) - state.DownloadProgressCallback(state.Request, response, totalBytesRead, totalSize); + state.DownloadProgressCallback?.Invoke(state.Request, response, totalBytesRead, totalSize); } if (nolength) diff --git a/LibreMetaverse/Capabilities/EventQueueClient.cs b/LibreMetaverse/Capabilities/EventQueueClient.cs index 72114fe..1dd3553 100644 --- a/LibreMetaverse/Capabilities/EventQueueClient.cs +++ b/LibreMetaverse/Capabilities/EventQueueClient.cs @@ -1,6 +1,6 @@ /* * Copyright (c) 2006-2016, openmetaverse.co - * Copyright (c) 2022, Sjofn LLC. + * Copyright (c) 2022-2023, Sjofn LLC. * All rights reserved. * * - Redistribution and use in source and binary forms, with or without @@ -38,9 +38,9 @@ namespace OpenMetaverse.Http public class EventQueueClient { /// For exponential backoff on error. - public const int REQUEST_BACKOFF_SECONDS = 15 * 1000; // 15 seconds start - public const int REQUEST_BACKOFF_SECONDS_INC = 5 * 1000; // 5 seconds increase - public const int REQUEST_BACKOFF_SECONDS_MAX = 5 * 60 * 1000; // 5 minutes + private const int REQUEST_BACKOFF_SECONDS = 15 * 1000; // 15 seconds start + private const int REQUEST_BACKOFF_SECONDS_INC = 5 * 1000; // 5 seconds increase + private const int REQUEST_BACKOFF_SECONDS_MAX = 5 * 60 * 1000; // 5 minutes public delegate void ConnectedCallback(); public delegate void EventCallback(string eventName, OSDMap body); @@ -48,13 +48,14 @@ namespace OpenMetaverse.Http public ConnectedCallback OnConnected; public EventCallback OnEvent; - public bool Running => _Running; + public bool Running { get; private set; } + + private readonly Uri _Address; + private readonly Simulator _Simulator; + private readonly CancellationTokenSource _queueCts; + private bool _Dead; + private OSD _AckPayload; - protected readonly Uri _Address; - protected readonly Simulator _Simulator; - protected bool _Dead; - protected bool _Running; - private CancellationTokenSource _HttpCts; /// Number of times we've received an unknown CAPS exception in series. private int _errorCount; @@ -63,19 +64,71 @@ namespace OpenMetaverse.Http { _Address = eventQueueLocation; _Simulator = sim; + _queueCts = new CancellationTokenSource(); } public void Start() { _Dead = false; - _Running = true; + Running = true; - // Create an EventQueueGet request - OSDMap payload = new OSDMap {["ack"] = new OSD(), ["done"] = OSD.FromBoolean(false)}; + Task.Factory.StartNew(() => + { + // Initial request + _AckPayload = new OSDMap { ["ack"] = new OSD(), ["done"] = OSD.FromBoolean(false) }; + var initialTimeoutCts = CancellationTokenSource.CreateLinkedTokenSource(_queueCts.Token); + initialTimeoutCts.CancelAfter(TimeSpan.FromSeconds(30)); + + Task initialReq = _Simulator.Client.HttpCapsClient.PostRequestAsync(_Address, OSDFormat.Xml, _AckPayload, + initialTimeoutCts.Token, RequestCompletedHandler, null, ConnectedResponseHandler); + + initialReq.Wait(initialTimeoutCts.Token); + initialTimeoutCts.Dispose(); + + while (Running && !_queueCts.Token.IsCancellationRequested) + { + if (_errorCount > 0) + { // Exponentially back off, so we don't hammer the CPU + while (!_queueCts.Token.IsCancellationRequested) + { + _queueCts.Token.WaitHandle.WaitOne( + Math.Min(REQUEST_BACKOFF_SECONDS + _errorCount * REQUEST_BACKOFF_SECONDS_INC, + REQUEST_BACKOFF_SECONDS_MAX)); + } + } + // Resume the connection. + if (!_queueCts.Token.IsCancellationRequested) + { + using (CancellationTokenSource timeoutCts = + CancellationTokenSource.CreateLinkedTokenSource(_queueCts.Token)) + { + timeoutCts.CancelAfter(TimeSpan.FromSeconds(30)); + + try + { + Task req = _Simulator.Client.HttpCapsClient.PostRequestAsync(_Address, OSDFormat.Xml, + _AckPayload, timeoutCts.Token, RequestCompletedHandler); + req.Wait(timeoutCts.Token); + } + catch (OperationCanceledException) + { + /*no-op*/ + } + } + } + + + // If the event queue is dead at this point, turn it off since + // that was the last thing we want to do + if (_Dead) + { + Running = false; + Logger.DebugLog($"Sent event queue shutdown message for {_Simulator}"); + } + } + + }, _queueCts.Token); // TOOD: TaskCreationOptions.LongRunning? - _HttpCts = new CancellationTokenSource(); - Task req = _Simulator.Client.HttpCapsClient.PostRequestAsync(_Address, OSDFormat.Xml, payload, _HttpCts.Token, - RequestCompletedHandler, null, ConnectedResponseHandler); } public void Stop(bool immediate) @@ -84,17 +137,17 @@ namespace OpenMetaverse.Http if (immediate) { - _Running = false; + Running = false; } - _HttpCts.Cancel(); + _queueCts.Cancel(); } void ConnectedResponseHandler(HttpResponseMessage response) { if (!response.IsSuccessStatusCode) { return; } - _Running = true; + Running = true; // The event queue is starting up for the first time if (OnConnected != null) @@ -120,11 +173,11 @@ namespace OpenMetaverse.Http } else { - Logger.Log($"Got an unparseable response from {_Simulator} event queue: \"" + + Logger.Log($"Received an invalid response from {_Simulator} event queue: \"" + System.Text.Encoding.UTF8.GetString(responseData) + "\"", Helpers.LogLevel.Warning); } } - else if (error != null) + else if (response != null && error != null) { #region Error handling @@ -132,30 +185,31 @@ namespace OpenMetaverse.Http { case HttpStatusCode.NotFound: case HttpStatusCode.Gone: - Logger.Log($"Closing event queue at {_Simulator} due to missing caps URI", Helpers.LogLevel.Info); + Logger.Log($"Closing event queue at {_Simulator} due to missing caps URI", Helpers.LogLevel.Info, _Simulator.Client); - _Running = false; + Running = false; _Dead = true; break; case (HttpStatusCode)499: // weird error returned occasionally, ignore for now // I believe this is the timeout error invented by LL for LSL HTTP-out requests (gwyneth 20220413) - Logger.Log($"Possible HTTP-out timeout error from {_Simulator}, no need to continue", Helpers.LogLevel.Debug); + Logger.Log($"Possible HTTP-out timeout error from {_Simulator}, no need to continue", Helpers.LogLevel.Debug, _Simulator.Client); - _Running = false; + Running = false; _Dead = true; break; case HttpStatusCode.InternalServerError: // As per LL's instructions, we ought to consider this a // 'request to close client' (gwyneth 20220413) - Logger.Log($"Grid sent a {response.StatusCode} at {_Simulator}, closing connection", Helpers.LogLevel.Debug); + Logger.Log($"Grid sent a {response.StatusCode} at {_Simulator}, closing connection", Helpers.LogLevel.Debug, _Simulator.Client); // ... but do we happen to have an InnerException? Log it! if (error.InnerException != null) { // unravel the whole inner error message, so we finally figure out what it is! // (gwyneth 20220414) - Logger.Log($"Unrecognized internal caps exception from {_Simulator}: '{error.InnerException.Message}'", Helpers.LogLevel.Warning); - Logger.Log($"\nMessage ---\n{error.Message}", Helpers.LogLevel.Warning); + Logger.Log($"Unrecognized internal caps exception from {_Simulator}: '{error.InnerException.Message}'", + Helpers.LogLevel.Warning, _Simulator.Client); + Logger.Log($"\nMessage ---\n{error.Message}", Helpers.LogLevel.Warning, _Simulator.Client); if (error.Data.Count > 0) { Logger.Log(" Extra details:", Helpers.LogLevel.Warning); @@ -163,13 +217,13 @@ namespace OpenMetaverse.Http { Logger.Log(String.Format(" Key: {0,-20} Value: '{1}'", de.Key, de.Value), - Helpers.LogLevel.Warning); + Helpers.LogLevel.Warning, _Simulator.Client); } } // but we'll nevertheless close this connection (gwyneth 20220414) } - _Running = false; + Running = false; _Dead = true; break; case HttpStatusCode.BadGateway: @@ -182,7 +236,8 @@ namespace OpenMetaverse.Http // Note: if this condition persists, it _might_ be the grid trying to request // that the client closes the connection, as per LL's specs (gwyneth 20220414) Logger.Log($"Grid sent a Bad Gateway Error at {_Simulator}; " + - $"probably a time-out from the grid's EventQueue server (normal) -- ignoring and continuing", Helpers.LogLevel.Debug); + $"probably a time-out from the grid's EventQueue server (normal) -- ignoring and continuing", + Helpers.LogLevel.Debug, _Simulator.Client); break; default: ++_errorCount; @@ -191,71 +246,55 @@ namespace OpenMetaverse.Http if (response.StatusCode != HttpStatusCode.OK) { Logger.Log($"Unrecognized caps connection problem from {_Simulator}: {response.StatusCode} {response.ReasonPhrase}", - Helpers.LogLevel.Warning); + Helpers.LogLevel.Warning, _Simulator.Client); } else if (error.InnerException != null) { // see comment above (gwyneth 20220414) - Logger.Log($"Unrecognized internal caps exception from {_Simulator}: '{error.InnerException.Message}'", Helpers.LogLevel.Warning); - Logger.Log($"Message ---\n{error.Message}", Helpers.LogLevel.Warning); + Logger.Log($"Unrecognized internal caps exception from {_Simulator}: '{error.InnerException.Message}'", + Helpers.LogLevel.Warning, _Simulator.Client); + Logger.Log($"Message ---\n{error.Message}", Helpers.LogLevel.Warning, _Simulator.Client); if (error.Data.Count > 0) { - Logger.Log(" Extra details:", Helpers.LogLevel.Warning); + Logger.Log(" Extra details:", Helpers.LogLevel.Warning, _Simulator.Client); foreach (DictionaryEntry de in error.Data) { Logger.Log(string.Format(" Key: {0,-20} Value: {1}", "'" + de.Key + "'", de.Value), - Helpers.LogLevel.Warning); + Helpers.LogLevel.Warning, _Simulator.Client); } } } else { Logger.Log($"Unrecognized caps exception from {_Simulator}: {error.Message}", - Helpers.LogLevel.Warning); + Helpers.LogLevel.Warning, _Simulator.Client); } break; } // end switch #endregion Error handling } + else if (error != null) + { + ++_errorCount; + Logger.Log($"Exception thrown from {_Simulator} event queue: " + + $"{(error.InnerException != null ? error.InnerException.Message : error.Message)}", Helpers.LogLevel.Warning, _Simulator.Client); + } else { ++_errorCount; - - Logger.Log($"No response from {_Simulator} event queue but no reported error either", Helpers.LogLevel.Warning); + Logger.Log($"No response from {_Simulator} event queue with no reported error", Helpers.LogLevel.Warning, _Simulator.Client); } - -#pragma warning disable CS0164 // This label has not been referenced - HandlingDone: - - #region Resume the connection - - if (_Running) + + if (Running) { OSDMap payload = new OSDMap(); if (ack != 0) { payload["ack"] = OSD.FromInteger(ack); } else { payload["ack"] = new OSD(); } payload["done"] = OSD.FromBoolean(_Dead); - - if (_errorCount > 0) { // Exponentially back off, so we don't hammer the CPU - Thread.Sleep(Math.Min(REQUEST_BACKOFF_SECONDS + _errorCount * REQUEST_BACKOFF_SECONDS_INC, REQUEST_BACKOFF_SECONDS_MAX)); - } - // Resume the connection. - Task req = _Simulator.Client.HttpCapsClient.PostRequestAsync(_Address, OSDFormat.Xml, payload, _HttpCts.Token, - RequestCompletedHandler); - - // If the event queue is dead at this point, turn it off since - // that was the last thing we want to do - if (_Dead) - { - _Running = false; - Logger.DebugLog($"Sent event queue shutdown message for {_Simulator}"); - } + _AckPayload = payload; } -#pragma warning restore CS0164 // This label has not been referenced - - #endregion Resume the connection #region Handle incoming events diff --git a/LibreMetaverse/Capabilities/HttpCapsClient.cs b/LibreMetaverse/Capabilities/HttpCapsClient.cs index ff55fd7..9f31663 100644 --- a/LibreMetaverse/Capabilities/HttpCapsClient.cs +++ b/LibreMetaverse/Capabilities/HttpCapsClient.cs @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Sjofn, LLC. + * Copyright (c) 2022-2023, Sjofn, LLC. * All rights reserved. * * - Redistribution and use in source and binary forms, with or without @@ -234,19 +234,26 @@ namespace LibreMetaverse private async Task SendRequestAsync(HttpRequestMessage request, CancellationToken? cancellationToken, DownloadCompleteHandler completeHandler, DownloadProgressHandler progressHandler, ConnectedHandler connectedHandler) { - using (var response = (cancellationToken.HasValue) - ? await SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken.Value) - : await SendAsync(request, HttpCompletionOption.ResponseHeadersRead)) + try { - if (!response.IsSuccessStatusCode) + using (var response = (cancellationToken.HasValue) + ? await SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken.Value) + : await SendAsync(request, HttpCompletionOption.ResponseHeadersRead)) { - completeHandler?.Invoke(response, null, - new HttpRequestException(response.StatusCode + " " + response.ReasonPhrase)); + if (!response.IsSuccessStatusCode) + { + completeHandler?.Invoke(response, null, + new HttpRequestException(response.StatusCode + " " + response.ReasonPhrase)); + } + + connectedHandler?.Invoke(response); + + await ProcessResponseAsync(response, cancellationToken, completeHandler, progressHandler); } - - connectedHandler?.Invoke(response); - - await ProcessResponseAsync(response, cancellationToken, completeHandler, progressHandler); + } + catch (HttpRequestException ex) + { + completeHandler?.Invoke(null, null, ex); } } diff --git a/LibreMetaverse/Caps.cs b/LibreMetaverse/Caps.cs index c7fa081..53bc460 100644 --- a/LibreMetaverse/Caps.cs +++ b/LibreMetaverse/Caps.cs @@ -307,6 +307,7 @@ namespace OpenMetaverse private void EventQueueConnectedHandler() { Logger.DebugLog($"Event queue for {Simulator} is connected", Simulator.Client); + Simulator.DisconnectCandidate = false; Simulator.Client.Network.RaiseConnectedEvent(Simulator); } @@ -333,7 +334,7 @@ namespace OpenMetaverse { Logger.Log($"No Message handler exists for event {eventName}. Unable to decode. Will try Generic Handler next", Helpers.LogLevel.Warning); - Logger.Log("Please report this information at https://radegast.life/bugs/issue-entry/: " + Environment.NewLine + body, + Logger.Log("Please report this information at https://github.com/cinderblocks/libremetaverse/issues: " + Environment.NewLine + body, Helpers.LogLevel.Debug); // try generic decoder next which takes a caps event and tries to match it to an existing packet diff --git a/LibreMetaverse/DirectoryManager.cs b/LibreMetaverse/DirectoryManager.cs index b6eb2dd..665a79f 100644 --- a/LibreMetaverse/DirectoryManager.cs +++ b/LibreMetaverse/DirectoryManager.cs @@ -1029,7 +1029,7 @@ namespace OpenMetaverse /// /// Searches Places for land owned by the specified group /// - /// ID of the group you want to recieve land list for (You must be a member of the group) + /// ID of the group you want to receive land list for (You must be a member of the group) /// Transaction (Query) ID which can be associated with results from your request. public UUID StartPlacesSearch(UUID groupID) { @@ -1055,7 +1055,7 @@ namespace OpenMetaverse /// One of the values from the SearchCategory Struct, ie: Any, Linden, Newcomer /// A string containing a list of keywords to search for separated by a space character /// String Simulator Name to search in - /// LLUID of group you want to recieve results for + /// LLUID of group you want to receive results for /// Transaction (Query) ID which can be associated with results from your request. /// Transaction (Query) ID which can be associated with results from your request. public UUID StartPlacesSearch(DirFindFlags findFlags, ParcelCategory searchCategory, string searchText, string simulatorName, diff --git a/LibreMetaverse/EstateTools.cs b/LibreMetaverse/EstateTools.cs index 3969982..06d49f4 100644 --- a/LibreMetaverse/EstateTools.cs +++ b/LibreMetaverse/EstateTools.cs @@ -167,8 +167,7 @@ namespace OpenMetaverse protected virtual void OnTopCollidersReply(TopCollidersReplyEventArgs e) { EventHandler handler = m_TopCollidersReply; - if (handler != null) - handler(this, e); + handler?.Invoke(this, e); } /// Thread sync lock object @@ -190,8 +189,7 @@ namespace OpenMetaverse protected virtual void OnTopScriptsReply(TopScriptsReplyEventArgs e) { EventHandler handler = m_TopScriptsReply; - if (handler != null) - handler(this, e); + handler?.Invoke(this, e); } /// Thread sync lock object @@ -214,8 +212,7 @@ namespace OpenMetaverse protected virtual void OnEstateUsersReply(EstateUsersReplyEventArgs e) { EventHandler handler = m_EstateUsersReply; - if (handler != null) - handler(this, e); + handler?.Invoke(this, e); } /// Thread sync lock object @@ -238,8 +235,7 @@ namespace OpenMetaverse protected virtual void OnEstateGroupsReply(EstateGroupsReplyEventArgs e) { EventHandler handler = m_EstateGroupsReply; - if (handler != null) - handler(this, e); + handler?.Invoke(this, e); } /// Thread sync lock object @@ -261,8 +257,7 @@ namespace OpenMetaverse protected virtual void OnEstateManagersReply(EstateManagersReplyEventArgs e) { EventHandler handler = m_EstateManagersReply; - if (handler != null) - handler(this, e); + handler?.Invoke(this, e); } /// Thread sync lock object @@ -284,8 +279,7 @@ namespace OpenMetaverse protected virtual void OnEstateBansReply(EstateBansReplyEventArgs e) { EventHandler handler = m_EstateBansReply; - if (handler != null) - handler(this, e); + handler?.Invoke(this, e); } /// Thread sync lock object @@ -307,8 +301,7 @@ namespace OpenMetaverse protected virtual void OnEstateCovenantReply(EstateCovenantReplyEventArgs e) { EventHandler handler = m_EstateCovenantReply; - if (handler != null) - handler(this, e); + handler?.Invoke(this, e); } /// Thread sync lock object @@ -331,8 +324,7 @@ namespace OpenMetaverse protected virtual void OnEstateUpdateInfoReply(EstateUpdateInfoReplyEventArgs e) { EventHandler handler = m_EstateUpdateInfoReply; - if (handler != null) - handler(this, e); + handler?.Invoke(this, e); } /// Thread sync lock object diff --git a/LibreMetaverse/FriendsManager.cs b/LibreMetaverse/FriendsManager.cs index f9ddfd9..5d2e565 100644 --- a/LibreMetaverse/FriendsManager.cs +++ b/LibreMetaverse/FriendsManager.cs @@ -218,8 +218,7 @@ namespace OpenMetaverse protected virtual void OnfriendsListReady(FriendsReadyEventArgs e) { EventHandler handler = m_FriendsListReadyResponse; - if (handler != null) - handler(this, e); + handler?.Invoke(this, e); } /// Thread sync lock object @@ -240,8 +239,7 @@ namespace OpenMetaverse protected virtual void OnFriendOnline(FriendInfoEventArgs e) { EventHandler handler = m_FriendOnline; - if (handler != null) - handler(this, e); + handler?.Invoke(this, e); } /// Thread sync lock object @@ -263,8 +261,7 @@ namespace OpenMetaverse protected virtual void OnFriendOffline(FriendInfoEventArgs e) { EventHandler handler = m_FriendOffline; - if (handler != null) - handler(this, e); + handler?.Invoke(this, e); } /// Thread sync lock object @@ -286,8 +283,7 @@ namespace OpenMetaverse protected virtual void OnFriendRights(FriendInfoEventArgs e) { EventHandler handler = m_FriendRights; - if (handler != null) - handler(this, e); + handler?.Invoke(this, e); } /// Thread sync lock object @@ -309,8 +305,7 @@ namespace OpenMetaverse protected virtual void OnFriendNames(FriendNamesEventArgs e) { EventHandler handler = m_FriendNames; - if (handler != null) - handler(this, e); + handler?.Invoke(this, e); } /// Thread sync lock object @@ -332,8 +327,7 @@ namespace OpenMetaverse protected virtual void OnFriendshipOffered(FriendshipOfferedEventArgs e) { EventHandler handler = m_FriendshipOffered; - if (handler != null) - handler(this, e); + handler?.Invoke(this, e); } /// Thread sync lock object @@ -355,8 +349,7 @@ namespace OpenMetaverse protected virtual void OnFriendshipResponse(FriendshipResponseEventArgs e) { EventHandler handler = m_FriendshipResponse; - if (handler != null) - handler(this, e); + handler?.Invoke(this, e); } /// Thread sync lock object @@ -378,8 +371,7 @@ namespace OpenMetaverse protected virtual void OnFriendshipTerminated(FriendshipTerminatedEventArgs e) { EventHandler handler = m_FriendshipTerminated; - if (handler != null) - handler(this, e); + handler?.Invoke(this, e); } /// Thread sync lock object @@ -402,8 +394,7 @@ namespace OpenMetaverse protected virtual void OnFriendFoundReply(FriendFoundReplyEventArgs e) { EventHandler handler = m_FriendFound; - if (handler != null) - handler(this, e); + handler?.Invoke(this, e); } /// Thread sync lock object diff --git a/LibreMetaverse/GridClient.cs b/LibreMetaverse/GridClient.cs index b7c83e1..28b14ad 100644 --- a/LibreMetaverse/GridClient.cs +++ b/LibreMetaverse/GridClient.cs @@ -145,7 +145,6 @@ namespace OpenMetaverse { AllowAutoRedirect = true, AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip, - MaxConnectionsPerServer = Settings.MAX_HTTP_CONNECTIONS, ServerCertificateCustomValidationCallback = (message, cert, chain, sslPolicyErrors) => { if (sslPolicyErrors == SslPolicyErrors.None) @@ -157,6 +156,10 @@ namespace OpenMetaverse return true; } }; + + if (Utils.GetRunningRuntime() != Utils.Runtime.Mono) + handler.MaxConnectionsPerServer = Settings.MAX_HTTP_CONNECTIONS; + HttpCapsClient client = new HttpCapsClient(handler); client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Add("User-Agent", $"{Settings.USER_AGENT}"); diff --git a/LibreMetaverse/GridManager.cs b/LibreMetaverse/GridManager.cs index e273a07..03f75a4 100644 --- a/LibreMetaverse/GridManager.cs +++ b/LibreMetaverse/GridManager.cs @@ -158,14 +158,15 @@ namespace OpenMetaverse public uint GlobalY; /// Get the Local X position of the item - public uint LocalX { get { return GlobalX % 256; } } + public uint LocalX { get { return GlobalX % Simulator.DefaultRegionSizeX; } } /// Get the Local Y position of the item - public uint LocalY { get { return GlobalY % 256; } } + public uint LocalY { get { return GlobalY % Simulator.DefaultRegionSizeY; } } /// Get the Handle of the region public ulong RegionHandle { - get { return Utils.UIntsToLong((uint)(GlobalX - (GlobalX % 256)), (uint)(GlobalY - (GlobalY % 256))); } + get { return Utils.UIntsToLong((uint)(GlobalX - (GlobalX % Simulator.DefaultRegionSizeX)), + (uint)(GlobalY - (GlobalY % Simulator.DefaultRegionSizeY))); } } } diff --git a/LibreMetaverse/GroupManager.cs b/LibreMetaverse/GroupManager.cs index 8ef83dd..ad72bfb 100644 --- a/LibreMetaverse/GroupManager.cs +++ b/LibreMetaverse/GroupManager.cs @@ -1047,9 +1047,7 @@ namespace OpenMetaverse UUID requestID = UUID.Random(); Uri cap = null; - if (Client.Network.CurrentSim != null - && Client.Network.CurrentSim.Caps != null - && (cap = Client.Network.CurrentSim.Caps.CapabilityURI("GroupMemberData")) != null) + if ((cap = Client.Network.CurrentSim?.Caps?.CapabilityURI("GroupMemberData")) != null) { OSDMap payload = new OSDMap(1) { ["group_id"] = @group }; Task req = Client.HttpCapsClient.PostRequestAsync(cap, OSDFormat.Xml, payload, CancellationToken.None, @@ -1630,11 +1628,9 @@ namespace OpenMetaverse { Uri ret = null; - if (Client.Network.Connected - && Client.Network.CurrentSim != null - && Client.Network.CurrentSim.Caps != null) + if (Client.Network.Connected) { - ret = Client.Network.CurrentSim.Caps.CapabilityURI("GroupAPIv1"); + ret = Client.Network.CurrentSim?.Caps?.CapabilityURI("GroupAPIv1"); if (ret != null) { ret = new Uri($"{ret}?group_id={groupID.ToString()}"); diff --git a/LibreMetaverse/Helpers.cs b/LibreMetaverse/Helpers.cs index 9f3b09b..45c6076 100644 --- a/LibreMetaverse/Helpers.cs +++ b/LibreMetaverse/Helpers.cs @@ -149,6 +149,11 @@ namespace OpenMetaverse /// Given an X/Y location in absolute (grid-relative) terms, a region /// handle is returned along with the local X/Y location in that region /// + /// + /// NOTE: this does not work for varregions -- the region handle is correct but + /// the local X,Y are wrong. TODO: create new function + /// that takes a reference to the region and thus can calculate region local address. + /// /// The absolute X location, a number such as /// 255360.35 /// The absolute Y location, a number such as @@ -160,8 +165,8 @@ namespace OpenMetaverse /// A 64-bit region handle that can be used to teleport to public static ulong GlobalPosToRegionHandle(float globalX, float globalY, out float localX, out float localY) { - uint x = ((uint)globalX / 256) * 256; - uint y = ((uint)globalY / 256) * 256; + uint x = ((uint)globalX / Simulator.DefaultRegionSizeX) * Simulator.DefaultRegionSizeX; + uint y = ((uint)globalY / Simulator.DefaultRegionSizeY) * Simulator.DefaultRegionSizeY; localX = globalX - (float)x; localY = globalY - (float)y; return Utils.UIntsToLong(x, y); diff --git a/LibreMetaverse/ImportExport/ModelUploader.cs b/LibreMetaverse/ImportExport/ModelUploader.cs index a487448..9ea6569 100644 --- a/LibreMetaverse/ImportExport/ModelUploader.cs +++ b/LibreMetaverse/ImportExport/ModelUploader.cs @@ -196,7 +196,8 @@ namespace OpenMetaverse.ImportExport Client.Inventory.RequestFetchInventory(reply["new_inventory_item"].AsUUID(), Client.Self.AgentID); } } - if (callback != null) callback(contents); + + callback?.Invoke(contents); })); } })); diff --git a/LibreMetaverse/InventoryAISClient.cs b/LibreMetaverse/InventoryAISClient.cs index 4e3e341..cb3cf1c 100644 --- a/LibreMetaverse/InventoryAISClient.cs +++ b/LibreMetaverse/InventoryAISClient.cs @@ -48,8 +48,7 @@ namespace LibreMetaverse Client = client; } - public bool IsAvailable => (Client.Network.CurrentSim.Caps != null && - Client.Network.CurrentSim.Caps.CapabilityURI(INVENTORY_CAP_NAME) != null); + public bool IsAvailable => (Client.Network.CurrentSim.Caps?.CapabilityURI(INVENTORY_CAP_NAME) != null); public async Task CreateInventory(UUID parentUuid, OSD newInventory, bool createLink, InventoryManager.ItemCreatedCallback callback) { diff --git a/LibreMetaverse/InventoryManager.cs b/LibreMetaverse/InventoryManager.cs index 7113422..5bc8b49 100644 --- a/LibreMetaverse/InventoryManager.cs +++ b/LibreMetaverse/InventoryManager.cs @@ -582,8 +582,7 @@ namespace OpenMetaverse } Uri cap; - if (Client.Network.CurrentSim.Caps != null && - (cap = Client.Network.CurrentSim.Caps.CapabilityURI("FetchInventory2")) != null) + if ((cap = Client.Network.CurrentSim?.Caps?.CapabilityURI("FetchInventory2")) != null) { OSDMap payload = new OSDMap { ["agent_id"] = Client.Self.AgentID }; diff --git a/LibreMetaverse/LibreMetaverse.csproj b/LibreMetaverse/LibreMetaverse.csproj index afe5cde..f42f7a4 100644 --- a/LibreMetaverse/LibreMetaverse.csproj +++ b/LibreMetaverse/LibreMetaverse.csproj @@ -11,7 +11,7 @@ true snupkg 0419,1574,1591 - net48;netstandard2.1;net6.0;net7.0 + net7.0 x64;x86;AnyCPU ..\bin\ @@ -44,8 +44,8 @@ - - + + diff --git a/LibreMetaverse/Login.cs b/LibreMetaverse/Login.cs index de2d593..bc1abdd 100644 --- a/LibreMetaverse/Login.cs +++ b/LibreMetaverse/Login.cs @@ -369,6 +369,8 @@ namespace OpenMetaverse public int CircuitCode; public uint RegionX; public uint RegionY; + public uint RegionSizeX; + public uint RegionSizeY; public ushort SimPort; public IPAddress SimIP; public string SeedCapability; @@ -488,6 +490,9 @@ namespace OpenMetaverse CircuitCode = (int)ParseUInt("circuit_code", reply); RegionX = ParseUInt("region_x", reply); RegionY = ParseUInt("region_y", reply); + // Region size is returned by OpenSimulator derived systems but not SL + RegionSizeX = reply.ContainsKey("region_size_x") ? ParseUInt("region_size_x", reply) : Simulator.DefaultRegionSizeX; + RegionSizeY = reply.ContainsKey("region_size_y") ? ParseUInt("region_size_y", reply) : Simulator.DefaultRegionSizeY; SimPort = (ushort)ParseUInt("sim_port", reply); var simIP = ParseString("sim_ip", reply); IPAddress.TryParse(simIP, out SimIP); @@ -693,6 +698,9 @@ namespace OpenMetaverse CircuitCode = (int)ParseUInt("circuit_code", reply); RegionX = ParseUInt("region_x", reply); RegionY = ParseUInt("region_y", reply); + // Region size is returned by OpenSimulator derived systems but not SL + RegionSizeX = reply.ContainsKey("region_size_x") ? ParseUInt("region_size_x", reply) : Simulator.DefaultRegionSizeX; + RegionSizeY = reply.ContainsKey("region_size_y") ? ParseUInt("region_size_y", reply) : Simulator.DefaultRegionSizeY; SimPort = (ushort)ParseUInt("sim_port", reply); var simIP = ParseString("sim_ip", reply); IPAddress.TryParse(simIP, out SimIP); @@ -1691,7 +1699,7 @@ namespace OpenMetaverse var handle = Utils.UIntsToLong(regionX, regionY); // Connect to the sim given in the login reply - if (Connect(reply.SimIP, simPort, handle, true, LoginSeedCapability) != null) + if (Connect(reply.SimIP, simPort, handle, true, LoginSeedCapability, reply.RegionSizeX, reply.RegionSizeY) != null) { // Request the economy data right after login SendPacket(new EconomyDataRequestPacket()); diff --git a/LibreMetaverse/Messages/LindenMessages.cs b/LibreMetaverse/Messages/LindenMessages.cs index be2565f..f6f1025 100644 --- a/LibreMetaverse/Messages/LindenMessages.cs +++ b/LibreMetaverse/Messages/LindenMessages.cs @@ -1,4 +1,4 @@ -/* +/* * Copyright (c) 2006-2016, openmetaverse.co * Copyright (c) 2021-2022, Sjofn LLC * All rights reserved. @@ -61,6 +61,10 @@ namespace OpenMetaverse.Messages.Linden /// Status flags indicating the state of the Agent upon arrival, Flying, etc. public TeleportFlags Flags; + /// The size of the region teleporting into + public uint RegionSizeX; + public uint RegionSizeY; + /// /// Serialize the object /// @@ -71,7 +75,7 @@ namespace OpenMetaverse.Messages.Linden OSDArray infoArray = new OSDArray(1); - OSDMap info = new OSDMap(8) + OSDMap info = new OSDMap(10) { {"AgentID", OSD.FromUUID(AgentID)}, {"LocationID", OSD.FromInteger(LocationID)}, @@ -80,7 +84,9 @@ namespace OpenMetaverse.Messages.Linden {"SimAccess", OSD.FromInteger((byte) SimAccess)}, {"SimIP", MessageUtils.FromIP(IP)}, {"SimPort", OSD.FromInteger(Port)}, - {"TeleportFlags", OSD.FromUInteger((uint) Flags)} + {"TeleportFlags", OSD.FromUInteger((uint) Flags)}, + {"RegionSizeX", OSD.FromUInteger((uint) RegionSizeX)}, + {"RegionSizeY", OSD.FromUInteger((uint) RegionSizeY)} }; // Unused by the client @@ -108,6 +114,8 @@ namespace OpenMetaverse.Messages.Linden IP = MessageUtils.ToIP(blockMap["SimIP"]); Port = blockMap["SimPort"].AsInteger(); Flags = (TeleportFlags)blockMap["TeleportFlags"].AsUInteger(); + RegionSizeX = blockMap.ContainsKey("RegionSizeX") ? blockMap["RegionSizeX"].AsUInteger() : Simulator.DefaultRegionSizeX; + RegionSizeY = blockMap.ContainsKey("RegionSizeY") ? blockMap["RegionSizeY"].AsUInteger() : Simulator.DefaultRegionSizeY; } } @@ -162,6 +170,8 @@ namespace OpenMetaverse.Messages.Linden public Uri SeedCapability; public IPAddress IP; public int Port; + public uint RegionSizeX; + public uint RegionSizeY; /// /// Serialize the object @@ -190,12 +200,14 @@ namespace OpenMetaverse.Messages.Linden map["AgentData"] = agentDataArray; OSDArray regionDataArray = new OSDArray(1); - OSDMap regionDataMap = new OSDMap(4) + OSDMap regionDataMap = new OSDMap(6) { ["RegionHandle"] = OSD.FromULong(RegionHandle), ["SeedCapability"] = OSD.FromUri(SeedCapability), ["SimIP"] = MessageUtils.FromIP(IP), - ["SimPort"] = OSD.FromInteger(Port) + ["SimPort"] = OSD.FromInteger(Port), + ["RegionSizeX"] = OSD.FromUInteger(RegionSizeX), + ["RegionSizeY"] = OSD.FromUInteger(RegionSizeY) }; regionDataArray.Add(regionDataMap); map["RegionData"] = regionDataArray; @@ -222,6 +234,8 @@ namespace OpenMetaverse.Messages.Linden SeedCapability = regionDataMap["SeedCapability"].AsUri(); IP = MessageUtils.ToIP(regionDataMap["SimIP"]); Port = regionDataMap["SimPort"].AsInteger(); + RegionSizeX = regionDataMap.ContainsKey("RegionSizeX") ? regionDataMap["RegionSizeX"].AsUInteger() : Simulator.DefaultRegionSizeX; + RegionSizeY = regionDataMap.ContainsKey("RegionSizeY") ? regionDataMap["RegionSizeY"].AsUInteger() : Simulator.DefaultRegionSizeY; } } @@ -232,6 +246,8 @@ namespace OpenMetaverse.Messages.Linden public ulong RegionHandle; public IPAddress IP; public int Port; + public uint RegionSizeX; + public uint RegionSizeY; } public SimulatorInfoBlock[] Simulators; @@ -247,11 +263,13 @@ namespace OpenMetaverse.Messages.Linden OSDArray array = new OSDArray(Simulators.Length); foreach (SimulatorInfoBlock block in Simulators) { - OSDMap blockMap = new OSDMap(3) + OSDMap blockMap = new OSDMap(5) { ["Handle"] = OSD.FromULong(block.RegionHandle), ["IP"] = MessageUtils.FromIP(block.IP), - ["Port"] = OSD.FromInteger(block.Port) + ["Port"] = OSD.FromInteger(block.Port), + ["RegionSizeX"] = OSD.FromUInteger(block.RegionSizeX), + ["RegionSizeY"] = OSD.FromUInteger(block.RegionSizeY), }; array.Add(blockMap); } @@ -277,7 +295,9 @@ namespace OpenMetaverse.Messages.Linden { RegionHandle = blockMap["Handle"].AsULong(), IP = MessageUtils.ToIP(blockMap["IP"]), - Port = blockMap["Port"].AsInteger() + Port = blockMap["Port"].AsInteger(), + RegionSizeX = blockMap.ContainsKey("RegionSizeX") ? blockMap["RegionSizeX"].AsUInteger() : Simulator.DefaultRegionSizeX, + RegionSizeY = blockMap.ContainsKey("RegionSizeY") ? blockMap["RegionSizeY"].AsUInteger() : Simulator.DefaultRegionSizeY, }; Simulators[i] = block; } @@ -5395,7 +5415,7 @@ namespace OpenMetaverse.Messages.Linden } /// - /// Message recieved in response to request to change display name + /// Message received in response to request to change display name /// public class SetDisplayNameReplyMessage : IMessage { @@ -5434,7 +5454,7 @@ namespace OpenMetaverse.Messages.Linden } /// - /// Message recieved when someone nearby changes their display name + /// Message received when someone nearby changes their display name /// public class DisplayNameUpdateMessage : IMessage { diff --git a/LibreMetaverse/NetworkManager.cs b/LibreMetaverse/NetworkManager.cs index f8794a3..c182693 100644 --- a/LibreMetaverse/NetworkManager.cs +++ b/LibreMetaverse/NetworkManager.cs @@ -36,7 +36,7 @@ using OpenMetaverse.Interfaces; using OpenMetaverse.Messages.Linden; namespace OpenMetaverse -{ +{ /// /// NetworkManager is responsible for managing the network layer of /// OpenMetaverse. It tracks all the server connections, serializes @@ -463,14 +463,14 @@ namespace OpenMetaverse { Logger.DebugLog("simulator object was null, using first found connected simulator", Client); simulator = Client.Network.Simulators[0]; - } + } if (simulator != null) { simulator.SendPacket(packet); } - else - { - NetworkInvaildWarning("simulator", "SendPacket"); + else + { + NetworkInvaildWarning("simulator", "SendPacket"); } } @@ -479,34 +479,34 @@ namespace OpenMetaverse /// /// Incoming packet to process public void EnqueueIncoming(IncomingPacket packet) - { - if (_packetInbox != null) - { - if (_packetInbox.Writer.TryWrite(packet)) - Interlocked.Increment(ref _packetInboxCount); - } - else - { - NetworkInvaildWarning("_packetInbox", "EnqueueIncoming"); + { + if (_packetInbox != null) + { + if (_packetInbox.Writer.TryWrite(packet)) + Interlocked.Increment(ref _packetInboxCount); } - } - + else + { + NetworkInvaildWarning("_packetInbox", "EnqueueIncoming"); + } + } + /// /// adds a debug message when you try to access a network item /// while they are still null /// /// what /// where - protected void NetworkInvaildWarning(string source,string function) - { - long now = DateTimeOffset.Now.ToUnixTimeSeconds(); - long dif = lastpacketwarning - now; - if (dif > 10) - { - lastpacketwarning = now; - Logger.Log(source+" is null (Are we disconnected?) - from: "+ function, - Helpers.LogLevel.Debug); - } + protected void NetworkInvaildWarning(string source,string function) + { + long now = DateTimeOffset.Now.ToUnixTimeSeconds(); + long dif = lastpacketwarning - now; + if (dif > 10) + { + lastpacketwarning = now; + Logger.Log(source+" is null (Are we disconnected?) - from: " + function, + Helpers.LogLevel.Debug); + } } /// @@ -515,17 +515,30 @@ namespace OpenMetaverse /// Incoming packet to process public void EnqueueOutgoing(OutgoingPacket packet) { - if (_packetOutbox != null) - { - if (_packetOutbox.Writer.TryWrite(packet)) + if (_packetOutbox != null) + { + if (_packetOutbox.Writer.TryWrite(packet)) Interlocked.Increment(ref _packetOutboxCount); - } - else - { - NetworkInvaildWarning("_packetOutbox", "EnqueueOutgoing"); + } + else + { + NetworkInvaildWarning("_packetOutbox", "EnqueueOutgoing"); } } + /// + /// Connect to simulator assuming legacy region size + /// + /// IP address to connect to + /// Port to connect to + /// + /// + /// + /// + public Simulator Connect(IPAddress ip, ushort port, ulong handle, bool setDefault, Uri seedcaps) + { + return Connect(ip, port, handle, setDefault, seedcaps, Simulator.DefaultRegionSizeX, Simulator.DefaultRegionSizeY); + } /// /// Connect to a simulator /// @@ -537,13 +550,26 @@ namespace OpenMetaverse /// connection, use this if the avatar is moving in to this simulator /// URL of the capabilities server to use for /// this sim connection + /// Size of the region in X meters + /// Size of the region in Y meters /// A Simulator object on success, otherwise null - public Simulator Connect(IPAddress ip, ushort port, ulong handle, bool setDefault, Uri seedcaps) + public Simulator Connect(IPAddress ip, ushort port, ulong handle, bool setDefault, Uri seedcaps, uint sizeX, uint sizeY) { IPEndPoint endPoint = new IPEndPoint(ip, port); - return Connect(endPoint, handle, setDefault, seedcaps); + return Connect(endPoint, handle, setDefault, seedcaps, sizeX, sizeY); } + /// + /// Connect to simulator assuming legacy region size + /// + /// + /// + /// + /// + /// + public Simulator Connect(IPEndPoint endPoint, ulong handle, bool setDefault, Uri seedcaps) { + return Connect(endPoint, handle, setDefault, seedcaps, Simulator.DefaultRegionSizeX, Simulator.DefaultRegionSizeY); + } /// /// Connect to a simulator /// @@ -554,15 +580,17 @@ namespace OpenMetaverse /// connection, use this if the avatar is moving in to this simulator /// URL of the capabilities server to use for /// this sim connection + /// Size of the region in X meters + /// Size of the region in Y meters /// A Simulator object on success, otherwise null - public Simulator Connect(IPEndPoint endPoint, ulong handle, bool setDefault, Uri seedcaps) + public Simulator Connect(IPEndPoint endPoint, ulong handle, bool setDefault, Uri seedcaps, uint sizeX, uint sizeY) { Simulator simulator = FindSimulator(endPoint); if (simulator == null) { // We're not tracking this sim, create a new Simulator object - simulator = new Simulator(Client, endPoint, handle); + simulator = new Simulator(Client, endPoint, handle, sizeX, sizeY); // Immediately add this simulator to the list of current sims. It will be removed if the // connection fails @@ -639,7 +667,7 @@ namespace OpenMetaverse lock (Simulators) { Simulators.Remove(simulator); - } + } return null; } @@ -682,13 +710,13 @@ namespace OpenMetaverse // Otherwise we fire it manually with a NetworkTimeout type after LOGOUT_TIMEOUT System.Timers.Timer timeout = new System.Timers.Timer(); - EventHandler callback = delegate + void Callback(object sender, LoggedOutEventArgs e) { Shutdown(DisconnectType.ClientInitiated); timeout.Stop(); - }; + } - LoggedOut += callback; + LoggedOut += Callback; timeout.Interval = Client.Settings.LOGOUT_TIMEOUT; timeout.Elapsed += delegate @@ -702,7 +730,7 @@ namespace OpenMetaverse // Send the packet requesting a clean logout RequestLogout(); - LoggedOut -= callback; + LoggedOut -= Callback; } /// @@ -713,9 +741,13 @@ namespace OpenMetaverse public void Logout() { AutoResetEvent logoutEvent = new AutoResetEvent(false); - EventHandler callback = delegate { logoutEvent.Set(); }; - LoggedOut += callback; + void Callback(object sender, LoggedOutEventArgs e) + { + logoutEvent.Set(); + } + + LoggedOut += Callback; // Send the packet requesting a clean logout RequestLogout(); @@ -724,9 +756,11 @@ namespace OpenMetaverse // will be fired in the callback. Otherwise we fire it manually with // a NetworkTimeout type if (!logoutEvent.WaitOne(Client.Settings.LOGOUT_TIMEOUT, false)) + { Shutdown(DisconnectType.NetworkTimeout); + } - LoggedOut -= callback; + LoggedOut -= Callback; } /// @@ -787,20 +821,26 @@ namespace OpenMetaverse simulatorsCount = Simulators.Count; } - if (simulatorsCount == 0) Shutdown(DisconnectType.SimShutdown); + if (simulatorsCount == 0) + { + Shutdown(DisconnectType.SimShutdown, $"You have disconnected from {simulator.Name}."); + } } - else - { - NetworkInvaildWarning("simulator", "DisconnectSim"); + else + { + NetworkInvaildWarning("simulator", "DisconnectSim"); } } /// - /// Shutdown will disconnect all the sims except for the current sim - /// first, and then kill the connection to CurrentSim. This should only - /// be called if the logout process times out on RequestLogout + /// This method disconnects Client from all simulators leaving CurrentSim + /// last to disconnect. /// + /// + /// This should only be called if the logout process times out on + /// RequestLogout + /// /// Type of shutdown public void Shutdown(DisconnectType type) { @@ -808,10 +848,13 @@ namespace OpenMetaverse } /// - /// Shutdown will disconnect all the sims except for the current sim - /// first, and then kill the connection to CurrentSim. This should only - /// be called if the logout process times out on RequestLogout + /// This method disconnects Client from all simulators leaving CurrentSim + /// last to disconnect. /// + /// + /// This should only be called if the logout process times out on + /// RequestLogout + /// /// Type of shutdown /// Shutdown message public void Shutdown(DisconnectType type, string message) @@ -824,17 +867,14 @@ namespace OpenMetaverse lock (Simulators) { // Disconnect all simulators except the current one - foreach (Simulator t in Simulators) + foreach (var sim in Simulators.Where(t => t != null && t != CurrentSim)) { - if (t != null && t != CurrentSim) - { - t.Disconnect(sendCloseCircuit); + sim.Disconnect(sendCloseCircuit); - // Fire the SimDisconnected event if a handler is registered - if (m_SimDisconnected != null) - { - OnSimDisconnected(new SimDisconnectedEventArgs(t, type)); - } + // Fire the SimDisconnected event if a handler is registered + if (m_SimDisconnected != null) + { + OnSimDisconnected(new SimDisconnectedEventArgs(sim, type)); } } @@ -843,7 +883,7 @@ namespace OpenMetaverse if (CurrentSim != null) { - // Kill the connection to the curent simulator + // Kill the connection to the current simulator CurrentSim.Disconnect(sendCloseCircuit); // Fire the SimDisconnected event if a handler is registered @@ -881,10 +921,9 @@ namespace OpenMetaverse { lock (Simulators) { - foreach (Simulator t in Simulators) + foreach (var sim in Simulators.Where(t => t.IPEndPoint.Equals(endPoint))) { - if (t.IPEndPoint.Equals(endPoint)) - return t; + return sim; } } @@ -913,73 +952,73 @@ namespace OpenMetaverse private async Task OutgoingPacketHandler() { - if (_packetOutbox != null) - { - var reader = _packetOutbox.Reader; - - // FIXME: This is kind of ridiculous. Port the HTB code from Simian over ASAP! - var stopwatch = new System.Diagnostics.Stopwatch(); - - while (await reader.WaitToReadAsync() && Connected) - { - while (reader.TryRead(out var outgoingPacket)) - { - Interlocked.Decrement(ref _packetOutboxCount); - - var simulator = outgoingPacket.Simulator; - - stopwatch.Stop(); - if (stopwatch.ElapsedMilliseconds < 10) - { - //Logger.DebugLog(String.Format("Rate limiting, last packet was {0}ms ago", ms)); - Thread.Sleep(10 - (int)stopwatch.ElapsedMilliseconds); - } - - simulator.SendPacketFinal(outgoingPacket); - stopwatch.Start(); - } + if (_packetOutbox != null) + { + var reader = _packetOutbox.Reader; + + // FIXME: This is kind of ridiculous. Port the HTB code from Simian over ASAP! + var stopwatch = new System.Diagnostics.Stopwatch(); + + while (await reader.WaitToReadAsync() && Connected) + { + while (reader.TryRead(out var outgoingPacket)) + { + Interlocked.Decrement(ref _packetOutboxCount); + + var simulator = outgoingPacket.Simulator; + + stopwatch.Stop(); + if (stopwatch.ElapsedMilliseconds < 10) + { + //Logger.DebugLog(String.Format("Rate limiting, last packet was {0}ms ago", ms)); + Thread.Sleep(10 - (int)stopwatch.ElapsedMilliseconds); + } + + simulator.SendPacketFinal(outgoingPacket); + stopwatch.Start(); + } } - } - else - { - NetworkInvaildWarning("_packetOutbox", "OutgoingPacketHandler"); + } + else + { + NetworkInvaildWarning("_packetOutbox", "OutgoingPacketHandler"); } } private async Task IncomingPacketHandler() { - if (_packetInbox != null) - { - var reader = _packetInbox.Reader; - - while (await reader.WaitToReadAsync() && Connected) - { - while (reader.TryRead(out var incomingPacket)) - { - Interlocked.Decrement(ref _packetInboxCount); - - var packet = incomingPacket.Packet; - var simulator = incomingPacket.Simulator; - - if (packet == null) continue; - - // Skip blacklisted packets - if (UDPBlacklist.Contains(packet.Type.ToString())) - { - Logger.Log($"Discarding Blacklisted packet {packet.Type} from {simulator.IPEndPoint}", - Helpers.LogLevel.Warning); - return; - } - - // Fire the callback(s), if any - PacketEvents.RaiseEvent(packet.Type, packet, simulator); - } + if (_packetInbox != null) + { + var reader = _packetInbox.Reader; + + while (await reader.WaitToReadAsync() && Connected) + { + while (reader.TryRead(out var incomingPacket)) + { + Interlocked.Decrement(ref _packetInboxCount); + + var packet = incomingPacket.Packet; + var simulator = incomingPacket.Simulator; + + if (packet == null) continue; + + // Skip blacklisted packets + if (UDPBlacklist.Contains(packet.Type.ToString())) + { + Logger.Log($"Discarding Blacklisted packet {packet.Type} from {simulator.IPEndPoint}", + Helpers.LogLevel.Warning); + return; + } + + // Fire the callback(s), if any + PacketEvents.RaiseEvent(packet.Type, packet, simulator); + } } - } - else - { - NetworkInvaildWarning("_packetInbox", "IncomingPacketHandler"); + } + else + { + NetworkInvaildWarning("_packetInbox", "IncomingPacketHandler"); } } @@ -1277,10 +1316,10 @@ namespace OpenMetaverse if (FindSimulator(endPoint) != null) return; - if (Connect(ip, port, handle, false, null) == null) + if (Connect(ip, port, handle, false, null, t.RegionSizeX, t.RegionSizeY) == null) { Logger.Log($"Unable to connect to new sim {ip}:{port}", - Helpers.LogLevel.Error, Client); + Helpers.LogLevel.Error, Client); } } } diff --git a/LibreMetaverse/ObjectManager.cs b/LibreMetaverse/ObjectManager.cs index e7470a8..d7df9cc 100644 --- a/LibreMetaverse/ObjectManager.cs +++ b/LibreMetaverse/ObjectManager.cs @@ -198,8 +198,7 @@ namespace OpenMetaverse protected virtual void OnObjectProperties(ObjectPropertiesEventArgs e) { EventHandler handler = m_ObjectProperties; - if (handler != null) - handler(this, e); + handler?.Invoke(this, e); } /// Thread sync lock object @@ -224,8 +223,7 @@ namespace OpenMetaverse protected virtual void OnObjectPropertiesUpdated(ObjectPropertiesUpdatedEventArgs e) { EventHandler handler = m_ObjectPropertiesUpdated; - if (handler != null) - handler(this, e); + handler?.Invoke(this, e); } /// Thread sync lock object @@ -250,8 +248,7 @@ namespace OpenMetaverse protected virtual void OnObjectPropertiesFamily(ObjectPropertiesFamilyEventArgs e) { EventHandler handler = m_ObjectPropertiesFamily; - if (handler != null) - handler(this, e); + handler?.Invoke(this, e); } /// Thread sync lock object @@ -278,8 +275,7 @@ namespace OpenMetaverse protected virtual void OnAvatarUpdate(AvatarUpdateEventArgs e) { EventHandler handler = m_AvatarUpdate; - if (handler != null) - handler(this, e); + handler?.Invoke(this, e); } /// /// Raises the ParticleUpdate Event @@ -288,8 +284,7 @@ namespace OpenMetaverse /// the data sent from the simulator protected virtual void OnParticleUpdate(ParticleUpdateEventArgs e) { EventHandler handler = m_ParticleUpdate; - if (handler != null) - handler(this, e); + handler?.Invoke(this, e); } /// Thread sync lock object @@ -337,8 +332,7 @@ namespace OpenMetaverse protected virtual void OnObjectDataBlockUpdate(ObjectDataBlockUpdateEventArgs e) { EventHandler handler = m_ObjectDataBlockUpdate; - if (handler != null) - handler(this, e); + handler?.Invoke(this, e); } /// Thread sync lock object @@ -363,8 +357,7 @@ namespace OpenMetaverse protected virtual void OnKillObject(KillObjectEventArgs e) { EventHandler handler = m_KillObject; - if (handler != null) - handler(this, e); + handler?.Invoke(this, e); } /// Thread sync lock object @@ -389,8 +382,7 @@ namespace OpenMetaverse protected virtual void OnKillObjects(KillObjectsEventArgs e) { EventHandler handler = m_KillObjects; - if (handler != null) - handler(this, e); + handler?.Invoke(this, e); } /// Thread sync lock object @@ -415,8 +407,7 @@ namespace OpenMetaverse protected virtual void OnAvatarSitChanged(AvatarSitChangedEventArgs e) { EventHandler handler = m_AvatarSitChanged; - if (handler != null) - handler(this, e); + handler?.Invoke(this, e); } /// Thread sync lock object @@ -441,8 +432,7 @@ namespace OpenMetaverse protected virtual void OnPayPriceReply(PayPriceReplyEventArgs e) { EventHandler handler = m_PayPriceReply; - if (handler != null) - handler(this, e); + handler?.Invoke(this, e); } /// Thread sync lock object @@ -475,8 +465,7 @@ namespace OpenMetaverse protected virtual void OnPhysicsProperties(PhysicsPropertiesEventArgs e) { EventHandler handler = m_PhysicsProperties; - if (handler != null) - handler(this, e); + handler?.Invoke(this, e); } /// Thread sync lock object @@ -2611,8 +2600,7 @@ namespace OpenMetaverse #region Raise Events EventHandler handler = m_ObjectUpdate; - if (handler != null) - handler(this, new PrimEventArgs(simulator, prim, update.RegionData.TimeDilation, isNew, prim.IsAttachment)); + handler?.Invoke(this, new PrimEventArgs(simulator, prim, update.RegionData.TimeDilation, isNew, prim.IsAttachment)); #endregion } @@ -3310,10 +3298,7 @@ namespace OpenMetaverse // Start the timer again. Use a minimum of a 50ms pause in between calculations int delay = Math.Max(50, Settings.INTERPOLATION_INTERVAL - elapsed); - if (InterpolationTimer != null) - { - InterpolationTimer.Change(delay, Timeout.Infinite); - } + InterpolationTimer?.Change(delay, Timeout.Infinite); } } diff --git a/LibreMetaverse/ParcelManager.cs b/LibreMetaverse/ParcelManager.cs index d6f064f..d105099 100644 --- a/LibreMetaverse/ParcelManager.cs +++ b/LibreMetaverse/ParcelManager.cs @@ -606,13 +606,12 @@ namespace OpenMetaverse Media = new ParcelMedia(); } - /// - /// Update the parcel (in the current sim) - /// - /// Client message originates from - /// Whether we want the simulator to confirm - /// the update with a reply packet or not [default false] - public void Update(GridClient client, bool wantReply = false) + public void Update(GridClient client) + { + Update(client, client.Network.CurrentSim, false); + } + + public void Update(GridClient client, bool wantReply) { Update(client, client.Network.CurrentSim, wantReply); } @@ -1688,7 +1687,17 @@ namespace OpenMetaverse { OSD res = null; await Client.HttpCapsClient.PostRequestAsync(cap, OSDFormat.Xml, msg.Serialize(), CancellationToken.None, - (response, data, error) => res = OSDParser.Deserialize(data)); + (response, data, error) => + { + if (data != null) + { + res = OSDParser.Deserialize(data); + } + else if (error != null) + { + Logger.Log("Did not receive response from RemoteParcelRequest: " + error.Message, Helpers.LogLevel.Warning, Client); + } + }); if (res is OSDMap result) { diff --git a/LibreMetaverse/Primitives/TextureEntry.cs b/LibreMetaverse/Primitives/TextureEntry.cs index 5359703..3cf9f51 100644 --- a/LibreMetaverse/Primitives/TextureEntry.cs +++ b/LibreMetaverse/Primitives/TextureEntry.cs @@ -768,16 +768,11 @@ namespace OpenMetaverse private void FromBytes(byte[] data, int pos, int length) { + DefaultTexture = new TextureEntryFace(null); + if (length < 16) - { // No TextureEntry to process - DefaultTexture = null; return; - } - else - { - DefaultTexture = new TextureEntryFace(null); - } uint bitfieldSize = 0; uint faceBits = 0; diff --git a/LibreMetaverse/Settings.cs b/LibreMetaverse/Settings.cs index aec56ab..748ae9e 100644 --- a/LibreMetaverse/Settings.cs +++ b/LibreMetaverse/Settings.cs @@ -217,10 +217,6 @@ namespace OpenMetaverse /// server the full object info will automatically be requested public bool ALWAYS_REQUEST_OBJECTS = true; - /// Whether to establish connections to HTTP capabilities - /// servers for simulators - public bool ENABLE_CAPS = true; - /// Whether to decode sim stats public bool ENABLE_SIMSTATS = true; @@ -342,11 +338,7 @@ namespace OpenMetaverse /// You will get no output on the console. This behavior can be overriden by creating /// a logger configuration file for log4net /// -#if DEBUG - public static Helpers.LogLevel LOG_LEVEL = Helpers.LogLevel.Debug; -#else public static Helpers.LogLevel LOG_LEVEL = Helpers.LogLevel.None; -#endif /// Attach avatar names to log messages public bool LOG_NAMES = true; diff --git a/LibreMetaverse/Simulator.cs b/LibreMetaverse/Simulator.cs index 6d74060..2f82738 100644 --- a/LibreMetaverse/Simulator.cs +++ b/LibreMetaverse/Simulator.cs @@ -171,7 +171,7 @@ namespace OpenMetaverse public int ConnectTime; /// Total number of packets that have been resent public int ResentPackets; - /// Total number of resent packets recieved + /// Total number of resent packets received public int ReceivedResends; /// Total number of pings sent to this simulator by this agent public int SentPings; @@ -180,7 +180,7 @@ namespace OpenMetaverse /// /// Incoming bytes per second /// - /// It would be nice to have this claculated on the fly, but + /// It would be nice to have this calculated on the fly, but /// this is far, far easier public int IncomingBPS; /// @@ -252,6 +252,11 @@ namespace OpenMetaverse #endregion Structs #region Public Members + + // Default legacy simulator/region size + public const uint DefaultRegionSizeX = 256; + public const uint DefaultRegionSizeY = 256; + /// A public reference to the client that this Simulator object is attached to public GridClient Client; /// A Unique Cache identifier for this simulator @@ -260,6 +265,10 @@ namespace OpenMetaverse public Caps Caps; /// Unique identified for this region generated via it's coordinates on the world map public ulong Handle; + /// Simulator land size in X direction in meters + public uint SizeX; + /// Simulator land size in Y direction in meters + public uint SizeY; /// The current version of software this simulator is running public string SimVersion = String.Empty; /// Human readable name given to the simulator @@ -497,10 +506,7 @@ namespace OpenMetaverse public readonly SimulatorDataPool DataPool; internal bool DownloadingParcelMap { - get - { - return Client.Settings.POOL_PARCEL_DATA ? DataPool.DownloadingParcelMap : _DownloadingParcelMap; - } + get => Client.Settings.POOL_PARCEL_DATA ? DataPool.DownloadingParcelMap : _DownloadingParcelMap; set { if (Client.Settings.POOL_PARCEL_DATA) DataPool.DownloadingParcelMap = value; @@ -520,7 +526,7 @@ namespace OpenMetaverse /// Reference to the object /// IPEndPoint of the simulator /// Region handle for the simulator - public Simulator(GridClient client, IPEndPoint address, ulong handle) + public Simulator(GridClient client, IPEndPoint address, ulong handle, uint sizeX = DefaultRegionSizeX, uint sizeY = DefaultRegionSizeY) : base(address) { Client = client; @@ -532,14 +538,16 @@ namespace OpenMetaverse Handle = handle; Network = Client.Network; + SizeX = sizeX; + SizeY = sizeY; PacketArchive = new IncomingPacketIDCollection(Settings.PACKET_ARCHIVE_SIZE); InBytes = new Queue(Client.Settings.STATS_QUEUE_SIZE); OutBytes = new Queue(Client.Settings.STATS_QUEUE_SIZE); if (client.Settings.STORE_LAND_PATCHES) { - Terrain = new TerrainPatch[16 * 16]; - WindSpeeds = new Vector2[16 * 16]; + Terrain = new TerrainPatch[sizeX/16 * sizeY/16]; + WindSpeeds = new Vector2[sizeX/16 * sizeY/16]; } } @@ -648,7 +656,7 @@ namespace OpenMetaverse /// /// Initiates connection to the simulator /// - /// Should we block until ack for this packet is recieved + /// Should we block until ack for this packet is received public void UseCircuitCode(bool waitForAck) { // Send the UseCircuitCode packet to initiate the connection @@ -690,17 +698,14 @@ namespace OpenMetaverse Caps = null; } - if (Client.Settings.ENABLE_CAPS) + // Connect to the CAPS system + if (seedcaps != null) { - // Connect to the new CAPS system - if (seedcaps != null) - { - Caps = new Caps(this, seedcaps); - } - else - { - Logger.Log("Setting up a sim without a valid capabilities server!", Helpers.LogLevel.Error, Client); - } + Caps = new Caps(this, seedcaps); + } + else + { + Logger.Log("Setting up a sim without valid http capabilities", Helpers.LogLevel.Error, Client); } } @@ -709,6 +714,8 @@ namespace OpenMetaverse /// public void Disconnect(bool sendCloseCircuit) { + DisconnectCandidate = false; + if (!connected) return; connected = false; @@ -795,7 +802,7 @@ namespace OpenMetaverse /// True if the lookup was successful, otherwise false public bool TerrainHeightAtPoint(int x, int y, out float height) { - if (Terrain != null && x >= 0 && x < 256 && y >= 0 && y < 256) + if (Terrain != null && x >= 0 && x < SizeX && y >= 0 && y < SizeY) { int patchX = x / 16; int patchY = y / 16; @@ -1002,7 +1009,7 @@ namespace OpenMetaverse /// /// Returns Simulator Name as a String /// - /// + /// Simulator name as String public override string ToString() { return !String.IsNullOrEmpty(Name) @@ -1059,8 +1066,8 @@ namespace OpenMetaverse // Check if this packet came from the server we expected it to come from if (!remoteEndPoint.Address.Equals(((IPEndPoint)buffer.RemoteEndPoint).Address)) { - Logger.Log("Received " + buffer.DataLength + " bytes of data from unrecognized source " + - ((IPEndPoint)buffer.RemoteEndPoint), Helpers.LogLevel.Warning, Client); + Logger.Log($"Received {buffer.DataLength} bytes of data from unrecognized source {(IPEndPoint)buffer.RemoteEndPoint}", + Helpers.LogLevel.Warning, Client); return; } @@ -1201,7 +1208,7 @@ namespace OpenMetaverse /// - /// Sends out pending acknowledgements + /// Sends out pending acknowledgments /// /// Number of ACKs sent private int SendAcks() diff --git a/LibreMetaverse/TerrainCompressor.cs b/LibreMetaverse/TerrainCompressor.cs index 43ffd4a..7677b76 100644 --- a/LibreMetaverse/TerrainCompressor.cs +++ b/LibreMetaverse/TerrainCompressor.cs @@ -61,16 +61,27 @@ namespace OpenMetaverse public int PatchIDs; public uint WordBits; + // true if PatchIDs are 32 bits and not 10 + public bool LargeRegion { get; set; } + public int X { - get { return PatchIDs >> 5; } - set { PatchIDs += (value << 5); } + get { return PatchIDs >> (LargeRegion ? 16 : 5); } + set { PatchIDs += (value << (LargeRegion ? 16 : 5)); } } public int Y { - get { return PatchIDs & 0x1F; } - set { PatchIDs |= value & 0x1F; } + get { return PatchIDs & (LargeRegion ? 0xffff : 0x1F); } + set { PatchIDs |= value & (LargeRegion ? 0xffff : 0x1F); } + } + + public int setPatchIDs(int xx, int yy) { + if (LargeRegion) + PatchIDs = (xx << 16) | (yy & 0xffff); + else + PatchIDs = (xx << 5) | (yy & 0x1f); + return PatchIDs; } } @@ -148,14 +159,18 @@ namespace OpenMetaverse /// simulator heightmap and an array of indices of patches to compress /// /// A 256 * 256 array of floating point values - /// specifying the height at each meter in the simulator + /// specifying the height at each meter in the simulator. + /// This can be larger if it is a varregion. /// Array of indexes in the 16x16 grid of patches /// for this simulator. For example if 1 and 17 are specified, patches /// x=1,y=0 and x=1,y=1 are sent /// public static LayerDataPacket CreateLandPacket(float[] heightmap, int[] patches) { - LayerDataPacket layer = new LayerDataPacket {LayerID = {Type = (byte) TerrainPatch.LayerType.Land}}; + var layerType = TerrainPatch.LayerType.Land; + if (heightmap.Length > Simulator.DefaultRegionSizeY * Simulator.DefaultRegionSizeY) + layerType = TerrainPatch.LayerType.LandExtended; + LayerDataPacket layer = new LayerDataPacket {LayerID = {Type = (byte) layerType}}; TerrainPatch.GroupHeader header = new TerrainPatch.GroupHeader { @@ -235,15 +250,19 @@ namespace OpenMetaverse return layer; } - public static void CreatePatch(BitPack output, float[] patchData, int x, int y) + private static void CreatePatch(BitPack output, float[] patchData, int x, int y) + { + CreatePatch(output, patchData, x, y, false); + } + private static void CreatePatch(BitPack output, float[] patchData, int x, int y, bool largeRegion) { if (patchData.Length != 16 * 16) throw new ArgumentException("Patch data must be a 16x16 array"); TerrainPatch.Header header = PrescanPatch(patchData); + header.LargeRegion = largeRegion; header.QuantWBits = 136; - header.PatchIDs = (y & 0x1F); - header.PatchIDs += (x << 5); + header.setPatchIDs(x, y); // NOTE: No idea what prequant and postquant should be or what they do int[] patch = CompressPatch(patchData, header, 10); @@ -252,14 +271,18 @@ namespace OpenMetaverse } public static void CreatePatch(BitPack output, float[,] patchData, int x, int y) + { + CreatePatch(output, patchData, x, y, false); + } + public static void CreatePatch(BitPack output, float[,] patchData, int x, int y, bool largeRegion) { if (patchData.Length != 16 * 16) throw new ArgumentException("Patch data must be a 16x16 array"); var header = PrescanPatch(patchData); + header.LargeRegion = largeRegion; header.QuantWBits = 136; - header.PatchIDs = (y & 0x1F); - header.PatchIDs += (x << 5); + header.setPatchIDs(x, y); // NOTE: No idea what prequant and postquant should be or what they do int[] patch = CompressPatch(patchData, header, 10); @@ -278,6 +301,10 @@ namespace OpenMetaverse /// Y offset of the patch to create, valid values are /// from 0 to 15 public static void CreatePatchFromHeightmap(BitPack output, float[] heightmap, int x, int y) + { + CreatePatchFromHeightmap(output, heightmap, x, y, false); + } + public static void CreatePatchFromHeightmap(BitPack output, float[] heightmap, int x, int y, bool largeRegion) { if (heightmap.Length != 256 * 256) throw new ArgumentException("Heightmap data must be 256x256"); @@ -286,9 +313,9 @@ namespace OpenMetaverse throw new ArgumentException("X and Y patch offsets must be from 0 to 15"); var header = PrescanPatch(heightmap, x, y); + header.LargeRegion = largeRegion; header.QuantWBits = 136; - header.PatchIDs = (y & 0x1F); - header.PatchIDs += (x << 5); + header.setPatchIDs(x, y); // NOTE: No idea what prequant and postquant should be or what they do int[] patch = CompressPatch(heightmap, x, y, header, 10); @@ -296,6 +323,8 @@ namespace OpenMetaverse EncodePatch(output, patch, 0, wbits); } + // Scan the height map to get the range of values so the values can be compressed. + // Returns a TerrainPatch.Header with the range information filled in. private static TerrainPatch.Header PrescanPatch(float[] patch) { TerrainPatch.Header header = new TerrainPatch.Header(); @@ -318,6 +347,8 @@ namespace OpenMetaverse return header; } + // Scan the height map to get the range of values so the values can be compressed. + // Returns a TerrainPatch.Header with the range information filled in. private static TerrainPatch.Header PrescanPatch(float[,] patch) { TerrainPatch.Header header = new TerrainPatch.Header(); @@ -340,6 +371,8 @@ namespace OpenMetaverse return header; } + // Scan the height map to get the range of values so the values can be compressed. + // Returns a TerrainPatch.Header with the range information filled in. private static TerrainPatch.Header PrescanPatch(float[] heightmap, int patchX, int patchY) { TerrainPatch.Header header = new TerrainPatch.Header(); @@ -363,6 +396,11 @@ namespace OpenMetaverse } public static TerrainPatch.Header DecodePatchHeader(BitPack bitpack) + { + return DecodePatchHeader(bitpack, false); + + } + public static TerrainPatch.Header DecodePatchHeader(BitPack bitpack, bool largeRegion) { TerrainPatch.Header header = new TerrainPatch.Header {QuantWBits = bitpack.UnpackBits(8)}; @@ -377,7 +415,9 @@ namespace OpenMetaverse header.Range = bitpack.UnpackBits(16); // Patch IDs (10 bits) - header.PatchIDs = bitpack.UnpackBits(10); + + header.LargeRegion = largeRegion; + header.PatchIDs = bitpack.UnpackBits(largeRegion ? 32 : 10); // Word bits header.WordBits = (uint)((header.QuantWBits & 0x0f) + 2); @@ -428,7 +468,7 @@ namespace OpenMetaverse output.PackBits(header.QuantWBits, 8); output.PackFloat(header.DCOffset); output.PackBits(header.Range, 16); - output.PackBits(header.PatchIDs, 10); + output.PackBits(header.PatchIDs, header.LargeRegion ? 32 : 10); // the IDs are larger for large regions return wbits; } diff --git a/LibreMetaverse/TerrainManager.cs b/LibreMetaverse/TerrainManager.cs index 8a112e9..71183ea 100644 --- a/LibreMetaverse/TerrainManager.cs +++ b/LibreMetaverse/TerrainManager.cs @@ -67,7 +67,7 @@ namespace OpenMetaverse Client.Network.RegisterCallback(PacketType.LayerData, LayerDataHandler); } - private void DecompressLand(Simulator simulator, BitPack bitpack, TerrainPatch.GroupHeader group) + private void DecompressLand(Simulator simulator, BitPack bitpack, TerrainPatch.GroupHeader group, bool largeRegion = false) { int x; int y; @@ -76,7 +76,7 @@ namespace OpenMetaverse while (true) { - TerrainPatch.Header header = TerrainCompressor.DecodePatchHeader(bitpack); + TerrainPatch.Header header = TerrainCompressor.DecodePatchHeader(bitpack, largeRegion); if (header.QuantWBits == TerrainCompressor.END_OF_PATCHES) break; @@ -84,7 +84,7 @@ namespace OpenMetaverse x = header.X; y = header.Y; - if (x >= TerrainCompressor.PATCHES_PER_EDGE || y >= TerrainCompressor.PATCHES_PER_EDGE) + if (!largeRegion && (x >= TerrainCompressor.PATCHES_PER_EDGE || y >= TerrainCompressor.PATCHES_PER_EDGE)) { Logger.Log(String.Format( "Invalid LayerData land packet, x={0}, y={1}, dc_offset={2}, range={3}, quant_wbits={4}, patchids={5}, count={6}", @@ -117,7 +117,7 @@ namespace OpenMetaverse } } - private void DecompressWind(Simulator simulator, BitPack bitpack, TerrainPatch.GroupHeader group) + private void DecompressWind(Simulator simulator, BitPack bitpack, TerrainPatch.GroupHeader group, bool largeRegion = false) { int[] patches = new int[32 * 32]; @@ -131,12 +131,12 @@ namespace OpenMetaverse // wind_direction = vec2(x,y) // X values - TerrainPatch.Header header = TerrainCompressor.DecodePatchHeader(bitpack); + TerrainPatch.Header header = TerrainCompressor.DecodePatchHeader(bitpack, largeRegion); TerrainCompressor.DecodePatch(patches, bitpack, header, group.PatchSize); float[] xvalues = TerrainCompressor.DecompressPatch(patches, header, group); // Y values - header = TerrainCompressor.DecodePatchHeader(bitpack); + header = TerrainCompressor.DecodePatchHeader(bitpack, largeRegion); TerrainCompressor.DecodePatch(patches, bitpack, header, group.PatchSize); float[] yvalues = TerrainCompressor.DecompressPatch(patches, header, group); @@ -172,6 +172,10 @@ namespace OpenMetaverse if (m_LandPatchReceivedEvent != null || Client.Settings.STORE_LAND_PATCHES) DecompressLand(e.Simulator, bitpack, header); break; + case TerrainPatch.LayerType.LandExtended: + if (m_LandPatchReceivedEvent != null || Client.Settings.STORE_LAND_PATCHES) + DecompressLand(e.Simulator, bitpack, header, true); + break; case TerrainPatch.LayerType.Water: Logger.Log("Got a Water LayerData packet, implement me!", Helpers.LogLevel.Error, Client); break; diff --git a/LibreMetaverse/UDPBase.cs b/LibreMetaverse/UDPBase.cs index cda79fc..212749c 100644 --- a/LibreMetaverse/UDPBase.cs +++ b/LibreMetaverse/UDPBase.cs @@ -119,7 +119,7 @@ namespace OpenMetaverse // kick off an async receive. The Start() method will return, the // actual receives will occur asynchronously and will be caught in - // AsyncEndRecieve(). + // AsyncEndReceive(). AsyncBeginReceive(); } diff --git a/LibreMetaverse/_Packets_.cs b/LibreMetaverse/_Packets_.cs index 096c5f3..4c90716 100644 --- a/LibreMetaverse/_Packets_.cs +++ b/LibreMetaverse/_Packets_.cs @@ -10023,6 +10023,9 @@ namespace OpenMetaverse.Packets public byte[] SeedCapability; public byte SimAccess; public uint TeleportFlags; + // Sim/region size information sent in TeleportFinishMesssage + public uint RegionSizeX = Simulator.DefaultRegionSizeX; + public uint RegionSizeY = Simulator.DefaultRegionSizeY; public override int Length { @@ -10075,6 +10078,7 @@ namespace OpenMetaverse.Packets Buffer.BlockCopy(SeedCapability, 0, bytes, i, SeedCapability.Length); i += SeedCapability.Length; bytes[i++] = SimAccess; Utils.UIntToBytes(TeleportFlags, bytes, i); i += 4; + // size information is not sent in the UDP packet } } diff --git a/SecondBotEvents/Commands/Group.cs b/SecondBotEvents/Commands/Group.cs index 1ca61d3..3e456de 100644 --- a/SecondBotEvents/Commands/Group.cs +++ b/SecondBotEvents/Commands/Group.cs @@ -66,7 +66,7 @@ namespace SecondBotEvents.Commands return Failure("Unknown group", new[] { group, avatar, state }); } ProcessAvatar(avatar); - if(avataruuid == null) + if(avataruuid == UUID.Zero) { return Failure("Unknown avatar", new[] { group, avatar, state }); } @@ -75,8 +75,10 @@ namespace SecondBotEvents.Commands { Action = GroupBanAction.Unban; } - List avatarstoaction = new List(); - avatarstoaction.Add(avataruuid); + List avatarstoaction = new() + { + avataruuid + }; GetClient().Groups.RequestBanAction(groupuuid, Action, avatarstoaction.ToArray()); return BasicReply("Accepted"); } @@ -104,7 +106,7 @@ namespace SecondBotEvents.Commands return Failure("Unknown group", new[] { group, avatar }); } ProcessAvatar(avatar); - if (avataruuid == null) + if (avataruuid == UUID.Zero) { return Failure("Unknown avatar", new[] { group, avatar}); } @@ -172,12 +174,13 @@ namespace SecondBotEvents.Commands { return Failure("avatar lookup", new [] { group, avatar, role }); } - List roles = new List(); - roles.Add(UUID.Zero); - if(role != "everyone") + List roles = new() { - UUID roleuuid = UUID.Zero; - if (UUID.TryParse(role, out roleuuid) == false) + UUID.Zero + }; + if (role != "everyone") + { + if (UUID.TryParse(role, out UUID roleuuid) == false) { return Failure("Unable to process role UUID", new[] { group, avatar, role }); } @@ -215,10 +218,12 @@ namespace SecondBotEvents.Commands { return Failure("Message empty", new [] { group, title, message }); } - GroupNotice NewNotice = new GroupNotice(); - NewNotice.Subject = title; - NewNotice.Message = message; - NewNotice.OwnerID = GetClient().Self.AgentID; + GroupNotice NewNotice = new() + { + Subject = title, + Message = message, + OwnerID = GetClient().Self.AgentID + }; GetClient().Groups.SendGroupNotice(groupuuid, NewNotice); return BasicReply("Sending notice", new [] { group, title, message }); } @@ -301,11 +306,13 @@ namespace SecondBotEvents.Commands { return Failure("Message empty", new [] { group, title, message, attachment }); } - GroupNotice NewNotice = new GroupNotice(); - NewNotice.Subject = title; - NewNotice.Message = message; - NewNotice.OwnerID = GetClient().Self.AgentID; - NewNotice.AttachmentID = inventoryuuid; + GroupNotice NewNotice = new() + { + Subject = title, + Message = message, + OwnerID = GetClient().Self.AgentID, + AttachmentID = inventoryuuid + }; GetClient().Groups.SendGroupNotice(groupuuid, NewNotice); return BasicReply("Sending notice with attachment", new [] { group, title, message, attachment }); } @@ -351,8 +358,7 @@ namespace SecondBotEvents.Commands [ArgHints("group", "the UUID of the group")] public object GroupchatGroupHasUnread(string group) { - UUID groupUUID = UUID.Zero; - if(UUID.TryParse(group,out groupUUID) == false) + if(UUID.TryParse(group,out UUID groupUUID) == false) { return Failure("group value is invaild", new [] { group }); } @@ -400,8 +406,7 @@ namespace SecondBotEvents.Commands [ReturnHintsFailure("Unknown group")] public object Groupchat(string group, string message) { - UUID groupUUID = UUID.Zero; - if (UUID.TryParse(group, out groupUUID) == false) + if (UUID.TryParse(group, out UUID groupUUID) == false) { return Failure("group value is invaild", new [] { group, message }); } diff --git a/SecondBotEvents/Commands/Inventory.cs b/SecondBotEvents/Commands/Inventory.cs index f571e09..5caab79 100644 --- a/SecondBotEvents/Commands/Inventory.cs +++ b/SecondBotEvents/Commands/Inventory.cs @@ -44,8 +44,10 @@ namespace SecondBotEvents.Commands break; } } - AssetSound S = new AssetSound(); - S.AssetData = audioData; + AssetSound S = new() + { + AssetData = audioData + }; S.Encode(); GetClient().Inventory.RequestCreateItemFromAsset(S.AssetData, inventoryName, "", AssetType.Sound, InventoryType.Sound, AA.UUID, null); @@ -204,7 +206,7 @@ namespace SecondBotEvents.Commands return Failure("Cant find target folder", new [] { name }); } List contents = GetClient().Inventory.FolderContents(AA.UUID, GetClient().Self.AgentID, true, true, InventorySortOrder.ByName, 5 * 1000); - List wareables = new List(); + List wareables = new(); if (contents == null) { return Failure("target folder is empty or so full I cant get it in 5 secs...", new [] { name }); @@ -241,7 +243,7 @@ namespace SecondBotEvents.Commands { return Failure("Unable to find notecard folder"); } - List purge_notecards = new List(); + List purge_notecards = new(); List contents = GetClient().Inventory.FolderContents(NotecardFolder.UUID, GetClient().Self.AgentID, true, true, InventorySortOrder.ByDate, 40 * 1000); foreach (InventoryBase C in contents) { @@ -255,7 +257,7 @@ namespace SecondBotEvents.Commands } } } - if (purge_notecards.Count() > 0) + if (purge_notecards.Count > 0) { GetClient().Inventory.Remove(purge_notecards, new List()); } @@ -266,7 +268,7 @@ namespace SecondBotEvents.Commands [ReturnHints("Asset UUID or UUID zero")] [ReturnHints("Invaild item uuid")] [ArgHints("item", "inventory level UUID of item")] - public object getRealUUID(string item) + public object GetRealUUID(string item) { if (UUID.TryParse(item, out UUID itemUUID) == false) { @@ -364,7 +366,7 @@ namespace SecondBotEvents.Commands return Failure("Unable to find inventory", new [] { item, objectuuid, running }); } Dictionary objects_copy = GetClient().Network.CurrentSim.ObjectsPrimitives.Copy(); - KeyValuePair RealObject = new KeyValuePair(0,null); + KeyValuePair RealObject = new(0, null); foreach (KeyValuePair Obj in objects_copy) { if (Obj.Value.ID == objectUUID) @@ -431,7 +433,7 @@ namespace SecondBotEvents.Commands [ReturnHintsFailure("new folder name is too short, must be longer than 3 characters.")] [ArgHints("parentFolder", "UUID of folder to create a subfolder in")] [ArgHints("folderName", "name of the new folder")] - public object CreateInventoryFolder(string parentFolder, string folderName, string token) + public object CreateInventoryFolder(string parentFolder, string folderName) { if (UUID.TryParse(parentFolder, out UUID parentFolderUUID) == false) { diff --git a/SecondBotEvents/Commands/ParcelCommands.cs b/SecondBotEvents/Commands/ParcelCommands.cs index 84f76fa..ab43b86 100644 --- a/SecondBotEvents/Commands/ParcelCommands.cs +++ b/SecondBotEvents/Commands/ParcelCommands.cs @@ -49,8 +49,8 @@ namespace SecondBotEvents.Commands } targetparcel.SalePrice = amountvalue; targetparcel.AuthBuyerID = avataruuid; - parcel_static.ParcelSetFlag(ParcelFlags.ForSale, targetparcel, true); - parcel_static.ParcelSetFlag(ParcelFlags.ForSaleObjects, targetparcel, false); + ParcelStatic.ParcelSetFlag(ParcelFlags.ForSale, targetparcel, true); + ParcelStatic.ParcelSetFlag(ParcelFlags.ForSaleObjects, targetparcel, false); targetparcel.Update(GetClient()); return Failure("ok", new [] { amount, avatar }); } @@ -167,8 +167,8 @@ namespace SecondBotEvents.Commands { return Failure(tests.Value); } - Dictionary flags = parcel_static.get_flags_list(); - Dictionary collection = new Dictionary(); + Dictionary flags = ParcelStatic.GetFlagsList(); + Dictionary collection = new(); foreach (ParcelFlags cfg in flags.Values) { collection.Add(cfg.ToString(), targetparcel.Flags.HasFlag(cfg).ToString()); @@ -237,10 +237,12 @@ namespace SecondBotEvents.Commands { return BasicReply("Avatar is in the blacklist", new [] { avatar }); } - ParcelAccessEntry entry = new ParcelAccessEntry(); - entry.AgentID = avataruuid; - entry.Flags = AccessList.Ban; - entry.Time = new System.DateTime(3030, 03, 03); + ParcelAccessEntry entry = new() + { + AgentID = avataruuid, + Flags = AccessList.Ban, + Time = new System.DateTime(3030, 03, 03) + }; targetparcel.AccessBlackList.Add(entry); targetparcel.Update(GetClient()); return BasicReply("ok", new [] { avatar }); @@ -266,7 +268,7 @@ namespace SecondBotEvents.Commands return Failure("Invaild avatar", new [] { avatar }); } bool alreadyBanned = false; - ParcelAccessEntry removeentry = new ParcelAccessEntry(); + ParcelAccessEntry removeentry = new(); foreach (ParcelAccessEntry E in targetparcel.AccessBlackList) { if (E.AgentID == avataruuid) @@ -298,7 +300,7 @@ namespace SecondBotEvents.Commands { return Failure(tests.Value, new [] { musicurl }); } - bool status = parcel_static.set_parcel_music(GetClient(), targetparcel, musicurl); + bool status = ParcelStatic.SetParcelMusic(GetClient(), targetparcel, musicurl); return BasicReply(status.ToString(), new [] { musicurl }); } @@ -319,11 +321,11 @@ namespace SecondBotEvents.Commands { return Failure(tests.Value, new [] { escapedflagdata }); } - List acceptablewords = new List(); - Dictionary flags = parcel_static.get_flags_list(); + List acceptablewords = new(); + Dictionary flags = ParcelStatic.GetFlagsList(); acceptablewords.AddRange(new[] { "True", "False" }); - Dictionary setflags = new Dictionary(); + Dictionary setflags = new(); string[] args = escapedflagdata.Split(":::"); foreach (string a in args) { @@ -348,7 +350,7 @@ namespace SecondBotEvents.Commands { return Failure("No accepted flags", new [] { escapedflagdata }); } - if (parcel_static.has_parcel_perm(targetparcel, GetClient()) == false) + if (ParcelStatic.HasParcelPerm(targetparcel, GetClient()) == false) { return Failure("Incorrect perms to control parcel", new [] { escapedflagdata }); } @@ -356,7 +358,7 @@ namespace SecondBotEvents.Commands { if (flags.ContainsKey(cfg.Key) == true) { - parcel_static.ParcelSetFlag(flags[cfg.Key], targetparcel, cfg.Value); + ParcelStatic.ParcelSetFlag(flags[cfg.Key], targetparcel, cfg.Value); } } targetparcel.Update(GetClient()); @@ -494,7 +496,7 @@ namespace SecondBotEvents.Commands { return Failure(tests.Value); } - GetParcelBanlistObject reply = new GetParcelBanlistObject(); + GetParcelBanlistObject reply = new(); int delays = 0; bool haslookup = true; while ((haslookup == true) && (delays < 3)) @@ -582,7 +584,7 @@ namespace SecondBotEvents.Commands { if (bits[0] == "MediaType") { - UpdateParcel_MediaType(targetparcel, bits[1]); + UpdateParcelMediaType(targetparcel, bits[1]); } else if ((bits[0] == "MediaWidth") || (bits[0] == "MediaHeight")) { @@ -636,7 +638,7 @@ namespace SecondBotEvents.Commands return BasicReply("ok", new [] { escapedflagdata }); } - protected bool UpdateParcel_MediaType(Parcel targetparcel, string value) + protected static bool UpdateParcelMediaType(Parcel targetparcel, string value) { if (value == "IMG-PNG") { @@ -670,7 +672,7 @@ namespace SecondBotEvents.Commands public class GetParcelBanlistObject { - public Dictionary entrys = new Dictionary(); + public Dictionary entrys = new(); public string parcelName = ""; public string regionName = ""; public int delay = 0; diff --git a/SecondBotEvents/SecondBotEvents.csproj b/SecondBotEvents/SecondBotEvents.csproj index 2033c41..13fb8d0 100644 --- a/SecondBotEvents/SecondBotEvents.csproj +++ b/SecondBotEvents/SecondBotEvents.csproj @@ -1,28 +1,25 @@ - - + Exe - net6.0 + net7.0 SecondBotEvents.Startup - git rev-parse --short HEAD - False - False + git rev-parse --short HEAD + False + False - - - - + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + - - - + \ No newline at end of file diff --git a/SecondBotEvents/Services/BotClientService.cs b/SecondBotEvents/Services/BotClientService.cs index f8b4b2d..93a7f6e 100644 --- a/SecondBotEvents/Services/BotClientService.cs +++ b/SecondBotEvents/Services/BotClientService.cs @@ -1,6 +1,7 @@ using OpenMetaverse; using OpenMetaverse.Assets; using SecondBotEvents.Config; +using Swan; using System; using System.Collections.Generic; using System.Text; @@ -200,7 +201,9 @@ namespace SecondBotEvents.Services { return "No sim"; } - return client.Network.CurrentSim.Name + " " + client.Self.SimPosition.ToString(); + Vector3 pos = client.Self.SimPosition; + string loc = "" + Math.Round(pos.X).ToString() + "," + Math.Round(pos.Y).ToString() + "," + Math.Round(pos.Z).ToString(); + return client.Network.CurrentSim.Name + " " + loc; } } } diff --git a/SecondBotEvents/Services/DataStoreService.cs b/SecondBotEvents/Services/DataStoreService.cs index 739123b..5b659c1 100644 --- a/SecondBotEvents/Services/DataStoreService.cs +++ b/SecondBotEvents/Services/DataStoreService.cs @@ -18,25 +18,25 @@ namespace SecondBotEvents.Services myConfig = new DataStoreConfig(master.fromEnv,master.fromFolder); } - protected Dictionary avatarsName2Key = new Dictionary(); - protected Dictionary avatarLastUsed = new Dictionary(); + protected Dictionary avatarsName2Key = new(); + protected Dictionary avatarLastUsed = new(); - protected Dictionary groupsKey2Name = new Dictionary(); + protected Dictionary groupsKey2Name = new(); - protected Dictionary> groupMembers = new Dictionary>(); - protected Dictionary> groupRoles = new Dictionary>(); + protected Dictionary> groupMembers = new(); + protected Dictionary> groupRoles = new(); - protected List localChatHistory = new List(); + protected List localChatHistory = new(); - protected Dictionary> chatWindows = new Dictionary>(); // sess, list chat - protected Dictionary chatWindowsUnread = new Dictionary(); // sess, bool - protected Dictionary chatWindowsIsGroup = new Dictionary(); // sess, bool - protected Dictionary chatWindowsOwner = new Dictionary(); // sess, owner id + protected Dictionary> chatWindows = new(); // sess, list chat + protected Dictionary chatWindowsUnread = new(); // sess, bool + protected Dictionary chatWindowsIsGroup = new(); // sess, bool + protected Dictionary chatWindowsOwner = new(); // sess, owner id - protected Dictionary KeyValueStore = new Dictionary(); - protected Dictionary KeyValueStoreLastUsed = new Dictionary(); + protected Dictionary KeyValueStore = new(); + protected Dictionary KeyValueStoreLastUsed = new(); - protected List commandHistories = new List(); + protected List commandHistories = new(); protected long lastCleanupKeyValueStore = 0; protected long lastCleanupAvatarStore = 0; @@ -53,7 +53,7 @@ namespace SecondBotEvents.Services return groupsKey2Name[group]; } string reply = "lookup"; - AutoResetEvent fetchEvent = new AutoResetEvent(false); + AutoResetEvent fetchEvent = new(false); void callback(object sender, CurrentGroupsEventArgs e) { foreach(KeyValuePair entry in e.Groups) @@ -91,7 +91,7 @@ namespace SecondBotEvents.Services if (dif > 125) { lastCleanupKeyValueStore = unixtime; - List clearentrys = new List(); + List clearentrys = new(); foreach (KeyValuePair entry in KeyValueStoreLastUsed) { dif = unixtime - entry.Value; @@ -121,7 +121,7 @@ namespace SecondBotEvents.Services if (dif > 75) { lastCleanupAvatarStore = unixtime; - Dictionary clearLinks = new Dictionary(); + Dictionary clearLinks = new(); foreach (KeyValuePair entry in avatarsName2Key) { dif = unixtime - avatarLastUsed[entry.Value]; @@ -141,10 +141,10 @@ namespace SecondBotEvents.Services } } } - int sum = commandHistories.Count() + KeyValueStoreLastUsed.Count() + KeyValueStore.Count() + - chatWindowsOwner.Count() + chatWindowsIsGroup.Count() + chatWindowsUnread.Count() + - chatWindows.Count() + localChatHistory.Count() + groupRoles.Count() + - groupMembers.Count() + groupsKey2Name.Count() + avatarsName2Key.Count(); + int sum = commandHistories.Count + KeyValueStoreLastUsed.Count + KeyValueStore.Count + + chatWindowsOwner.Count + chatWindowsIsGroup.Count + chatWindowsUnread.Count + + chatWindows.Count + localChatHistory.Count + groupRoles.Count + + groupMembers.Count + groupsKey2Name.Count + avatarsName2Key.Count; return sum.ToString(); } @@ -152,7 +152,7 @@ namespace SecondBotEvents.Services { lock (commandHistories) { - CommandHistory A = new CommandHistory(status, command, args, SecondbotHelpers.UnixTimeNow()); + CommandHistory A = new(status, command, args, SecondbotHelpers.UnixTimeNow()); commandHistories.Add(A); int c = commandHistories.Count; while (c > myConfig.GetCommandHistoryLimit()) @@ -226,7 +226,7 @@ namespace SecondBotEvents.Services public List GetAllGroupsChatWithUnread() { - List reply = new List(); + List reply = new(); foreach(KeyValuePair windowState in chatWindowsUnread) { if(windowState.Value == false) @@ -299,11 +299,11 @@ namespace SecondBotEvents.Services public Dictionary GetGroupRoles(UUID group) { - Dictionary reply = new Dictionary(); + Dictionary reply = new(); if (groupRoles.ContainsKey(group) == false) { - AutoResetEvent fetchEvent = new AutoResetEvent(false); + AutoResetEvent fetchEvent = new(false); void callback(object sender, GroupRolesDataReplyEventArgs e) { if (e.GroupID == group) @@ -341,7 +341,7 @@ namespace SecondBotEvents.Services if (groupMembers[group].Contains(avatar) == false) { reply = false; - AutoResetEvent fetchEvent = new AutoResetEvent(false); + AutoResetEvent fetchEvent = new(false); void callback(object sender, GroupMembersReplyEventArgs e) { if (e.GroupID == group) @@ -395,7 +395,7 @@ namespace SecondBotEvents.Services { purgeLen = myConfig.GetGroupChatHistoryLimitPerGroup(); } - int counter = chatWindows[sessionID].Count(); + int counter = chatWindows[sessionID].Count; while (counter > purgeLen) { chatWindows[sessionID].RemoveAt(0); @@ -471,7 +471,7 @@ namespace SecondBotEvents.Services } - protected Dictionary> notecardDataStore = new Dictionary>(); + protected Dictionary> notecardDataStore = new(); public List GetLocalChat() { @@ -532,7 +532,7 @@ namespace SecondBotEvents.Services if(avatarsName2Key.ContainsValue(avatarId) == false) { bool hasReply = false; - AutoResetEvent fetchEvent = new AutoResetEvent(false); + AutoResetEvent fetchEvent = new(false); void callback(object sender, UUIDNameReplyEventArgs e) { foreach (KeyValuePair av in e.Names) @@ -563,7 +563,7 @@ namespace SecondBotEvents.Services UUID wantedReplyID = UUID.SecureRandom(); bool hasReply = false; - AutoResetEvent fetchEvent = new AutoResetEvent(false); + AutoResetEvent fetchEvent = new(false); void callback(object sender, AvatarPickerReplyEventArgs e) { if (e.QueryID == wantedReplyID) @@ -590,7 +590,7 @@ namespace SecondBotEvents.Services public void GetAvatarNames(List avatars) { - List lookup = new List(); + List lookup = new(); foreach (UUID id in avatars) { if (avatarsName2Key.ContainsValue(id) == false) @@ -664,7 +664,7 @@ namespace SecondBotEvents.Services public Dictionary GetAvatarImWindows() { - Dictionary windows = new Dictionary(); + Dictionary windows = new(); foreach (KeyValuePair links in chatWindowsIsGroup) { if(links.Value == true) @@ -728,7 +728,7 @@ namespace SecondBotEvents.Services public List GetAvatarImWindowsUnread() { - List windows = new List(); + List windows = new(); foreach (KeyValuePair links in chatWindowsIsGroup) { if (links.Value == true) @@ -834,8 +834,8 @@ namespace SecondBotEvents.Services { if (estateBanlist == null) { - List reply = new List(); - AutoResetEvent fetchEvent = new AutoResetEvent(false); + List reply = new(); + AutoResetEvent fetchEvent = new(false); void callback(object sender, EstateBansReplyEventArgs e) { reply = e.Banned; @@ -1077,7 +1077,7 @@ namespace SecondBotEvents.Services public class CommandHistory { public string Command = ""; - public string[] Args = new string[] { }; + public string[] Args = Array.Empty(); public long Unixtime = 0; public bool status = false; diff --git a/SecondBotEvents/Services/HomeboundService.cs b/SecondBotEvents/Services/HomeboundService.cs index 218695d..0702de8 100644 --- a/SecondBotEvents/Services/HomeboundService.cs +++ b/SecondBotEvents/Services/HomeboundService.cs @@ -46,11 +46,11 @@ namespace SecondBotEvents.Services protected bool attemptedTeleportBackup = false; protected long teleportActionLockout = 0; - public void GoHome() + public bool GoHome() { attemptedTeleportHome = true; LogFormater.Info("Teleporting to home sim"); - GetClient().Self.Teleport(home.name, new Vector3(home.x, home.y, home.z), new Vector3(0, 0, 0)); + return GetClient().Self.Teleport(home.name, new Vector3(home.x, home.y, home.z), new Vector3(0, 0, 0)); } protected void Tick() { @@ -85,8 +85,14 @@ namespace SecondBotEvents.Services } if (simNickname == "") { - simNickname = "Someplace # "; - return; + if (GetClient().Network.CurrentSim != null) + { + simNickname = ""+ GetClient().Network.CurrentSim.Name+" # "; + } + else + { + simNickname = "Someplace # "; + } } long dif = SecondbotHelpers.UnixTimeNow() - teleportActionLockout; if(dif < 30) @@ -96,7 +102,10 @@ namespace SecondBotEvents.Services teleportActionLockout = SecondbotHelpers.UnixTimeNow(); if (attemptedTeleportHome == false) { - GoHome(); + if(GoHome() == false) + { + LogFormater.Warn("Unable to teleport to home sim"); + } return; } else if(attemptedTeleportBackup == false) @@ -104,7 +113,10 @@ namespace SecondBotEvents.Services attemptedTeleportBackup = true; LogFormater.Info("Teleporting to backup sim"); teleportActionLockout = SecondbotHelpers.UnixTimeNow(); - GetClient().Self.Teleport(backup.name, new Vector3(backup.x, backup.y, backup.z), new Vector3(0, 0, 0)); + if(GetClient().Self.Teleport(backup.name, new Vector3(backup.x, backup.y, backup.z), new Vector3(0, 0, 0)) == false) + { + LogFormater.Warn("Unable to teleport to backup sim"); + } return; } attemptedTeleportHome = false; diff --git a/SecondBotEvents/Services/HttpService.cs b/SecondBotEvents/Services/HttpService.cs index aa9ce6d..6b8f35f 100644 --- a/SecondBotEvents/Services/HttpService.cs +++ b/SecondBotEvents/Services/HttpService.cs @@ -161,13 +161,16 @@ namespace SecondBotEvents.Services string UUIDfetch = master.DataStoreService.GetAvatarUUID(avatar); if (UUIDfetch != "lookup") { - UUID.TryParse(UUIDfetch, out avataruuid); + if(UUID.TryParse(UUIDfetch, out avataruuid) == false) + { + avataruuid = UUID.Zero; + } } } protected object BasicReply(string input) { - return BasicReply(input, new string[] { }, GetCallingCommand()); + return BasicReply(input, Array.Empty(), GetCallingCommand()); } protected object BasicReply(string input, string[] args) @@ -178,13 +181,13 @@ namespace SecondBotEvents.Services protected object BasicReply(string input, string[] args, string command) { master.DataStoreService.AddCommandToHistory(true, command, args); - return new { command = command, args = args, reply = input, status = true }; + return new { command, args, reply = input, status = true }; } protected object Failure(string input, string command, string[] args, string whyfailed) { master.DataStoreService.AddCommandToHistory(false, command, args); - return new { command = command, args = args, reply = input, status = false, whyfailed = whyfailed }; + return new { command, args, reply = input, status = false, whyfailed }; } protected object Failure(string input, string[] args) @@ -194,10 +197,10 @@ namespace SecondBotEvents.Services protected object Failure(string input) { - return Failure(input, GetCallingCommand(), new string[] { }, null); + return Failure(input, GetCallingCommand(), Array.Empty(), null); } - protected string GetCallingCommand() + protected static string GetCallingCommand() { return (new System.Diagnostics.StackTrace()).GetFrame(2).GetMethod().Name; } @@ -272,7 +275,7 @@ namespace SecondBotEvents.Services public string Run([FormField] string commandName, [FormField] string args, [FormField] string signing, [FormField] string unixtime) { - string[] myArgs = new string[] { }; + string[] myArgs = Array.Empty(); if(args != null) { myArgs = args.Split("~#~", StringSplitOptions.RemoveEmptyEntries); @@ -285,7 +288,7 @@ namespace SecondBotEvents.Services { return "No bot connected yet"; } - SignedCommand C = new SignedCommand(commandName, signing, myArgs, cmdUnixtime, null, true, 5, master.CommandsService.myConfig.GetSharedSecret()); + SignedCommand C = new(commandName, signing, myArgs, cmdUnixtime, null, true, 5, master.CommandsService.myConfig.GetSharedSecret()); if(C.accepted == false) { return "Command request rejected"; diff --git a/SecondBotEvents/Services/RelayService.cs b/SecondBotEvents/Services/RelayService.cs index f46a856..0cfa83e 100644 --- a/SecondBotEvents/Services/RelayService.cs +++ b/SecondBotEvents/Services/RelayService.cs @@ -13,7 +13,7 @@ namespace SecondBotEvents.Services { protected RelayConfig myConfig; protected bool botConnected = false; - protected List Relays = new List(); + protected List Relays = new(); public RelayService(EventsSecondBot setMaster) : base(setMaster) { myConfig = new RelayConfig(master.fromEnv, master.fromFolder); @@ -348,7 +348,7 @@ namespace SecondBotEvents.Services readonly string[] vaildToOptions = new[] { "avatar", "group", "localchat", "discord", "http" }; readonly - protected HttpClient HTTPclient = new HttpClient(); + protected HttpClient HTTPclient = new(); public void TriggerWith(string sourceType, string message, string filterOption1, string filterOption2=null, string filterOption3 = null) { // avatarim, {message}, avatarUUID @@ -414,7 +414,7 @@ namespace SecondBotEvents.Services case "http": { long unixtime = SecondbotHelpers.UnixTimeNow(); - Dictionary values = new Dictionary + Dictionary values = new() { { "fromType", fromType }, { "fromOption", fromOption }, diff --git a/SecondBotEvents/Static/parcel.cs b/SecondBotEvents/Static/parcel.cs index 94bed34..c4649a5 100644 --- a/SecondBotEvents/Static/parcel.cs +++ b/SecondBotEvents/Static/parcel.cs @@ -5,9 +5,9 @@ using System.Text; namespace SecondBotEvents { - public static class parcel_static + public static class ParcelStatic { - public static bool set_parcel_music(GridClient bot, Parcel p, string url) + public static bool SetParcelMusic(GridClient bot, Parcel p, string url) { if (p.MusicURL != url) { @@ -27,7 +27,7 @@ namespace SecondBotEvents p.Flags |= F; } } - public static bool has_parcel_perm(Parcel P, GridClient bot) + public static bool HasParcelPerm(Parcel P, GridClient bot) { bool has_perm = true; if (P.OwnerID != bot.Self.AgentID) @@ -54,30 +54,32 @@ namespace SecondBotEvents return has_perm; } - public static string[] get_flag_names() + public static string[] GetFlagNames() { System.Type enumType = typeof(ParcelFlags); - List flagnames = new List(System.Enum.GetNames(enumType)); + List flagnames = new(System.Enum.GetNames(enumType)); flagnames.Remove("None"); return flagnames.ToArray(); } - public static Dictionary get_media_list() + public static Dictionary GetMediaList() { - Dictionary flags = new Dictionary(); - flags.Add("MediaAutoScale", "Bool (True|False)"); - flags.Add("MediaLoop", "Bool (True|False)"); - flags.Add("MediaID", "UUID (Texture)"); - flags.Add("MediaURL", "String"); - flags.Add("MediaDesc", "String"); - flags.Add("MediaHeight", "Int (256 to 1024)"); - flags.Add("MediaWidth", "Int (256 to 1024)"); - flags.Add("MediaType", "String [\"IMG-PNG\",\"IMG-JPG\",\"VID-MP4\",\"VID-AVI\" or \"Custom-MIME_TYPE_CODE\"]"); + Dictionary flags = new() + { + { "MediaAutoScale", "Bool (True|False)" }, + { "MediaLoop", "Bool (True|False)" }, + { "MediaID", "UUID (Texture)" }, + { "MediaURL", "String" }, + { "MediaDesc", "String" }, + { "MediaHeight", "Int (256 to 1024)" }, + { "MediaWidth", "Int (256 to 1024)" }, + { "MediaType", "String [\"IMG-PNG\",\"IMG-JPG\",\"VID-MP4\",\"VID-AVI\" or \"Custom-MIME_TYPE_CODE\"]" } + }; return flags; } - public static Dictionary get_flags_list() + public static Dictionary GetFlagsList() { - Dictionary flags = new Dictionary(); + Dictionary flags = new(); Type enumType = typeof(ParcelFlags); Array enumValues = Enum.GetValues(enumType); Array enumNames = Enum.GetNames(enumType);