update lib meta and cleanup

This commit is contained in:
Madpeter 2023-07-23 14:13:32 +01:00
parent 608690c748
commit 59b768f1b1
46 changed files with 773 additions and 591 deletions

View file

@ -3,7 +3,7 @@
<AssemblyName>LibreMetaverse.StructuredData</AssemblyName> <AssemblyName>LibreMetaverse.StructuredData</AssemblyName>
<Description>LibreMetaverse structured data library</Description> <Description>LibreMetaverse structured data library</Description>
<PackageId>LibreMetaverse.StructuredData</PackageId> <PackageId>LibreMetaverse.StructuredData</PackageId>
<TargetFrameworks>net48;netstandard2.1;net6.0;net7.0</TargetFrameworks> <TargetFrameworks>net7.0</TargetFrameworks>
<OutputType>Library</OutputType> <OutputType>Library</OutputType>
<RootNamespace>LibreMetaverse.StructuredData</RootNamespace> <RootNamespace>LibreMetaverse.StructuredData</RootNamespace>
<GenerateAssemblyInfo>true</GenerateAssemblyInfo> <GenerateAssemblyInfo>true</GenerateAssemblyInfo>

View file

@ -3,7 +3,7 @@
<AssemblyName>LibreMetaverse.Types</AssemblyName> <AssemblyName>LibreMetaverse.Types</AssemblyName>
<PackageId>LibreMetaverse.Types</PackageId> <PackageId>LibreMetaverse.Types</PackageId>
<Description>LibreMetaverse type library</Description> <Description>LibreMetaverse type library</Description>
<TargetFrameworks>net48;netstandard2.1;net6.0;net7.0</TargetFrameworks> <TargetFrameworks>net7.0</TargetFrameworks>
<OutputType>Library</OutputType> <OutputType>Library</OutputType>
<RootNamespace>LibreMetaverse</RootNamespace> <RootNamespace>LibreMetaverse</RootNamespace>
<GenerateAssemblyInfo>true</GenerateAssemblyInfo> <GenerateAssemblyInfo>true</GenerateAssemblyInfo>

View file

@ -366,7 +366,7 @@ namespace OpenMetaverse
public static string MD5(string str) public static string MD5(string str)
{ {
StringBuilder digest = new StringBuilder(32); 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 // Convert the hash to a hex string
foreach (byte b in hash) foreach (byte b in hash)
@ -399,7 +399,7 @@ namespace OpenMetaverse
/// <returns>The PBKDF2 hash of the supplied string</returns> /// <returns>The PBKDF2 hash of the supplied string</returns>
public static string PBKDF2(string str) 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[] hash = derivebytes.GetBytes(20);
byte[] salt = derivebytes.Salt; byte[] salt = derivebytes.Salt;
return Convert.ToBase64String(salt) + "|" + Convert.ToBase64String(hash); return Convert.ToBase64String(salt) + "|" + Convert.ToBase64String(hash);

View file

@ -910,7 +910,7 @@ namespace OpenMetaverse
/// <summary>Thread sync lock object</summary> /// <summary>Thread sync lock object</summary>
private readonly object m_InstantMessageLock = new object(); private readonly object m_InstantMessageLock = new object();
/// <summary>Raised when an ImprovedInstantMessage packet is recieved from the simulator, this is used for everything from /// <summary>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</summary> /// private messaging to friendship offers. The Dialog field defines what type of message has arrived</summary>
public event EventHandler<InstantMessageEventArgs> IM public event EventHandler<InstantMessageEventArgs> IM
{ {
@ -1104,8 +1104,7 @@ namespace OpenMetaverse
protected virtual void OnCameraConstraint(CameraConstraintEventArgs e) protected virtual void OnCameraConstraint(CameraConstraintEventArgs e)
{ {
EventHandler<CameraConstraintEventArgs> handler = m_CameraConstraint; EventHandler<CameraConstraintEventArgs> handler = m_CameraConstraint;
if (handler != null) handler?.Invoke(this, e);
handler(this, e);
} }
/// <summary>Thread sync lock object</summary> /// <summary>Thread sync lock object</summary>
@ -1128,8 +1127,7 @@ namespace OpenMetaverse
protected virtual void OnScriptSensorReply(ScriptSensorReplyEventArgs e) protected virtual void OnScriptSensorReply(ScriptSensorReplyEventArgs e)
{ {
EventHandler<ScriptSensorReplyEventArgs> handler = m_ScriptSensorReply; EventHandler<ScriptSensorReplyEventArgs> handler = m_ScriptSensorReply;
if (handler != null) handler?.Invoke(this, e);
handler(this, e);
} }
/// <summary>Thread sync lock object</summary> /// <summary>Thread sync lock object</summary>
@ -1151,8 +1149,7 @@ namespace OpenMetaverse
protected virtual void OnAvatarSitResponse(AvatarSitResponseEventArgs e) protected virtual void OnAvatarSitResponse(AvatarSitResponseEventArgs e)
{ {
EventHandler<AvatarSitResponseEventArgs> handler = m_AvatarSitResponse; EventHandler<AvatarSitResponseEventArgs> handler = m_AvatarSitResponse;
if (handler != null) handler?.Invoke(this, e);
handler(this, e);
} }
/// <summary>Thread sync lock object</summary> /// <summary>Thread sync lock object</summary>
@ -1478,7 +1475,7 @@ namespace OpenMetaverse
private HomeInfo home; private HomeInfo home;
private string fullName; private string fullName;
private TeleportStatus teleportStat = TeleportStatus.None; private TeleportStatus teleportStatus = TeleportStatus.None;
private ManualResetEvent teleportEvent = new ManualResetEvent(false); private ManualResetEvent teleportEvent = new ManualResetEvent(false);
private uint heightWidthGenCounter; private uint heightWidthGenCounter;
private Dictionary<UUID, AssetGesture> gestureCache = new Dictionary<UUID, AssetGesture>(); private Dictionary<UUID, AssetGesture> gestureCache = new Dictionary<UUID, AssetGesture>();
@ -2966,7 +2963,13 @@ namespace OpenMetaverse
/// <returns>true on success, false on failure</returns> /// <returns>true on success, false on failure</returns>
public bool Teleport(UUID landmark) 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(); teleportEvent.Reset();
TeleportLandmarkRequestPacket p = new TeleportLandmarkRequestPacket TeleportLandmarkRequestPacket p = new TeleportLandmarkRequestPacket
{ {
@ -2981,15 +2984,15 @@ namespace OpenMetaverse
teleportEvent.WaitOne(Client.Settings.TELEPORT_TIMEOUT, false); teleportEvent.WaitOne(Client.Settings.TELEPORT_TIMEOUT, false);
if (teleportStat == TeleportStatus.None || if (teleportStatus == TeleportStatus.None ||
teleportStat == TeleportStatus.Start || teleportStatus == TeleportStatus.Start ||
teleportStat == TeleportStatus.Progress) teleportStatus == TeleportStatus.Progress)
{ {
TeleportMessage = "Teleport timed out."; TeleportMessage = "Teleport timed out.";
teleportStat = TeleportStatus.Failed; teleportStatus = TeleportStatus.Failed;
} }
return (teleportStat == TeleportStatus.Finished); return (teleportStatus == TeleportStatus.Finished);
} }
/// <summary> /// <summary>
@ -3018,7 +3021,14 @@ namespace OpenMetaverse
{ {
if (Client.Network.CurrentSim == null) { return false; } 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) if (simName != Client.Network.CurrentSim.Name)
{ {
@ -3030,7 +3040,7 @@ namespace OpenMetaverse
else else
{ {
TeleportMessage = $"Unable to resolve simulator named: {simName}"; TeleportMessage = $"Unable to resolve simulator named: {simName}";
teleportStat = TeleportStatus.Failed; teleportStatus = TeleportStatus.Failed;
return false; return false;
} }
} }
@ -3063,40 +3073,46 @@ namespace OpenMetaverse
/// <remarks>This call is blocking</remarks> /// <remarks>This call is blocking</remarks>
public bool Teleport(ulong regionHandle, Vector3 position, Vector3 lookAt) 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 || if (Client.Network.CurrentSim == null ||
Client.Network.CurrentSim.Caps == null || Client.Network.CurrentSim.Caps == null ||
!Client.Network.CurrentSim.Caps.IsEventQueueRunning) !Client.Network.CurrentSim.Caps.IsEventQueueRunning)
{ {
// Wait a bit to see if the event queue comes online // Wait a bit to see if the event queue comes online
AutoResetEvent queueEvent = new AutoResetEvent(false); AutoResetEvent queueEvent = new AutoResetEvent(false);
EventHandler<EventQueueRunningEventArgs> 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); queueEvent.WaitOne(10 * 1000, false);
Client.Network.EventQueueRunning -= queueCallback; Client.Network.EventQueueRunning -= QueueCallback;
} }
teleportStat = TeleportStatus.None; teleportStatus = TeleportStatus.None;
teleportEvent.Reset(); teleportEvent.Reset();
RequestTeleport(regionHandle, position, lookAt); RequestTeleport(regionHandle, position, lookAt);
teleportEvent.WaitOne(Client.Settings.TELEPORT_TIMEOUT, false); teleportEvent.WaitOne(Client.Settings.TELEPORT_TIMEOUT, false);
if (teleportStat == TeleportStatus.None || if (teleportStatus == TeleportStatus.None ||
teleportStat == TeleportStatus.Start || teleportStatus == TeleportStatus.Start ||
teleportStat == TeleportStatus.Progress) teleportStatus == TeleportStatus.Progress)
{ {
TeleportMessage = "Teleport timed out."; TeleportMessage = "Teleport timed out.";
teleportStat = TeleportStatus.Failed; teleportStatus = TeleportStatus.Failed;
} }
return (teleportStat == TeleportStatus.Finished); return (teleportStatus == TeleportStatus.Finished);
} }
/// <summary> /// <summary>
@ -3117,8 +3133,7 @@ namespace OpenMetaverse
/// <param name="lookAt"><seealso cref="Vector3"/> direction in destination sim agent will look at</param> /// <param name="lookAt"><seealso cref="Vector3"/> direction in destination sim agent will look at</param>
public void RequestTeleport(ulong regionHandle, Vector3 position, Vector3 lookAt) public void RequestTeleport(ulong regionHandle, Vector3 position, Vector3 lookAt)
{ {
if (Client.Network.CurrentSim != null && if (Client.Network?.CurrentSim?.Caps != null &&
Client.Network.CurrentSim.Caps != null &&
Client.Network.CurrentSim.Caps.IsEventQueueRunning) Client.Network.CurrentSim.Caps.IsEventQueueRunning)
{ {
TeleportLocationRequestPacket teleport = new TeleportLocationRequestPacket TeleportLocationRequestPacket teleport = new TeleportLocationRequestPacket
@ -3144,7 +3159,7 @@ namespace OpenMetaverse
{ {
TeleportMessage = "CAPS event queue is not running"; TeleportMessage = "CAPS event queue is not running";
teleportEvent.Set(); teleportEvent.Set();
teleportStat = TeleportStatus.Failed; teleportStatus = TeleportStatus.Failed;
} }
} }
@ -3251,7 +3266,7 @@ namespace OpenMetaverse
} }
public void SendTeleportLureRequest(UUID targetID) 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 #endregion Teleporting
@ -4302,7 +4317,9 @@ namespace OpenMetaverse
SimAccess = (byte) msg.SimAccess, SimAccess = (byte) msg.SimAccess,
SimIP = Utils.IPToUInt(msg.IP), SimIP = Utils.IPToUInt(msg.IP),
SimPort = (ushort) msg.Port, SimPort = (ushort) msg.Port,
TeleportFlags = (uint) msg.Flags TeleportFlags = (uint) msg.Flags,
RegionSizeX = msg.RegionSizeX,
RegionSizeY = msg.RegionSizeY
} }
}; };
// FIXME: Check This // FIXME: Check This
@ -4328,7 +4345,7 @@ namespace OpenMetaverse
TeleportMessage = "Teleport started"; TeleportMessage = "Teleport started";
flags = (TeleportFlags)start.Info.TeleportFlags; flags = (TeleportFlags)start.Info.TeleportFlags;
teleportStat = TeleportStatus.Start; teleportStatus = TeleportStatus.Start;
Logger.DebugLog($"TeleportStart received, Flags: {flags}", Client); Logger.DebugLog($"TeleportStart received, Flags: {flags}", Client);
} }
@ -4338,7 +4355,7 @@ namespace OpenMetaverse
TeleportMessage = Utils.BytesToString(progress.Info.Message); TeleportMessage = Utils.BytesToString(progress.Info.Message);
flags = (TeleportFlags)progress.Info.TeleportFlags; flags = (TeleportFlags)progress.Info.TeleportFlags;
teleportStat = TeleportStatus.Progress; teleportStatus = TeleportStatus.Progress;
Logger.DebugLog($"TeleportProgress received, Message: {TeleportMessage}, Flags: {flags}", Client); Logger.DebugLog($"TeleportProgress received, Message: {TeleportMessage}, Flags: {flags}", Client);
} }
@ -4347,7 +4364,7 @@ namespace OpenMetaverse
TeleportFailedPacket failed = (TeleportFailedPacket)packet; TeleportFailedPacket failed = (TeleportFailedPacket)packet;
TeleportMessage = Utils.BytesToString(failed.Info.Reason); TeleportMessage = Utils.BytesToString(failed.Info.Reason);
teleportStat = TeleportStatus.Failed; teleportStatus = TeleportStatus.Failed;
finished = true; finished = true;
Logger.DebugLog($"TeleportFailed received, Reason: {TeleportMessage}", Client); Logger.DebugLog($"TeleportFailed received, Reason: {TeleportMessage}", Client);
@ -4365,19 +4382,20 @@ namespace OpenMetaverse
// Connect to the new sim // Connect to the new sim
Client.Network.CurrentSim.AgentMovementComplete = false; // we're not there anymore Client.Network.CurrentSim.AgentMovementComplete = false; // we're not there anymore
Simulator newSimulator = Client.Network.Connect(new IPAddress(finish.Info.SimIP), 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) if (newSimulator != null)
{ {
TeleportMessage = "Teleport finished"; 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 else
{ {
TeleportMessage = "Failed to connect to the new sim after a teleport"; TeleportMessage = $"Failed to connect to {newSimulator} after teleport";
teleportStat = TeleportStatus.Failed; teleportStatus = TeleportStatus.Failed;
// We're going to get disconnected now // We're going to get disconnected now
Logger.Log(TeleportMessage, Helpers.LogLevel.Error, Client); Logger.Log(TeleportMessage, Helpers.LogLevel.Error, Client);
@ -4388,7 +4406,7 @@ namespace OpenMetaverse
//TeleportCancelPacket cancel = (TeleportCancelPacket)packet; //TeleportCancelPacket cancel = (TeleportCancelPacket)packet;
TeleportMessage = "Cancelled"; TeleportMessage = "Cancelled";
teleportStat = TeleportStatus.Cancelled; teleportStatus = TeleportStatus.Cancelled;
finished = true; finished = true;
Logger.DebugLog($"TeleportCancel received from {simulator}", Client); Logger.DebugLog($"TeleportCancel received from {simulator}", Client);
@ -4399,7 +4417,7 @@ namespace OpenMetaverse
TeleportMessage = "Teleport finished"; TeleportMessage = "Teleport finished";
flags = (TeleportFlags)local.Info.TeleportFlags; flags = (TeleportFlags)local.Info.TeleportFlags;
teleportStat = TeleportStatus.Finished; teleportStatus = TeleportStatus.Finished;
relativePosition = local.Info.Position; relativePosition = local.Info.Position;
Movement.Camera.LookDirection(local.Info.LookAt); Movement.Camera.LookDirection(local.Info.LookAt);
// This field is apparently not used for anything // This field is apparently not used for anything
@ -4411,7 +4429,7 @@ namespace OpenMetaverse
if (m_Teleport != null) if (m_Teleport != null)
{ {
OnTeleport(new TeleportEventArgs(TeleportMessage, teleportStat, flags)); OnTeleport(new TeleportEventArgs(TeleportMessage, teleportStatus, flags));
} }
if (finished) { teleportEvent.Set(); } if (finished) { teleportEvent.Set(); }
@ -4541,7 +4559,8 @@ namespace OpenMetaverse
Logger.DebugLog($"Crossed in to new region area, attempting to connect to {endPoint}", Client); Logger.DebugLog($"Crossed in to new region area, attempting to connect to {endPoint}", Client);
Simulator oldSim = Client.Network.CurrentSim; 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) if (newSim != null)
{ {

View file

@ -393,18 +393,12 @@ namespace OpenMetaverse
{ {
if (value > 0) if (value > 0)
{ {
if (updateTimer != null) updateTimer?.Change(value, value);
{
updateTimer.Change(value, value);
}
updateInterval = value; updateInterval = value;
} }
else else
{ {
if (updateTimer != null) updateTimer?.Change(Timeout.Infinite, Timeout.Infinite);
{
updateTimer.Change(Timeout.Infinite, Timeout.Infinite);
}
updateInterval = 0; updateInterval = 0;
} }
} }

View file

@ -219,7 +219,7 @@ namespace OpenMetaverse
/// </summary> /// </summary>
/// <param name="assetID">UUID of the asset</param> /// <param name="assetID">UUID of the asset</param>
/// <param name="assetData">Raw bytes the asset consists of</param> /// <param name="assetData">Raw bytes the asset consists of</param>
/// <returns>Weather the operation was successfull</returns> /// <returns>Whether the operation was successful</returns>
public bool SaveAssetToCache(UUID assetID, byte[] assetData) public bool SaveAssetToCache(UUID assetID, byte[] assetData)
{ {
if (!Operational()) if (!Operational())

View file

@ -319,8 +319,7 @@ namespace OpenMetaverse
protected virtual void OnXferReceived(XferReceivedEventArgs e) protected virtual void OnXferReceived(XferReceivedEventArgs e)
{ {
EventHandler<XferReceivedEventArgs> handler = m_XferReceivedEvent; EventHandler<XferReceivedEventArgs> handler = m_XferReceivedEvent;
if (handler != null) handler?.Invoke(this, e);
handler(this, e);
} }
/// <summary>Thread sync lock object</summary> /// <summary>Thread sync lock object</summary>
@ -344,8 +343,7 @@ namespace OpenMetaverse
protected virtual void OnAssetUploaded(AssetUploadEventArgs e) protected virtual void OnAssetUploaded(AssetUploadEventArgs e)
{ {
EventHandler<AssetUploadEventArgs> handler = m_AssetUploadedEvent; EventHandler<AssetUploadEventArgs> handler = m_AssetUploadedEvent;
if (handler != null) handler?.Invoke(this, e);
handler(this, e);
} }
/// <summary>Thread sync lock object</summary> /// <summary>Thread sync lock object</summary>
@ -369,8 +367,7 @@ namespace OpenMetaverse
protected virtual void OnUploadProgress(AssetUploadEventArgs e) protected virtual void OnUploadProgress(AssetUploadEventArgs e)
{ {
EventHandler<AssetUploadEventArgs> handler = m_UploadProgressEvent; EventHandler<AssetUploadEventArgs> handler = m_UploadProgressEvent;
if (handler != null) handler?.Invoke(this, e);
handler(this, e);
} }
/// <summary>Thread sync lock object</summary> /// <summary>Thread sync lock object</summary>
@ -394,8 +391,7 @@ namespace OpenMetaverse
protected virtual void OnInitiateDownload(InitiateDownloadEventArgs e) protected virtual void OnInitiateDownload(InitiateDownloadEventArgs e)
{ {
EventHandler<InitiateDownloadEventArgs> handler = m_InitiateDownloadEvent; EventHandler<InitiateDownloadEventArgs> handler = m_InitiateDownloadEvent;
if (handler != null) handler?.Invoke(this, e);
handler(this, e);
} }
/// <summary>Thread sync lock object</summary> /// <summary>Thread sync lock object</summary>
@ -419,8 +415,7 @@ namespace OpenMetaverse
protected virtual void OnImageReceiveProgress(ImageReceiveProgressEventArgs e) protected virtual void OnImageReceiveProgress(ImageReceiveProgressEventArgs e)
{ {
EventHandler<ImageReceiveProgressEventArgs> handler = m_ImageReceiveProgressEvent; EventHandler<ImageReceiveProgressEventArgs> handler = m_ImageReceiveProgressEvent;
if (handler != null) handler?.Invoke(this, e);
handler(this, e);
} }
/// <summary>Thread sync lock object</summary> /// <summary>Thread sync lock object</summary>
@ -640,8 +635,7 @@ namespace OpenMetaverse
} }
// If ViewerAsset capability exists, use that, if not, fallback to UDP (which is obsoleted on Second Life.) // If ViewerAsset capability exists, use that, if not, fallback to UDP (which is obsoleted on Second Life.)
if (Client.Network.CurrentSim.Caps != null if (Client.Network.CurrentSim?.Caps?.CapabilityURI("ViewerAsset") != null)
&& Client.Network.CurrentSim.Caps.CapabilityURI("ViewerAsset") != null)
{ {
RequestAssetHTTP(assetID, transfer, callback); RequestAssetHTTP(assetID, transfer, callback);
} }
@ -827,10 +821,20 @@ namespace OpenMetaverse
} }
// If ViewerAsset capability exists, use that, if not, fallback to UDP // If ViewerAsset capability exists, use that, if not, fallback to UDP
if (Client.Network.CurrentSim.Caps != null if (Client.Network.CurrentSim?.Caps?.CapabilityURI("ViewerAsset") != null)
&& 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 else
{ {
@ -849,6 +853,7 @@ namespace OpenMetaverse
/// <param name="callback"></param> /// <param name="callback"></param>
private void RequestInventoryAssetHTTP(UUID assetID, AssetDownload transfer, AssetReceivedCallback callback) private void RequestInventoryAssetHTTP(UUID assetID, AssetDownload transfer, AssetReceivedCallback callback)
{ {
int attempts = 0;
DownloadRequest req = new DownloadRequest( DownloadRequest req = new DownloadRequest(
BuildFetchRequestUri(transfer.AssetType, assetID), BuildFetchRequestUri(transfer.AssetType, assetID),
null, null,
@ -873,6 +878,7 @@ namespace OpenMetaverse
} }
else // download failed else // download failed
{ {
attempts++;
Logger.Log($"Failed to fetch asset {assetID}: {((error == null) ? "" : error.Message)}", Logger.Log($"Failed to fetch asset {assetID}: {((error == null) ? "" : error.Message)}",
Helpers.LogLevel.Warning, Client); Helpers.LogLevel.Warning, Client);
if (callback != null) if (callback != null)
@ -880,6 +886,10 @@ namespace OpenMetaverse
transfer.Success = false; transfer.Success = false;
transfer.Status = StatusCode.Error; transfer.Status = StatusCode.Error;
} }
if (attempts == 5)
{
callback(transfer, null);
}
} }
} }
@ -1213,8 +1223,7 @@ namespace OpenMetaverse
if (meshID == UUID.Zero || callback == null) if (meshID == UUID.Zero || callback == null)
return; return;
if (Client.Network.CurrentSim.Caps != null && if (Client.Network.CurrentSim?.Caps?.GetMeshCapURI() != null)
Client.Network.CurrentSim.Caps.GetMeshCapURI() != null)
{ {
// Do we have this mesh asset in the cache? // Do we have this mesh asset in the cache?
if (Client.Assets.Cache.HasAsset(meshID)) if (Client.Assets.Cache.HasAsset(meshID))
@ -1329,8 +1338,7 @@ namespace OpenMetaverse
uint packetStart, TextureDownloadCallback callback, bool progress) uint packetStart, TextureDownloadCallback callback, bool progress)
{ {
if (Client.Settings.USE_HTTP_TEXTURES 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); HttpRequestTexture(textureID, imageType, priority, discardLevel, packetStart, callback, progress);
} }

View file

@ -206,6 +206,7 @@ namespace OpenMetaverse.Assets
private static bool LoadTerrain(string filePath, byte[] data, TerrainLoadedCallback terrainCallback, long bytesRead, long totalBytes) 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]; float[,] terrain = new float[256, 256];
bool loaded = false; bool loaded = false;
@ -350,10 +351,10 @@ namespace OpenMetaverse.Assets
BinaryWriter bs = new BinaryWriter(s); BinaryWriter bs = new BinaryWriter(s);
int y; int y;
for (y = 0; y < 256; y++) for (y = 0; y < sim.SizeY; y++)
{ {
int x; int x;
for (x = 0; x < 256; x++) for (x = 0; x < sim.SizeX; x++)
{ {
float height; float height;
sim.TerrainHeightAtPoint(x, y, out height); sim.TerrainHeightAtPoint(x, y, out height);

View file

@ -689,9 +689,7 @@ namespace OpenMetaverse
/// <returns>True if Display name functionality is available</returns> /// <returns>True if Display name functionality is available</returns>
public bool DisplayNamesAvailable() public bool DisplayNamesAvailable()
{ {
return (Client.Network.CurrentSim != null return Client.Network.CurrentSim?.Caps?.CapabilityURI("GetDisplayNames") != null;
&& Client.Network.CurrentSim.Caps != null)
&& Client.Network.CurrentSim.Caps.CapabilityURI("GetDisplayNames") != null;
} }
/// <summary> /// <summary>

View file

@ -296,8 +296,7 @@ namespace OpenMetaverse.Http
} }
// Fire the download progress callback for each chunk of received data // Fire the download progress callback for each chunk of received data
if (state.DownloadProgressCallback != null) state.DownloadProgressCallback?.Invoke(state.Request, response, totalBytesRead, totalSize);
state.DownloadProgressCallback(state.Request, response, totalBytesRead, totalSize);
} }
if (nolength) if (nolength)

View file

@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2006-2016, openmetaverse.co * Copyright (c) 2006-2016, openmetaverse.co
* Copyright (c) 2022, Sjofn LLC. * Copyright (c) 2022-2023, Sjofn LLC.
* All rights reserved. * All rights reserved.
* *
* - Redistribution and use in source and binary forms, with or without * - Redistribution and use in source and binary forms, with or without
@ -38,9 +38,9 @@ namespace OpenMetaverse.Http
public class EventQueueClient public class EventQueueClient
{ {
/// <summary>For exponential backoff on error.</summary> /// <summary>For exponential backoff on error.</summary>
public const int REQUEST_BACKOFF_SECONDS = 15 * 1000; // 15 seconds start private const int REQUEST_BACKOFF_SECONDS = 15 * 1000; // 15 seconds start
public const int REQUEST_BACKOFF_SECONDS_INC = 5 * 1000; // 5 seconds increase private 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_MAX = 5 * 60 * 1000; // 5 minutes
public delegate void ConnectedCallback(); public delegate void ConnectedCallback();
public delegate void EventCallback(string eventName, OSDMap body); public delegate void EventCallback(string eventName, OSDMap body);
@ -48,13 +48,14 @@ namespace OpenMetaverse.Http
public ConnectedCallback OnConnected; public ConnectedCallback OnConnected;
public EventCallback OnEvent; 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;
/// <summary>Number of times we've received an unknown CAPS exception in series.</summary> /// <summary>Number of times we've received an unknown CAPS exception in series.</summary>
private int _errorCount; private int _errorCount;
@ -63,19 +64,71 @@ namespace OpenMetaverse.Http
{ {
_Address = eventQueueLocation; _Address = eventQueueLocation;
_Simulator = sim; _Simulator = sim;
_queueCts = new CancellationTokenSource();
} }
public void Start() public void Start()
{ {
_Dead = false; _Dead = false;
_Running = true; Running = true;
// Create an EventQueueGet request Task.Factory.StartNew(() =>
OSDMap payload = new OSDMap {["ack"] = new OSD(), ["done"] = OSD.FromBoolean(false)}; {
// 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) public void Stop(bool immediate)
@ -84,17 +137,17 @@ namespace OpenMetaverse.Http
if (immediate) if (immediate)
{ {
_Running = false; Running = false;
} }
_HttpCts.Cancel(); _queueCts.Cancel();
} }
void ConnectedResponseHandler(HttpResponseMessage response) void ConnectedResponseHandler(HttpResponseMessage response)
{ {
if (!response.IsSuccessStatusCode) { return; } if (!response.IsSuccessStatusCode) { return; }
_Running = true; Running = true;
// The event queue is starting up for the first time // The event queue is starting up for the first time
if (OnConnected != null) if (OnConnected != null)
@ -120,11 +173,11 @@ namespace OpenMetaverse.Http
} }
else 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); System.Text.Encoding.UTF8.GetString(responseData) + "\"", Helpers.LogLevel.Warning);
} }
} }
else if (error != null) else if (response != null && error != null)
{ {
#region Error handling #region Error handling
@ -132,30 +185,31 @@ namespace OpenMetaverse.Http
{ {
case HttpStatusCode.NotFound: case HttpStatusCode.NotFound:
case HttpStatusCode.Gone: 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; _Dead = true;
break; break;
case (HttpStatusCode)499: // weird error returned occasionally, ignore for now 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) // 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; _Dead = true;
break; break;
case HttpStatusCode.InternalServerError: case HttpStatusCode.InternalServerError:
// As per LL's instructions, we ought to consider this a // As per LL's instructions, we ought to consider this a
// 'request to close client' (gwyneth 20220413) // '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! // ... but do we happen to have an InnerException? Log it!
if (error.InnerException != null) if (error.InnerException != null)
{ {
// unravel the whole inner error message, so we finally figure out what it is! // unravel the whole inner error message, so we finally figure out what it is!
// (gwyneth 20220414) // (gwyneth 20220414)
Logger.Log($"Unrecognized internal caps exception from {_Simulator}: '{error.InnerException.Message}'", Helpers.LogLevel.Warning); Logger.Log($"Unrecognized internal caps exception from {_Simulator}: '{error.InnerException.Message}'",
Logger.Log($"\nMessage ---\n{error.Message}", Helpers.LogLevel.Warning); Helpers.LogLevel.Warning, _Simulator.Client);
Logger.Log($"\nMessage ---\n{error.Message}", Helpers.LogLevel.Warning, _Simulator.Client);
if (error.Data.Count > 0) if (error.Data.Count > 0)
{ {
Logger.Log(" Extra details:", Helpers.LogLevel.Warning); Logger.Log(" Extra details:", Helpers.LogLevel.Warning);
@ -163,13 +217,13 @@ namespace OpenMetaverse.Http
{ {
Logger.Log(String.Format(" Key: {0,-20} Value: '{1}'", Logger.Log(String.Format(" Key: {0,-20} Value: '{1}'",
de.Key, de.Value), de.Key, de.Value),
Helpers.LogLevel.Warning); Helpers.LogLevel.Warning, _Simulator.Client);
} }
} }
// but we'll nevertheless close this connection (gwyneth 20220414) // but we'll nevertheless close this connection (gwyneth 20220414)
} }
_Running = false; Running = false;
_Dead = true; _Dead = true;
break; break;
case HttpStatusCode.BadGateway: case HttpStatusCode.BadGateway:
@ -182,7 +236,8 @@ namespace OpenMetaverse.Http
// Note: if this condition persists, it _might_ be the grid trying to request // 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) // that the client closes the connection, as per LL's specs (gwyneth 20220414)
Logger.Log($"Grid sent a Bad Gateway Error at {_Simulator}; " + 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; break;
default: default:
++_errorCount; ++_errorCount;
@ -191,71 +246,55 @@ namespace OpenMetaverse.Http
if (response.StatusCode != HttpStatusCode.OK) if (response.StatusCode != HttpStatusCode.OK)
{ {
Logger.Log($"Unrecognized caps connection problem from {_Simulator}: {response.StatusCode} {response.ReasonPhrase}", 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) else if (error.InnerException != null)
{ {
// see comment above (gwyneth 20220414) // see comment above (gwyneth 20220414)
Logger.Log($"Unrecognized internal caps exception from {_Simulator}: '{error.InnerException.Message}'", Helpers.LogLevel.Warning); Logger.Log($"Unrecognized internal caps exception from {_Simulator}: '{error.InnerException.Message}'",
Logger.Log($"Message ---\n{error.Message}", Helpers.LogLevel.Warning); Helpers.LogLevel.Warning, _Simulator.Client);
Logger.Log($"Message ---\n{error.Message}", Helpers.LogLevel.Warning, _Simulator.Client);
if (error.Data.Count > 0) 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) foreach (DictionaryEntry de in error.Data)
{ {
Logger.Log(string.Format(" Key: {0,-20} Value: {1}", Logger.Log(string.Format(" Key: {0,-20} Value: {1}",
"'" + de.Key + "'", de.Value), "'" + de.Key + "'", de.Value),
Helpers.LogLevel.Warning); Helpers.LogLevel.Warning, _Simulator.Client);
} }
} }
} }
else else
{ {
Logger.Log($"Unrecognized caps exception from {_Simulator}: {error.Message}", Logger.Log($"Unrecognized caps exception from {_Simulator}: {error.Message}",
Helpers.LogLevel.Warning); Helpers.LogLevel.Warning, _Simulator.Client);
} }
break; break;
} // end switch } // end switch
#endregion Error handling #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 else
{ {
++_errorCount; ++_errorCount;
Logger.Log($"No response from {_Simulator} event queue with no reported error", Helpers.LogLevel.Warning, _Simulator.Client);
Logger.Log($"No response from {_Simulator} event queue but no reported error either", Helpers.LogLevel.Warning);
} }
#pragma warning disable CS0164 // This label has not been referenced if (Running)
HandlingDone:
#region Resume the connection
if (_Running)
{ {
OSDMap payload = new OSDMap(); OSDMap payload = new OSDMap();
if (ack != 0) { payload["ack"] = OSD.FromInteger(ack); } if (ack != 0) { payload["ack"] = OSD.FromInteger(ack); }
else { payload["ack"] = new OSD(); } else { payload["ack"] = new OSD(); }
payload["done"] = OSD.FromBoolean(_Dead); payload["done"] = OSD.FromBoolean(_Dead);
_AckPayload = payload;
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}");
}
} }
#pragma warning restore CS0164 // This label has not been referenced
#endregion Resume the connection
#region Handle incoming events #region Handle incoming events

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2022, Sjofn, LLC. * Copyright (c) 2022-2023, Sjofn, LLC.
* All rights reserved. * All rights reserved.
* *
* - Redistribution and use in source and binary forms, with or without * - 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, private async Task SendRequestAsync(HttpRequestMessage request, CancellationToken? cancellationToken,
DownloadCompleteHandler completeHandler, DownloadProgressHandler progressHandler, ConnectedHandler connectedHandler) DownloadCompleteHandler completeHandler, DownloadProgressHandler progressHandler, ConnectedHandler connectedHandler)
{ {
using (var response = (cancellationToken.HasValue) try
? await SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken.Value)
: await SendAsync(request, HttpCompletionOption.ResponseHeadersRead))
{ {
if (!response.IsSuccessStatusCode) using (var response = (cancellationToken.HasValue)
? await SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken.Value)
: await SendAsync(request, HttpCompletionOption.ResponseHeadersRead))
{ {
completeHandler?.Invoke(response, null, if (!response.IsSuccessStatusCode)
new HttpRequestException(response.StatusCode + " " + response.ReasonPhrase)); {
completeHandler?.Invoke(response, null,
new HttpRequestException(response.StatusCode + " " + response.ReasonPhrase));
}
connectedHandler?.Invoke(response);
await ProcessResponseAsync(response, cancellationToken, completeHandler, progressHandler);
} }
}
connectedHandler?.Invoke(response); catch (HttpRequestException ex)
{
await ProcessResponseAsync(response, cancellationToken, completeHandler, progressHandler); completeHandler?.Invoke(null, null, ex);
} }
} }

View file

@ -307,6 +307,7 @@ namespace OpenMetaverse
private void EventQueueConnectedHandler() private void EventQueueConnectedHandler()
{ {
Logger.DebugLog($"Event queue for {Simulator} is connected", Simulator.Client); Logger.DebugLog($"Event queue for {Simulator} is connected", Simulator.Client);
Simulator.DisconnectCandidate = false;
Simulator.Client.Network.RaiseConnectedEvent(Simulator); 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", Logger.Log($"No Message handler exists for event {eventName}. Unable to decode. Will try Generic Handler next",
Helpers.LogLevel.Warning); 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); Helpers.LogLevel.Debug);
// try generic decoder next which takes a caps event and tries to match it to an existing packet // try generic decoder next which takes a caps event and tries to match it to an existing packet

View file

@ -1029,7 +1029,7 @@ namespace OpenMetaverse
/// <summary> /// <summary>
/// Searches Places for land owned by the specified group /// Searches Places for land owned by the specified group
/// </summary> /// </summary>
/// <param name="groupID">ID of the group you want to recieve land list for (You must be a member of the group)</param> /// <param name="groupID">ID of the group you want to receive land list for (You must be a member of the group)</param>
/// <returns>Transaction (Query) ID which can be associated with results from your request.</returns> /// <returns>Transaction (Query) ID which can be associated with results from your request.</returns>
public UUID StartPlacesSearch(UUID groupID) public UUID StartPlacesSearch(UUID groupID)
{ {
@ -1055,7 +1055,7 @@ namespace OpenMetaverse
/// <param name="searchCategory">One of the values from the SearchCategory Struct, ie: Any, Linden, Newcomer</param> /// <param name="searchCategory">One of the values from the SearchCategory Struct, ie: Any, Linden, Newcomer</param>
/// <param name="searchText">A string containing a list of keywords to search for separated by a space character</param> /// <param name="searchText">A string containing a list of keywords to search for separated by a space character</param>
/// <param name="simulatorName">String Simulator Name to search in</param> /// <param name="simulatorName">String Simulator Name to search in</param>
/// <param name="groupID">LLUID of group you want to recieve results for</param> /// <param name="groupID">LLUID of group you want to receive results for</param>
/// <param name="transactionID">Transaction (Query) ID which can be associated with results from your request.</param> /// <param name="transactionID">Transaction (Query) ID which can be associated with results from your request.</param>
/// <returns>Transaction (Query) ID which can be associated with results from your request.</returns> /// <returns>Transaction (Query) ID which can be associated with results from your request.</returns>
public UUID StartPlacesSearch(DirFindFlags findFlags, ParcelCategory searchCategory, string searchText, string simulatorName, public UUID StartPlacesSearch(DirFindFlags findFlags, ParcelCategory searchCategory, string searchText, string simulatorName,

View file

@ -167,8 +167,7 @@ namespace OpenMetaverse
protected virtual void OnTopCollidersReply(TopCollidersReplyEventArgs e) protected virtual void OnTopCollidersReply(TopCollidersReplyEventArgs e)
{ {
EventHandler<TopCollidersReplyEventArgs> handler = m_TopCollidersReply; EventHandler<TopCollidersReplyEventArgs> handler = m_TopCollidersReply;
if (handler != null) handler?.Invoke(this, e);
handler(this, e);
} }
/// <summary>Thread sync lock object</summary> /// <summary>Thread sync lock object</summary>
@ -190,8 +189,7 @@ namespace OpenMetaverse
protected virtual void OnTopScriptsReply(TopScriptsReplyEventArgs e) protected virtual void OnTopScriptsReply(TopScriptsReplyEventArgs e)
{ {
EventHandler<TopScriptsReplyEventArgs> handler = m_TopScriptsReply; EventHandler<TopScriptsReplyEventArgs> handler = m_TopScriptsReply;
if (handler != null) handler?.Invoke(this, e);
handler(this, e);
} }
/// <summary>Thread sync lock object</summary> /// <summary>Thread sync lock object</summary>
@ -214,8 +212,7 @@ namespace OpenMetaverse
protected virtual void OnEstateUsersReply(EstateUsersReplyEventArgs e) protected virtual void OnEstateUsersReply(EstateUsersReplyEventArgs e)
{ {
EventHandler<EstateUsersReplyEventArgs> handler = m_EstateUsersReply; EventHandler<EstateUsersReplyEventArgs> handler = m_EstateUsersReply;
if (handler != null) handler?.Invoke(this, e);
handler(this, e);
} }
/// <summary>Thread sync lock object</summary> /// <summary>Thread sync lock object</summary>
@ -238,8 +235,7 @@ namespace OpenMetaverse
protected virtual void OnEstateGroupsReply(EstateGroupsReplyEventArgs e) protected virtual void OnEstateGroupsReply(EstateGroupsReplyEventArgs e)
{ {
EventHandler<EstateGroupsReplyEventArgs> handler = m_EstateGroupsReply; EventHandler<EstateGroupsReplyEventArgs> handler = m_EstateGroupsReply;
if (handler != null) handler?.Invoke(this, e);
handler(this, e);
} }
/// <summary>Thread sync lock object</summary> /// <summary>Thread sync lock object</summary>
@ -261,8 +257,7 @@ namespace OpenMetaverse
protected virtual void OnEstateManagersReply(EstateManagersReplyEventArgs e) protected virtual void OnEstateManagersReply(EstateManagersReplyEventArgs e)
{ {
EventHandler<EstateManagersReplyEventArgs> handler = m_EstateManagersReply; EventHandler<EstateManagersReplyEventArgs> handler = m_EstateManagersReply;
if (handler != null) handler?.Invoke(this, e);
handler(this, e);
} }
/// <summary>Thread sync lock object</summary> /// <summary>Thread sync lock object</summary>
@ -284,8 +279,7 @@ namespace OpenMetaverse
protected virtual void OnEstateBansReply(EstateBansReplyEventArgs e) protected virtual void OnEstateBansReply(EstateBansReplyEventArgs e)
{ {
EventHandler<EstateBansReplyEventArgs> handler = m_EstateBansReply; EventHandler<EstateBansReplyEventArgs> handler = m_EstateBansReply;
if (handler != null) handler?.Invoke(this, e);
handler(this, e);
} }
/// <summary>Thread sync lock object</summary> /// <summary>Thread sync lock object</summary>
@ -307,8 +301,7 @@ namespace OpenMetaverse
protected virtual void OnEstateCovenantReply(EstateCovenantReplyEventArgs e) protected virtual void OnEstateCovenantReply(EstateCovenantReplyEventArgs e)
{ {
EventHandler<EstateCovenantReplyEventArgs> handler = m_EstateCovenantReply; EventHandler<EstateCovenantReplyEventArgs> handler = m_EstateCovenantReply;
if (handler != null) handler?.Invoke(this, e);
handler(this, e);
} }
/// <summary>Thread sync lock object</summary> /// <summary>Thread sync lock object</summary>
@ -331,8 +324,7 @@ namespace OpenMetaverse
protected virtual void OnEstateUpdateInfoReply(EstateUpdateInfoReplyEventArgs e) protected virtual void OnEstateUpdateInfoReply(EstateUpdateInfoReplyEventArgs e)
{ {
EventHandler<EstateUpdateInfoReplyEventArgs> handler = m_EstateUpdateInfoReply; EventHandler<EstateUpdateInfoReplyEventArgs> handler = m_EstateUpdateInfoReply;
if (handler != null) handler?.Invoke(this, e);
handler(this, e);
} }
/// <summary>Thread sync lock object</summary> /// <summary>Thread sync lock object</summary>

View file

@ -218,8 +218,7 @@ namespace OpenMetaverse
protected virtual void OnfriendsListReady(FriendsReadyEventArgs e) protected virtual void OnfriendsListReady(FriendsReadyEventArgs e)
{ {
EventHandler<FriendsReadyEventArgs> handler = m_FriendsListReadyResponse; EventHandler<FriendsReadyEventArgs> handler = m_FriendsListReadyResponse;
if (handler != null) handler?.Invoke(this, e);
handler(this, e);
} }
/// <summary>Thread sync lock object</summary> /// <summary>Thread sync lock object</summary>
@ -240,8 +239,7 @@ namespace OpenMetaverse
protected virtual void OnFriendOnline(FriendInfoEventArgs e) protected virtual void OnFriendOnline(FriendInfoEventArgs e)
{ {
EventHandler<FriendInfoEventArgs> handler = m_FriendOnline; EventHandler<FriendInfoEventArgs> handler = m_FriendOnline;
if (handler != null) handler?.Invoke(this, e);
handler(this, e);
} }
/// <summary>Thread sync lock object</summary> /// <summary>Thread sync lock object</summary>
@ -263,8 +261,7 @@ namespace OpenMetaverse
protected virtual void OnFriendOffline(FriendInfoEventArgs e) protected virtual void OnFriendOffline(FriendInfoEventArgs e)
{ {
EventHandler<FriendInfoEventArgs> handler = m_FriendOffline; EventHandler<FriendInfoEventArgs> handler = m_FriendOffline;
if (handler != null) handler?.Invoke(this, e);
handler(this, e);
} }
/// <summary>Thread sync lock object</summary> /// <summary>Thread sync lock object</summary>
@ -286,8 +283,7 @@ namespace OpenMetaverse
protected virtual void OnFriendRights(FriendInfoEventArgs e) protected virtual void OnFriendRights(FriendInfoEventArgs e)
{ {
EventHandler<FriendInfoEventArgs> handler = m_FriendRights; EventHandler<FriendInfoEventArgs> handler = m_FriendRights;
if (handler != null) handler?.Invoke(this, e);
handler(this, e);
} }
/// <summary>Thread sync lock object</summary> /// <summary>Thread sync lock object</summary>
@ -309,8 +305,7 @@ namespace OpenMetaverse
protected virtual void OnFriendNames(FriendNamesEventArgs e) protected virtual void OnFriendNames(FriendNamesEventArgs e)
{ {
EventHandler<FriendNamesEventArgs> handler = m_FriendNames; EventHandler<FriendNamesEventArgs> handler = m_FriendNames;
if (handler != null) handler?.Invoke(this, e);
handler(this, e);
} }
/// <summary>Thread sync lock object</summary> /// <summary>Thread sync lock object</summary>
@ -332,8 +327,7 @@ namespace OpenMetaverse
protected virtual void OnFriendshipOffered(FriendshipOfferedEventArgs e) protected virtual void OnFriendshipOffered(FriendshipOfferedEventArgs e)
{ {
EventHandler<FriendshipOfferedEventArgs> handler = m_FriendshipOffered; EventHandler<FriendshipOfferedEventArgs> handler = m_FriendshipOffered;
if (handler != null) handler?.Invoke(this, e);
handler(this, e);
} }
/// <summary>Thread sync lock object</summary> /// <summary>Thread sync lock object</summary>
@ -355,8 +349,7 @@ namespace OpenMetaverse
protected virtual void OnFriendshipResponse(FriendshipResponseEventArgs e) protected virtual void OnFriendshipResponse(FriendshipResponseEventArgs e)
{ {
EventHandler<FriendshipResponseEventArgs> handler = m_FriendshipResponse; EventHandler<FriendshipResponseEventArgs> handler = m_FriendshipResponse;
if (handler != null) handler?.Invoke(this, e);
handler(this, e);
} }
/// <summary>Thread sync lock object</summary> /// <summary>Thread sync lock object</summary>
@ -378,8 +371,7 @@ namespace OpenMetaverse
protected virtual void OnFriendshipTerminated(FriendshipTerminatedEventArgs e) protected virtual void OnFriendshipTerminated(FriendshipTerminatedEventArgs e)
{ {
EventHandler<FriendshipTerminatedEventArgs> handler = m_FriendshipTerminated; EventHandler<FriendshipTerminatedEventArgs> handler = m_FriendshipTerminated;
if (handler != null) handler?.Invoke(this, e);
handler(this, e);
} }
/// <summary>Thread sync lock object</summary> /// <summary>Thread sync lock object</summary>
@ -402,8 +394,7 @@ namespace OpenMetaverse
protected virtual void OnFriendFoundReply(FriendFoundReplyEventArgs e) protected virtual void OnFriendFoundReply(FriendFoundReplyEventArgs e)
{ {
EventHandler<FriendFoundReplyEventArgs> handler = m_FriendFound; EventHandler<FriendFoundReplyEventArgs> handler = m_FriendFound;
if (handler != null) handler?.Invoke(this, e);
handler(this, e);
} }
/// <summary>Thread sync lock object</summary> /// <summary>Thread sync lock object</summary>

View file

@ -145,7 +145,6 @@ namespace OpenMetaverse
{ {
AllowAutoRedirect = true, AllowAutoRedirect = true,
AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip, AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip,
MaxConnectionsPerServer = Settings.MAX_HTTP_CONNECTIONS,
ServerCertificateCustomValidationCallback = (message, cert, chain, sslPolicyErrors) => ServerCertificateCustomValidationCallback = (message, cert, chain, sslPolicyErrors) =>
{ {
if (sslPolicyErrors == SslPolicyErrors.None) if (sslPolicyErrors == SslPolicyErrors.None)
@ -157,6 +156,10 @@ namespace OpenMetaverse
return true; return true;
} }
}; };
if (Utils.GetRunningRuntime() != Utils.Runtime.Mono)
handler.MaxConnectionsPerServer = Settings.MAX_HTTP_CONNECTIONS;
HttpCapsClient client = new HttpCapsClient(handler); HttpCapsClient client = new HttpCapsClient(handler);
client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Add("User-Agent", $"{Settings.USER_AGENT}"); client.DefaultRequestHeaders.Add("User-Agent", $"{Settings.USER_AGENT}");

View file

@ -158,14 +158,15 @@ namespace OpenMetaverse
public uint GlobalY; public uint GlobalY;
/// <summary>Get the Local X position of the item</summary> /// <summary>Get the Local X position of the item</summary>
public uint LocalX { get { return GlobalX % 256; } } public uint LocalX { get { return GlobalX % Simulator.DefaultRegionSizeX; } }
/// <summary>Get the Local Y position of the item</summary> /// <summary>Get the Local Y position of the item</summary>
public uint LocalY { get { return GlobalY % 256; } } public uint LocalY { get { return GlobalY % Simulator.DefaultRegionSizeY; } }
/// <summary>Get the Handle of the region</summary> /// <summary>Get the Handle of the region</summary>
public ulong RegionHandle 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))); }
} }
} }

View file

@ -1047,9 +1047,7 @@ namespace OpenMetaverse
UUID requestID = UUID.Random(); UUID requestID = UUID.Random();
Uri cap = null; Uri cap = null;
if (Client.Network.CurrentSim != null if ((cap = Client.Network.CurrentSim?.Caps?.CapabilityURI("GroupMemberData")) != null)
&& Client.Network.CurrentSim.Caps != null
&& (cap = Client.Network.CurrentSim.Caps.CapabilityURI("GroupMemberData")) != null)
{ {
OSDMap payload = new OSDMap(1) { ["group_id"] = @group }; OSDMap payload = new OSDMap(1) { ["group_id"] = @group };
Task req = Client.HttpCapsClient.PostRequestAsync(cap, OSDFormat.Xml, payload, CancellationToken.None, Task req = Client.HttpCapsClient.PostRequestAsync(cap, OSDFormat.Xml, payload, CancellationToken.None,
@ -1630,11 +1628,9 @@ namespace OpenMetaverse
{ {
Uri ret = null; Uri ret = null;
if (Client.Network.Connected if (Client.Network.Connected)
&& Client.Network.CurrentSim != null
&& Client.Network.CurrentSim.Caps != null)
{ {
ret = Client.Network.CurrentSim.Caps.CapabilityURI("GroupAPIv1"); ret = Client.Network.CurrentSim?.Caps?.CapabilityURI("GroupAPIv1");
if (ret != null) if (ret != null)
{ {
ret = new Uri($"{ret}?group_id={groupID.ToString()}"); ret = new Uri($"{ret}?group_id={groupID.ToString()}");

View file

@ -149,6 +149,11 @@ namespace OpenMetaverse
/// Given an X/Y location in absolute (grid-relative) terms, a region /// 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 /// handle is returned along with the local X/Y location in that region
/// </summary> /// </summary>
/// <remarks>
/// 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.
/// </remarks>
/// <param name="globalX">The absolute X location, a number such as /// <param name="globalX">The absolute X location, a number such as
/// 255360.35</param> /// 255360.35</param>
/// <param name="globalY">The absolute Y location, a number such as /// <param name="globalY">The absolute Y location, a number such as
@ -160,8 +165,8 @@ namespace OpenMetaverse
/// <returns>A 64-bit region handle that can be used to teleport to</returns> /// <returns>A 64-bit region handle that can be used to teleport to</returns>
public static ulong GlobalPosToRegionHandle(float globalX, float globalY, out float localX, out float localY) public static ulong GlobalPosToRegionHandle(float globalX, float globalY, out float localX, out float localY)
{ {
uint x = ((uint)globalX / 256) * 256; uint x = ((uint)globalX / Simulator.DefaultRegionSizeX) * Simulator.DefaultRegionSizeX;
uint y = ((uint)globalY / 256) * 256; uint y = ((uint)globalY / Simulator.DefaultRegionSizeY) * Simulator.DefaultRegionSizeY;
localX = globalX - (float)x; localX = globalX - (float)x;
localY = globalY - (float)y; localY = globalY - (float)y;
return Utils.UIntsToLong(x, y); return Utils.UIntsToLong(x, y);

View file

@ -196,7 +196,8 @@ namespace OpenMetaverse.ImportExport
Client.Inventory.RequestFetchInventory(reply["new_inventory_item"].AsUUID(), Client.Self.AgentID); Client.Inventory.RequestFetchInventory(reply["new_inventory_item"].AsUUID(), Client.Self.AgentID);
} }
} }
if (callback != null) callback(contents);
callback?.Invoke(contents);
})); }));
} }
})); }));

View file

@ -48,8 +48,7 @@ namespace LibreMetaverse
Client = client; Client = client;
} }
public bool IsAvailable => (Client.Network.CurrentSim.Caps != null && public bool IsAvailable => (Client.Network.CurrentSim.Caps?.CapabilityURI(INVENTORY_CAP_NAME) != null);
Client.Network.CurrentSim.Caps.CapabilityURI(INVENTORY_CAP_NAME) != null);
public async Task CreateInventory(UUID parentUuid, OSD newInventory, bool createLink, InventoryManager.ItemCreatedCallback callback) public async Task CreateInventory(UUID parentUuid, OSD newInventory, bool createLink, InventoryManager.ItemCreatedCallback callback)
{ {

View file

@ -582,8 +582,7 @@ namespace OpenMetaverse
} }
Uri cap; Uri cap;
if (Client.Network.CurrentSim.Caps != null && if ((cap = Client.Network.CurrentSim?.Caps?.CapabilityURI("FetchInventory2")) != null)
(cap = Client.Network.CurrentSim.Caps.CapabilityURI("FetchInventory2")) != null)
{ {
OSDMap payload = new OSDMap { ["agent_id"] = Client.Self.AgentID }; OSDMap payload = new OSDMap { ["agent_id"] = Client.Self.AgentID };

View file

@ -11,7 +11,7 @@
<IncludeSymbols>true</IncludeSymbols> <IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat> <SymbolPackageFormat>snupkg</SymbolPackageFormat>
<NoWarn>0419,1574,1591</NoWarn> <NoWarn>0419,1574,1591</NoWarn>
<TargetFrameworks>net48;netstandard2.1;net6.0;net7.0</TargetFrameworks> <TargetFrameworks>net7.0</TargetFrameworks>
<Platforms>x64;x86;AnyCPU</Platforms> <Platforms>x64;x86;AnyCPU</Platforms>
<OutputPath>..\bin\</OutputPath> <OutputPath>..\bin\</OutputPath>
</PropertyGroup> </PropertyGroup>
@ -44,8 +44,8 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="log4net" Version="2.0.15" /> <PackageReference Include="log4net" Version="2.0.15" />
<PackageReference Include="Microsoft.Extensions.ObjectPool" Version="7.0.0" /> <PackageReference Include="Microsoft.Extensions.ObjectPool" Version="7.0.9" />
<PackageReference Include="OggVorbisEncoder" Version="1.2.1" /> <PackageReference Include="OggVorbisEncoder" Version="1.2.2" />
<PackageReference Include="OpenJpegDotNet-LMV" Version="2.4.0.5" /> <PackageReference Include="OpenJpegDotNet-LMV" Version="2.4.0.5" />
<PackageReference Include="System.Drawing.Common" Version="7.0.0" /> <PackageReference Include="System.Drawing.Common" Version="7.0.0" />
<PackageReference Include="System.Net.Http" Version="4.3.4" /> <PackageReference Include="System.Net.Http" Version="4.3.4" />

View file

@ -369,6 +369,8 @@ namespace OpenMetaverse
public int CircuitCode; public int CircuitCode;
public uint RegionX; public uint RegionX;
public uint RegionY; public uint RegionY;
public uint RegionSizeX;
public uint RegionSizeY;
public ushort SimPort; public ushort SimPort;
public IPAddress SimIP; public IPAddress SimIP;
public string SeedCapability; public string SeedCapability;
@ -488,6 +490,9 @@ namespace OpenMetaverse
CircuitCode = (int)ParseUInt("circuit_code", reply); CircuitCode = (int)ParseUInt("circuit_code", reply);
RegionX = ParseUInt("region_x", reply); RegionX = ParseUInt("region_x", reply);
RegionY = ParseUInt("region_y", 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); SimPort = (ushort)ParseUInt("sim_port", reply);
var simIP = ParseString("sim_ip", reply); var simIP = ParseString("sim_ip", reply);
IPAddress.TryParse(simIP, out SimIP); IPAddress.TryParse(simIP, out SimIP);
@ -693,6 +698,9 @@ namespace OpenMetaverse
CircuitCode = (int)ParseUInt("circuit_code", reply); CircuitCode = (int)ParseUInt("circuit_code", reply);
RegionX = ParseUInt("region_x", reply); RegionX = ParseUInt("region_x", reply);
RegionY = ParseUInt("region_y", 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); SimPort = (ushort)ParseUInt("sim_port", reply);
var simIP = ParseString("sim_ip", reply); var simIP = ParseString("sim_ip", reply);
IPAddress.TryParse(simIP, out SimIP); IPAddress.TryParse(simIP, out SimIP);
@ -1691,7 +1699,7 @@ namespace OpenMetaverse
var handle = Utils.UIntsToLong(regionX, regionY); var handle = Utils.UIntsToLong(regionX, regionY);
// Connect to the sim given in the login reply // 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 // Request the economy data right after login
SendPacket(new EconomyDataRequestPacket()); SendPacket(new EconomyDataRequestPacket());

View file

@ -1,4 +1,4 @@
/* /*
* Copyright (c) 2006-2016, openmetaverse.co * Copyright (c) 2006-2016, openmetaverse.co
* Copyright (c) 2021-2022, Sjofn LLC * Copyright (c) 2021-2022, Sjofn LLC
* All rights reserved. * All rights reserved.
@ -61,6 +61,10 @@ namespace OpenMetaverse.Messages.Linden
/// <summary>Status flags indicating the state of the Agent upon arrival, Flying, etc.</summary> /// <summary>Status flags indicating the state of the Agent upon arrival, Flying, etc.</summary>
public TeleportFlags Flags; public TeleportFlags Flags;
/// <summary> The size of the region teleporting into </summary>
public uint RegionSizeX;
public uint RegionSizeY;
/// <summary> /// <summary>
/// Serialize the object /// Serialize the object
/// </summary> /// </summary>
@ -71,7 +75,7 @@ namespace OpenMetaverse.Messages.Linden
OSDArray infoArray = new OSDArray(1); OSDArray infoArray = new OSDArray(1);
OSDMap info = new OSDMap(8) OSDMap info = new OSDMap(10)
{ {
{"AgentID", OSD.FromUUID(AgentID)}, {"AgentID", OSD.FromUUID(AgentID)},
{"LocationID", OSD.FromInteger(LocationID)}, {"LocationID", OSD.FromInteger(LocationID)},
@ -80,7 +84,9 @@ namespace OpenMetaverse.Messages.Linden
{"SimAccess", OSD.FromInteger((byte) SimAccess)}, {"SimAccess", OSD.FromInteger((byte) SimAccess)},
{"SimIP", MessageUtils.FromIP(IP)}, {"SimIP", MessageUtils.FromIP(IP)},
{"SimPort", OSD.FromInteger(Port)}, {"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 // Unused by the client
@ -108,6 +114,8 @@ namespace OpenMetaverse.Messages.Linden
IP = MessageUtils.ToIP(blockMap["SimIP"]); IP = MessageUtils.ToIP(blockMap["SimIP"]);
Port = blockMap["SimPort"].AsInteger(); Port = blockMap["SimPort"].AsInteger();
Flags = (TeleportFlags)blockMap["TeleportFlags"].AsUInteger(); 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 Uri SeedCapability;
public IPAddress IP; public IPAddress IP;
public int Port; public int Port;
public uint RegionSizeX;
public uint RegionSizeY;
/// <summary> /// <summary>
/// Serialize the object /// Serialize the object
@ -190,12 +200,14 @@ namespace OpenMetaverse.Messages.Linden
map["AgentData"] = agentDataArray; map["AgentData"] = agentDataArray;
OSDArray regionDataArray = new OSDArray(1); OSDArray regionDataArray = new OSDArray(1);
OSDMap regionDataMap = new OSDMap(4) OSDMap regionDataMap = new OSDMap(6)
{ {
["RegionHandle"] = OSD.FromULong(RegionHandle), ["RegionHandle"] = OSD.FromULong(RegionHandle),
["SeedCapability"] = OSD.FromUri(SeedCapability), ["SeedCapability"] = OSD.FromUri(SeedCapability),
["SimIP"] = MessageUtils.FromIP(IP), ["SimIP"] = MessageUtils.FromIP(IP),
["SimPort"] = OSD.FromInteger(Port) ["SimPort"] = OSD.FromInteger(Port),
["RegionSizeX"] = OSD.FromUInteger(RegionSizeX),
["RegionSizeY"] = OSD.FromUInteger(RegionSizeY)
}; };
regionDataArray.Add(regionDataMap); regionDataArray.Add(regionDataMap);
map["RegionData"] = regionDataArray; map["RegionData"] = regionDataArray;
@ -222,6 +234,8 @@ namespace OpenMetaverse.Messages.Linden
SeedCapability = regionDataMap["SeedCapability"].AsUri(); SeedCapability = regionDataMap["SeedCapability"].AsUri();
IP = MessageUtils.ToIP(regionDataMap["SimIP"]); IP = MessageUtils.ToIP(regionDataMap["SimIP"]);
Port = regionDataMap["SimPort"].AsInteger(); 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 ulong RegionHandle;
public IPAddress IP; public IPAddress IP;
public int Port; public int Port;
public uint RegionSizeX;
public uint RegionSizeY;
} }
public SimulatorInfoBlock[] Simulators; public SimulatorInfoBlock[] Simulators;
@ -247,11 +263,13 @@ namespace OpenMetaverse.Messages.Linden
OSDArray array = new OSDArray(Simulators.Length); OSDArray array = new OSDArray(Simulators.Length);
foreach (SimulatorInfoBlock block in Simulators) foreach (SimulatorInfoBlock block in Simulators)
{ {
OSDMap blockMap = new OSDMap(3) OSDMap blockMap = new OSDMap(5)
{ {
["Handle"] = OSD.FromULong(block.RegionHandle), ["Handle"] = OSD.FromULong(block.RegionHandle),
["IP"] = MessageUtils.FromIP(block.IP), ["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); array.Add(blockMap);
} }
@ -277,7 +295,9 @@ namespace OpenMetaverse.Messages.Linden
{ {
RegionHandle = blockMap["Handle"].AsULong(), RegionHandle = blockMap["Handle"].AsULong(),
IP = MessageUtils.ToIP(blockMap["IP"]), 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; Simulators[i] = block;
} }
@ -5395,7 +5415,7 @@ namespace OpenMetaverse.Messages.Linden
} }
/// <summary> /// <summary>
/// Message recieved in response to request to change display name /// Message received in response to request to change display name
/// </summary> /// </summary>
public class SetDisplayNameReplyMessage : IMessage public class SetDisplayNameReplyMessage : IMessage
{ {
@ -5434,7 +5454,7 @@ namespace OpenMetaverse.Messages.Linden
} }
/// <summary> /// <summary>
/// Message recieved when someone nearby changes their display name /// Message received when someone nearby changes their display name
/// </summary> /// </summary>
public class DisplayNameUpdateMessage : IMessage public class DisplayNameUpdateMessage : IMessage
{ {

View file

@ -36,7 +36,7 @@ using OpenMetaverse.Interfaces;
using OpenMetaverse.Messages.Linden; using OpenMetaverse.Messages.Linden;
namespace OpenMetaverse namespace OpenMetaverse
{ {
/// <summary> /// <summary>
/// NetworkManager is responsible for managing the network layer of /// NetworkManager is responsible for managing the network layer of
/// OpenMetaverse. It tracks all the server connections, serializes /// 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); Logger.DebugLog("simulator object was null, using first found connected simulator", Client);
simulator = Client.Network.Simulators[0]; simulator = Client.Network.Simulators[0];
} }
if (simulator != null) if (simulator != null)
{ {
simulator.SendPacket(packet); simulator.SendPacket(packet);
} }
else else
{ {
NetworkInvaildWarning("simulator", "SendPacket"); NetworkInvaildWarning("simulator", "SendPacket");
} }
} }
@ -479,34 +479,34 @@ namespace OpenMetaverse
/// </summary> /// </summary>
/// <param name="packet">Incoming packet to process</param> /// <param name="packet">Incoming packet to process</param>
public void EnqueueIncoming(IncomingPacket packet) public void EnqueueIncoming(IncomingPacket packet)
{ {
if (_packetInbox != null) if (_packetInbox != null)
{ {
if (_packetInbox.Writer.TryWrite(packet)) if (_packetInbox.Writer.TryWrite(packet))
Interlocked.Increment(ref _packetInboxCount); Interlocked.Increment(ref _packetInboxCount);
}
else
{
NetworkInvaildWarning("_packetInbox", "EnqueueIncoming");
} }
} else
{
NetworkInvaildWarning("_packetInbox", "EnqueueIncoming");
}
}
/// <summary> /// <summary>
/// adds a debug message when you try to access a network item /// adds a debug message when you try to access a network item
/// while they are still null /// while they are still null
/// </summary> /// </summary>
/// <param name="source">what</param> /// <param name="source">what</param>
/// <param name="function">where</param> /// <param name="function">where</param>
protected void NetworkInvaildWarning(string source,string function) protected void NetworkInvaildWarning(string source,string function)
{ {
long now = DateTimeOffset.Now.ToUnixTimeSeconds(); long now = DateTimeOffset.Now.ToUnixTimeSeconds();
long dif = lastpacketwarning - now; long dif = lastpacketwarning - now;
if (dif > 10) if (dif > 10)
{ {
lastpacketwarning = now; lastpacketwarning = now;
Logger.Log(source+" is null (Are we disconnected?) - from: "+ function, Logger.Log(source+" is null (Are we disconnected?) - from: " + function,
Helpers.LogLevel.Debug); Helpers.LogLevel.Debug);
} }
} }
/// <summary> /// <summary>
@ -515,17 +515,30 @@ namespace OpenMetaverse
/// <param name="packet">Incoming packet to process</param> /// <param name="packet">Incoming packet to process</param>
public void EnqueueOutgoing(OutgoingPacket packet) public void EnqueueOutgoing(OutgoingPacket packet)
{ {
if (_packetOutbox != null) if (_packetOutbox != null)
{ {
if (_packetOutbox.Writer.TryWrite(packet)) if (_packetOutbox.Writer.TryWrite(packet))
Interlocked.Increment(ref _packetOutboxCount); Interlocked.Increment(ref _packetOutboxCount);
} }
else else
{ {
NetworkInvaildWarning("_packetOutbox", "EnqueueOutgoing"); NetworkInvaildWarning("_packetOutbox", "EnqueueOutgoing");
} }
} }
/// <summary>
/// Connect to simulator assuming legacy region size
/// </summary>
/// <param name="ip">IP address to connect to</param>
/// <param name="port">Port to connect to</param>
/// <param name="handle"></param>
/// <param name="setDefault"></param>
/// <param name="seedcaps"></param>
/// <returns></returns>
public Simulator Connect(IPAddress ip, ushort port, ulong handle, bool setDefault, Uri seedcaps)
{
return Connect(ip, port, handle, setDefault, seedcaps, Simulator.DefaultRegionSizeX, Simulator.DefaultRegionSizeY);
}
/// <summary> /// <summary>
/// Connect to a simulator /// Connect to a simulator
/// </summary> /// </summary>
@ -537,13 +550,26 @@ namespace OpenMetaverse
/// connection, use this if the avatar is moving in to this simulator</param> /// connection, use this if the avatar is moving in to this simulator</param>
/// <param name="seedcaps">URL of the capabilities server to use for /// <param name="seedcaps">URL of the capabilities server to use for
/// this sim connection</param> /// this sim connection</param>
/// <param name="sizeX">Size of the region in X meters</param>
/// <param name="sizeY">Size of the region in Y meters</param>
/// <returns>A Simulator object on success, otherwise null</returns> /// <returns>A Simulator object on success, otherwise null</returns>
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); IPEndPoint endPoint = new IPEndPoint(ip, port);
return Connect(endPoint, handle, setDefault, seedcaps); return Connect(endPoint, handle, setDefault, seedcaps, sizeX, sizeY);
} }
/// <summary>
/// Connect to simulator assuming legacy region size
/// </summary>
/// <param name="endPoint"></param>
/// <param name="handle"></param>
/// <param name="setDefault"></param>
/// <param name="seedcaps"></param>
/// <returns></returns>
public Simulator Connect(IPEndPoint endPoint, ulong handle, bool setDefault, Uri seedcaps) {
return Connect(endPoint, handle, setDefault, seedcaps, Simulator.DefaultRegionSizeX, Simulator.DefaultRegionSizeY);
}
/// <summary> /// <summary>
/// Connect to a simulator /// Connect to a simulator
/// </summary> /// </summary>
@ -554,15 +580,17 @@ namespace OpenMetaverse
/// connection, use this if the avatar is moving in to this simulator</param> /// connection, use this if the avatar is moving in to this simulator</param>
/// <param name="seedcaps">URL of the capabilities server to use for /// <param name="seedcaps">URL of the capabilities server to use for
/// this sim connection</param> /// this sim connection</param>
/// <param name="sizeX">Size of the region in X meters</param>
/// <param name="sizeY">Size of the region in Y meters</param>
/// <returns>A Simulator object on success, otherwise null</returns> /// <returns>A Simulator object on success, otherwise null</returns>
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); Simulator simulator = FindSimulator(endPoint);
if (simulator == null) if (simulator == null)
{ {
// We're not tracking this sim, create a new Simulator object // 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 // Immediately add this simulator to the list of current sims. It will be removed if the
// connection fails // connection fails
@ -639,7 +667,7 @@ namespace OpenMetaverse
lock (Simulators) lock (Simulators)
{ {
Simulators.Remove(simulator); Simulators.Remove(simulator);
} }
return null; return null;
} }
@ -682,13 +710,13 @@ namespace OpenMetaverse
// Otherwise we fire it manually with a NetworkTimeout type after LOGOUT_TIMEOUT // Otherwise we fire it manually with a NetworkTimeout type after LOGOUT_TIMEOUT
System.Timers.Timer timeout = new System.Timers.Timer(); System.Timers.Timer timeout = new System.Timers.Timer();
EventHandler<LoggedOutEventArgs> callback = delegate void Callback(object sender, LoggedOutEventArgs e)
{ {
Shutdown(DisconnectType.ClientInitiated); Shutdown(DisconnectType.ClientInitiated);
timeout.Stop(); timeout.Stop();
}; }
LoggedOut += callback; LoggedOut += Callback;
timeout.Interval = Client.Settings.LOGOUT_TIMEOUT; timeout.Interval = Client.Settings.LOGOUT_TIMEOUT;
timeout.Elapsed += delegate timeout.Elapsed += delegate
@ -702,7 +730,7 @@ namespace OpenMetaverse
// Send the packet requesting a clean logout // Send the packet requesting a clean logout
RequestLogout(); RequestLogout();
LoggedOut -= callback; LoggedOut -= Callback;
} }
/// <summary> /// <summary>
@ -713,9 +741,13 @@ namespace OpenMetaverse
public void Logout() public void Logout()
{ {
AutoResetEvent logoutEvent = new AutoResetEvent(false); AutoResetEvent logoutEvent = new AutoResetEvent(false);
EventHandler<LoggedOutEventArgs> callback = delegate { logoutEvent.Set(); };
LoggedOut += callback; void Callback(object sender, LoggedOutEventArgs e)
{
logoutEvent.Set();
}
LoggedOut += Callback;
// Send the packet requesting a clean logout // Send the packet requesting a clean logout
RequestLogout(); RequestLogout();
@ -724,9 +756,11 @@ namespace OpenMetaverse
// will be fired in the callback. Otherwise we fire it manually with // will be fired in the callback. Otherwise we fire it manually with
// a NetworkTimeout type // a NetworkTimeout type
if (!logoutEvent.WaitOne(Client.Settings.LOGOUT_TIMEOUT, false)) if (!logoutEvent.WaitOne(Client.Settings.LOGOUT_TIMEOUT, false))
{
Shutdown(DisconnectType.NetworkTimeout); Shutdown(DisconnectType.NetworkTimeout);
}
LoggedOut -= callback; LoggedOut -= Callback;
} }
/// <summary> /// <summary>
@ -787,20 +821,26 @@ namespace OpenMetaverse
simulatorsCount = Simulators.Count; simulatorsCount = Simulators.Count;
} }
if (simulatorsCount == 0) Shutdown(DisconnectType.SimShutdown); if (simulatorsCount == 0)
{
Shutdown(DisconnectType.SimShutdown, $"You have disconnected from {simulator.Name}.");
}
} }
else else
{ {
NetworkInvaildWarning("simulator", "DisconnectSim"); NetworkInvaildWarning("simulator", "DisconnectSim");
} }
} }
/// <summary> /// <summary>
/// Shutdown will disconnect all the sims except for the current sim /// This method disconnects Client from all simulators leaving CurrentSim
/// first, and then kill the connection to CurrentSim. This should only /// last to disconnect.
/// be called if the logout process times out on <code>RequestLogout</code>
/// </summary> /// </summary>
/// <remarks>
/// This should only be called if the logout process times out on
/// <code>RequestLogout</code>
/// </remarks>
/// <param name="type">Type of shutdown</param> /// <param name="type">Type of shutdown</param>
public void Shutdown(DisconnectType type) public void Shutdown(DisconnectType type)
{ {
@ -808,10 +848,13 @@ namespace OpenMetaverse
} }
/// <summary> /// <summary>
/// Shutdown will disconnect all the sims except for the current sim /// This method disconnects Client from all simulators leaving CurrentSim
/// first, and then kill the connection to CurrentSim. This should only /// last to disconnect.
/// be called if the logout process times out on <code>RequestLogout</code>
/// </summary> /// </summary>
/// <remarks>
/// This should only be called if the logout process times out on
/// <code>RequestLogout</code>
/// </remarks>
/// <param name="type">Type of shutdown</param> /// <param name="type">Type of shutdown</param>
/// <param name="message">Shutdown message</param> /// <param name="message">Shutdown message</param>
public void Shutdown(DisconnectType type, string message) public void Shutdown(DisconnectType type, string message)
@ -824,17 +867,14 @@ namespace OpenMetaverse
lock (Simulators) lock (Simulators)
{ {
// Disconnect all simulators except the current one // 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) sim.Disconnect(sendCloseCircuit);
{
t.Disconnect(sendCloseCircuit);
// Fire the SimDisconnected event if a handler is registered // Fire the SimDisconnected event if a handler is registered
if (m_SimDisconnected != null) if (m_SimDisconnected != null)
{ {
OnSimDisconnected(new SimDisconnectedEventArgs(t, type)); OnSimDisconnected(new SimDisconnectedEventArgs(sim, type));
}
} }
} }
@ -843,7 +883,7 @@ namespace OpenMetaverse
if (CurrentSim != null) if (CurrentSim != null)
{ {
// Kill the connection to the curent simulator // Kill the connection to the current simulator
CurrentSim.Disconnect(sendCloseCircuit); CurrentSim.Disconnect(sendCloseCircuit);
// Fire the SimDisconnected event if a handler is registered // Fire the SimDisconnected event if a handler is registered
@ -881,10 +921,9 @@ namespace OpenMetaverse
{ {
lock (Simulators) lock (Simulators)
{ {
foreach (Simulator t in Simulators) foreach (var sim in Simulators.Where(t => t.IPEndPoint.Equals(endPoint)))
{ {
if (t.IPEndPoint.Equals(endPoint)) return sim;
return t;
} }
} }
@ -913,73 +952,73 @@ namespace OpenMetaverse
private async Task OutgoingPacketHandler() private async Task OutgoingPacketHandler()
{ {
if (_packetOutbox != null) if (_packetOutbox != null)
{ {
var reader = _packetOutbox.Reader; var reader = _packetOutbox.Reader;
// FIXME: This is kind of ridiculous. Port the HTB code from Simian over ASAP! // FIXME: This is kind of ridiculous. Port the HTB code from Simian over ASAP!
var stopwatch = new System.Diagnostics.Stopwatch(); var stopwatch = new System.Diagnostics.Stopwatch();
while (await reader.WaitToReadAsync() && Connected) while (await reader.WaitToReadAsync() && Connected)
{ {
while (reader.TryRead(out var outgoingPacket)) while (reader.TryRead(out var outgoingPacket))
{ {
Interlocked.Decrement(ref _packetOutboxCount); Interlocked.Decrement(ref _packetOutboxCount);
var simulator = outgoingPacket.Simulator; var simulator = outgoingPacket.Simulator;
stopwatch.Stop(); stopwatch.Stop();
if (stopwatch.ElapsedMilliseconds < 10) if (stopwatch.ElapsedMilliseconds < 10)
{ {
//Logger.DebugLog(String.Format("Rate limiting, last packet was {0}ms ago", ms)); //Logger.DebugLog(String.Format("Rate limiting, last packet was {0}ms ago", ms));
Thread.Sleep(10 - (int)stopwatch.ElapsedMilliseconds); Thread.Sleep(10 - (int)stopwatch.ElapsedMilliseconds);
} }
simulator.SendPacketFinal(outgoingPacket); simulator.SendPacketFinal(outgoingPacket);
stopwatch.Start(); stopwatch.Start();
} }
} }
} }
else else
{ {
NetworkInvaildWarning("_packetOutbox", "OutgoingPacketHandler"); NetworkInvaildWarning("_packetOutbox", "OutgoingPacketHandler");
} }
} }
private async Task IncomingPacketHandler() private async Task IncomingPacketHandler()
{ {
if (_packetInbox != null) if (_packetInbox != null)
{ {
var reader = _packetInbox.Reader; var reader = _packetInbox.Reader;
while (await reader.WaitToReadAsync() && Connected) while (await reader.WaitToReadAsync() && Connected)
{ {
while (reader.TryRead(out var incomingPacket)) while (reader.TryRead(out var incomingPacket))
{ {
Interlocked.Decrement(ref _packetInboxCount); Interlocked.Decrement(ref _packetInboxCount);
var packet = incomingPacket.Packet; var packet = incomingPacket.Packet;
var simulator = incomingPacket.Simulator; var simulator = incomingPacket.Simulator;
if (packet == null) continue; if (packet == null) continue;
// Skip blacklisted packets // Skip blacklisted packets
if (UDPBlacklist.Contains(packet.Type.ToString())) if (UDPBlacklist.Contains(packet.Type.ToString()))
{ {
Logger.Log($"Discarding Blacklisted packet {packet.Type} from {simulator.IPEndPoint}", Logger.Log($"Discarding Blacklisted packet {packet.Type} from {simulator.IPEndPoint}",
Helpers.LogLevel.Warning); Helpers.LogLevel.Warning);
return; return;
} }
// Fire the callback(s), if any // Fire the callback(s), if any
PacketEvents.RaiseEvent(packet.Type, packet, simulator); PacketEvents.RaiseEvent(packet.Type, packet, simulator);
} }
} }
} }
else else
{ {
NetworkInvaildWarning("_packetInbox", "IncomingPacketHandler"); NetworkInvaildWarning("_packetInbox", "IncomingPacketHandler");
} }
} }
@ -1277,10 +1316,10 @@ namespace OpenMetaverse
if (FindSimulator(endPoint) != null) return; 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}", Logger.Log($"Unable to connect to new sim {ip}:{port}",
Helpers.LogLevel.Error, Client); Helpers.LogLevel.Error, Client);
} }
} }
} }

View file

@ -198,8 +198,7 @@ namespace OpenMetaverse
protected virtual void OnObjectProperties(ObjectPropertiesEventArgs e) protected virtual void OnObjectProperties(ObjectPropertiesEventArgs e)
{ {
EventHandler<ObjectPropertiesEventArgs> handler = m_ObjectProperties; EventHandler<ObjectPropertiesEventArgs> handler = m_ObjectProperties;
if (handler != null) handler?.Invoke(this, e);
handler(this, e);
} }
/// <summary>Thread sync lock object</summary> /// <summary>Thread sync lock object</summary>
@ -224,8 +223,7 @@ namespace OpenMetaverse
protected virtual void OnObjectPropertiesUpdated(ObjectPropertiesUpdatedEventArgs e) protected virtual void OnObjectPropertiesUpdated(ObjectPropertiesUpdatedEventArgs e)
{ {
EventHandler<ObjectPropertiesUpdatedEventArgs> handler = m_ObjectPropertiesUpdated; EventHandler<ObjectPropertiesUpdatedEventArgs> handler = m_ObjectPropertiesUpdated;
if (handler != null) handler?.Invoke(this, e);
handler(this, e);
} }
/// <summary>Thread sync lock object</summary> /// <summary>Thread sync lock object</summary>
@ -250,8 +248,7 @@ namespace OpenMetaverse
protected virtual void OnObjectPropertiesFamily(ObjectPropertiesFamilyEventArgs e) protected virtual void OnObjectPropertiesFamily(ObjectPropertiesFamilyEventArgs e)
{ {
EventHandler<ObjectPropertiesFamilyEventArgs> handler = m_ObjectPropertiesFamily; EventHandler<ObjectPropertiesFamilyEventArgs> handler = m_ObjectPropertiesFamily;
if (handler != null) handler?.Invoke(this, e);
handler(this, e);
} }
/// <summary>Thread sync lock object</summary> /// <summary>Thread sync lock object</summary>
@ -278,8 +275,7 @@ namespace OpenMetaverse
protected virtual void OnAvatarUpdate(AvatarUpdateEventArgs e) protected virtual void OnAvatarUpdate(AvatarUpdateEventArgs e)
{ {
EventHandler<AvatarUpdateEventArgs> handler = m_AvatarUpdate; EventHandler<AvatarUpdateEventArgs> handler = m_AvatarUpdate;
if (handler != null) handler?.Invoke(this, e);
handler(this, e);
} }
/// <summary> /// <summary>
/// Raises the ParticleUpdate Event /// Raises the ParticleUpdate Event
@ -288,8 +284,7 @@ namespace OpenMetaverse
/// the data sent from the simulator</param> /// the data sent from the simulator</param>
protected virtual void OnParticleUpdate(ParticleUpdateEventArgs e) { protected virtual void OnParticleUpdate(ParticleUpdateEventArgs e) {
EventHandler<ParticleUpdateEventArgs> handler = m_ParticleUpdate; EventHandler<ParticleUpdateEventArgs> handler = m_ParticleUpdate;
if (handler != null) handler?.Invoke(this, e);
handler(this, e);
} }
/// <summary>Thread sync lock object</summary> /// <summary>Thread sync lock object</summary>
@ -337,8 +332,7 @@ namespace OpenMetaverse
protected virtual void OnObjectDataBlockUpdate(ObjectDataBlockUpdateEventArgs e) protected virtual void OnObjectDataBlockUpdate(ObjectDataBlockUpdateEventArgs e)
{ {
EventHandler<ObjectDataBlockUpdateEventArgs> handler = m_ObjectDataBlockUpdate; EventHandler<ObjectDataBlockUpdateEventArgs> handler = m_ObjectDataBlockUpdate;
if (handler != null) handler?.Invoke(this, e);
handler(this, e);
} }
/// <summary>Thread sync lock object</summary> /// <summary>Thread sync lock object</summary>
@ -363,8 +357,7 @@ namespace OpenMetaverse
protected virtual void OnKillObject(KillObjectEventArgs e) protected virtual void OnKillObject(KillObjectEventArgs e)
{ {
EventHandler<KillObjectEventArgs> handler = m_KillObject; EventHandler<KillObjectEventArgs> handler = m_KillObject;
if (handler != null) handler?.Invoke(this, e);
handler(this, e);
} }
/// <summary>Thread sync lock object</summary> /// <summary>Thread sync lock object</summary>
@ -389,8 +382,7 @@ namespace OpenMetaverse
protected virtual void OnKillObjects(KillObjectsEventArgs e) protected virtual void OnKillObjects(KillObjectsEventArgs e)
{ {
EventHandler<KillObjectsEventArgs> handler = m_KillObjects; EventHandler<KillObjectsEventArgs> handler = m_KillObjects;
if (handler != null) handler?.Invoke(this, e);
handler(this, e);
} }
/// <summary>Thread sync lock object</summary> /// <summary>Thread sync lock object</summary>
@ -415,8 +407,7 @@ namespace OpenMetaverse
protected virtual void OnAvatarSitChanged(AvatarSitChangedEventArgs e) protected virtual void OnAvatarSitChanged(AvatarSitChangedEventArgs e)
{ {
EventHandler<AvatarSitChangedEventArgs> handler = m_AvatarSitChanged; EventHandler<AvatarSitChangedEventArgs> handler = m_AvatarSitChanged;
if (handler != null) handler?.Invoke(this, e);
handler(this, e);
} }
/// <summary>Thread sync lock object</summary> /// <summary>Thread sync lock object</summary>
@ -441,8 +432,7 @@ namespace OpenMetaverse
protected virtual void OnPayPriceReply(PayPriceReplyEventArgs e) protected virtual void OnPayPriceReply(PayPriceReplyEventArgs e)
{ {
EventHandler<PayPriceReplyEventArgs> handler = m_PayPriceReply; EventHandler<PayPriceReplyEventArgs> handler = m_PayPriceReply;
if (handler != null) handler?.Invoke(this, e);
handler(this, e);
} }
/// <summary>Thread sync lock object</summary> /// <summary>Thread sync lock object</summary>
@ -475,8 +465,7 @@ namespace OpenMetaverse
protected virtual void OnPhysicsProperties(PhysicsPropertiesEventArgs e) protected virtual void OnPhysicsProperties(PhysicsPropertiesEventArgs e)
{ {
EventHandler<PhysicsPropertiesEventArgs> handler = m_PhysicsProperties; EventHandler<PhysicsPropertiesEventArgs> handler = m_PhysicsProperties;
if (handler != null) handler?.Invoke(this, e);
handler(this, e);
} }
/// <summary>Thread sync lock object</summary> /// <summary>Thread sync lock object</summary>
@ -2611,8 +2600,7 @@ namespace OpenMetaverse
#region Raise Events #region Raise Events
EventHandler<PrimEventArgs> handler = m_ObjectUpdate; EventHandler<PrimEventArgs> handler = m_ObjectUpdate;
if (handler != null) handler?.Invoke(this, new PrimEventArgs(simulator, prim, update.RegionData.TimeDilation, isNew, prim.IsAttachment));
handler(this, new PrimEventArgs(simulator, prim, update.RegionData.TimeDilation, isNew, prim.IsAttachment));
#endregion #endregion
} }
@ -3310,10 +3298,7 @@ namespace OpenMetaverse
// Start the timer again. Use a minimum of a 50ms pause in between calculations // Start the timer again. Use a minimum of a 50ms pause in between calculations
int delay = Math.Max(50, Settings.INTERPOLATION_INTERVAL - elapsed); int delay = Math.Max(50, Settings.INTERPOLATION_INTERVAL - elapsed);
if (InterpolationTimer != null) InterpolationTimer?.Change(delay, Timeout.Infinite);
{
InterpolationTimer.Change(delay, Timeout.Infinite);
}
} }
} }

View file

@ -606,13 +606,12 @@ namespace OpenMetaverse
Media = new ParcelMedia(); Media = new ParcelMedia();
} }
/// <summary> public void Update(GridClient client)
/// Update the parcel (in the current sim) {
/// </summary> Update(client, client.Network.CurrentSim, false);
/// <param name="client">Client message originates from</param> }
/// <param name="wantReply">Whether we want the simulator to confirm
/// the update with a reply packet or not [default false]</param> public void Update(GridClient client, bool wantReply)
public void Update(GridClient client, bool wantReply = false)
{ {
Update(client, client.Network.CurrentSim, wantReply); Update(client, client.Network.CurrentSim, wantReply);
} }
@ -1688,7 +1687,17 @@ namespace OpenMetaverse
{ {
OSD res = null; OSD res = null;
await Client.HttpCapsClient.PostRequestAsync(cap, OSDFormat.Xml, msg.Serialize(), CancellationToken.None, 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) if (res is OSDMap result)
{ {

View file

@ -768,16 +768,11 @@ namespace OpenMetaverse
private void FromBytes(byte[] data, int pos, int length) private void FromBytes(byte[] data, int pos, int length)
{ {
DefaultTexture = new TextureEntryFace(null);
if (length < 16) if (length < 16)
{
// No TextureEntry to process // No TextureEntry to process
DefaultTexture = null;
return; return;
}
else
{
DefaultTexture = new TextureEntryFace(null);
}
uint bitfieldSize = 0; uint bitfieldSize = 0;
uint faceBits = 0; uint faceBits = 0;

View file

@ -217,10 +217,6 @@ namespace OpenMetaverse
/// server the full object info will automatically be requested</summary> /// server the full object info will automatically be requested</summary>
public bool ALWAYS_REQUEST_OBJECTS = true; public bool ALWAYS_REQUEST_OBJECTS = true;
/// <summary>Whether to establish connections to HTTP capabilities
/// servers for simulators</summary>
public bool ENABLE_CAPS = true;
/// <summary>Whether to decode sim stats</summary> /// <summary>Whether to decode sim stats</summary>
public bool ENABLE_SIMSTATS = true; 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 /// You will get no output on the console. This behavior can be overriden by creating
/// a logger configuration file for log4net /// a logger configuration file for log4net
/// </summary> /// </summary>
#if DEBUG
public static Helpers.LogLevel LOG_LEVEL = Helpers.LogLevel.Debug;
#else
public static Helpers.LogLevel LOG_LEVEL = Helpers.LogLevel.None; public static Helpers.LogLevel LOG_LEVEL = Helpers.LogLevel.None;
#endif
/// <summary>Attach avatar names to log messages</summary> /// <summary>Attach avatar names to log messages</summary>
public bool LOG_NAMES = true; public bool LOG_NAMES = true;

View file

@ -171,7 +171,7 @@ namespace OpenMetaverse
public int ConnectTime; public int ConnectTime;
/// <summary>Total number of packets that have been resent</summary> /// <summary>Total number of packets that have been resent</summary>
public int ResentPackets; public int ResentPackets;
/// <summary>Total number of resent packets recieved</summary> /// <summary>Total number of resent packets received</summary>
public int ReceivedResends; public int ReceivedResends;
/// <summary>Total number of pings sent to this simulator by this agent</summary> /// <summary>Total number of pings sent to this simulator by this agent</summary>
public int SentPings; public int SentPings;
@ -180,7 +180,7 @@ namespace OpenMetaverse
/// <summary> /// <summary>
/// Incoming bytes per second /// Incoming bytes per second
/// </summary> /// </summary>
/// <remarks>It would be nice to have this claculated on the fly, but /// <remarks>It would be nice to have this calculated on the fly, but
/// this is far, far easier</remarks> /// this is far, far easier</remarks>
public int IncomingBPS; public int IncomingBPS;
/// <summary> /// <summary>
@ -252,6 +252,11 @@ namespace OpenMetaverse
#endregion Structs #endregion Structs
#region Public Members #region Public Members
// Default legacy simulator/region size
public const uint DefaultRegionSizeX = 256;
public const uint DefaultRegionSizeY = 256;
/// <summary>A public reference to the client that this Simulator object is attached to</summary> /// <summary>A public reference to the client that this Simulator object is attached to</summary>
public GridClient Client; public GridClient Client;
/// <summary>A Unique Cache identifier for this simulator</summary> /// <summary>A Unique Cache identifier for this simulator</summary>
@ -260,6 +265,10 @@ namespace OpenMetaverse
public Caps Caps; public Caps Caps;
/// <summary>Unique identified for this region generated via it's coordinates on the world map</summary> /// <summary>Unique identified for this region generated via it's coordinates on the world map</summary>
public ulong Handle; public ulong Handle;
/// <summary>Simulator land size in X direction in meters</summary>
public uint SizeX;
/// <summary>Simulator land size in Y direction in meters</summary>
public uint SizeY;
/// <summary>The current version of software this simulator is running</summary> /// <summary>The current version of software this simulator is running</summary>
public string SimVersion = String.Empty; public string SimVersion = String.Empty;
/// <summary>Human readable name given to the simulator</summary> /// <summary>Human readable name given to the simulator</summary>
@ -497,10 +506,7 @@ namespace OpenMetaverse
public readonly SimulatorDataPool DataPool; public readonly SimulatorDataPool DataPool;
internal bool DownloadingParcelMap internal bool DownloadingParcelMap
{ {
get get => Client.Settings.POOL_PARCEL_DATA ? DataPool.DownloadingParcelMap : _DownloadingParcelMap;
{
return Client.Settings.POOL_PARCEL_DATA ? DataPool.DownloadingParcelMap : _DownloadingParcelMap;
}
set set
{ {
if (Client.Settings.POOL_PARCEL_DATA) DataPool.DownloadingParcelMap = value; if (Client.Settings.POOL_PARCEL_DATA) DataPool.DownloadingParcelMap = value;
@ -520,7 +526,7 @@ namespace OpenMetaverse
/// <param name="client">Reference to the <seealso cref="GridClient"/> object</param> /// <param name="client">Reference to the <seealso cref="GridClient"/> object</param>
/// <param name="address">IPEndPoint of the simulator</param> /// <param name="address">IPEndPoint of the simulator</param>
/// <param name="handle">Region handle for the simulator</param> /// <param name="handle">Region handle for the simulator</param>
public Simulator(GridClient client, IPEndPoint address, ulong handle) public Simulator(GridClient client, IPEndPoint address, ulong handle, uint sizeX = DefaultRegionSizeX, uint sizeY = DefaultRegionSizeY)
: base(address) : base(address)
{ {
Client = client; Client = client;
@ -532,14 +538,16 @@ namespace OpenMetaverse
Handle = handle; Handle = handle;
Network = Client.Network; Network = Client.Network;
SizeX = sizeX;
SizeY = sizeY;
PacketArchive = new IncomingPacketIDCollection(Settings.PACKET_ARCHIVE_SIZE); PacketArchive = new IncomingPacketIDCollection(Settings.PACKET_ARCHIVE_SIZE);
InBytes = new Queue<long>(Client.Settings.STATS_QUEUE_SIZE); InBytes = new Queue<long>(Client.Settings.STATS_QUEUE_SIZE);
OutBytes = new Queue<long>(Client.Settings.STATS_QUEUE_SIZE); OutBytes = new Queue<long>(Client.Settings.STATS_QUEUE_SIZE);
if (client.Settings.STORE_LAND_PATCHES) if (client.Settings.STORE_LAND_PATCHES)
{ {
Terrain = new TerrainPatch[16 * 16]; Terrain = new TerrainPatch[sizeX/16 * sizeY/16];
WindSpeeds = new Vector2[16 * 16]; WindSpeeds = new Vector2[sizeX/16 * sizeY/16];
} }
} }
@ -648,7 +656,7 @@ namespace OpenMetaverse
/// <summary> /// <summary>
/// Initiates connection to the simulator /// Initiates connection to the simulator
/// </summary> /// </summary>
/// <param name="waitForAck">Should we block until ack for this packet is recieved</param> /// <param name="waitForAck">Should we block until ack for this packet is received</param>
public void UseCircuitCode(bool waitForAck) public void UseCircuitCode(bool waitForAck)
{ {
// Send the UseCircuitCode packet to initiate the connection // Send the UseCircuitCode packet to initiate the connection
@ -690,17 +698,14 @@ namespace OpenMetaverse
Caps = null; Caps = null;
} }
if (Client.Settings.ENABLE_CAPS) // Connect to the CAPS system
if (seedcaps != null)
{ {
// Connect to the new CAPS system Caps = new Caps(this, seedcaps);
if (seedcaps != null) }
{ else
Caps = new Caps(this, seedcaps); {
} Logger.Log("Setting up a sim without valid http capabilities", Helpers.LogLevel.Error, Client);
else
{
Logger.Log("Setting up a sim without a valid capabilities server!", Helpers.LogLevel.Error, Client);
}
} }
} }
@ -709,6 +714,8 @@ namespace OpenMetaverse
/// </summary> /// </summary>
public void Disconnect(bool sendCloseCircuit) public void Disconnect(bool sendCloseCircuit)
{ {
DisconnectCandidate = false;
if (!connected) return; if (!connected) return;
connected = false; connected = false;
@ -795,7 +802,7 @@ namespace OpenMetaverse
/// <returns>True if the lookup was successful, otherwise false</returns> /// <returns>True if the lookup was successful, otherwise false</returns>
public bool TerrainHeightAtPoint(int x, int y, out float height) 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 patchX = x / 16;
int patchY = y / 16; int patchY = y / 16;
@ -1002,7 +1009,7 @@ namespace OpenMetaverse
/// <summary> /// <summary>
/// Returns Simulator Name as a String /// Returns Simulator Name as a String
/// </summary> /// </summary>
/// <returns></returns> /// <returns>Simulator name as String</returns>
public override string ToString() public override string ToString()
{ {
return !String.IsNullOrEmpty(Name) return !String.IsNullOrEmpty(Name)
@ -1059,8 +1066,8 @@ namespace OpenMetaverse
// Check if this packet came from the server we expected it to come from // Check if this packet came from the server we expected it to come from
if (!remoteEndPoint.Address.Equals(((IPEndPoint)buffer.RemoteEndPoint).Address)) if (!remoteEndPoint.Address.Equals(((IPEndPoint)buffer.RemoteEndPoint).Address))
{ {
Logger.Log("Received " + buffer.DataLength + " bytes of data from unrecognized source " + Logger.Log($"Received {buffer.DataLength} bytes of data from unrecognized source {(IPEndPoint)buffer.RemoteEndPoint}",
((IPEndPoint)buffer.RemoteEndPoint), Helpers.LogLevel.Warning, Client); Helpers.LogLevel.Warning, Client);
return; return;
} }
@ -1201,7 +1208,7 @@ namespace OpenMetaverse
/// <summary> /// <summary>
/// Sends out pending acknowledgements /// Sends out pending acknowledgments
/// </summary> /// </summary>
/// <returns>Number of ACKs sent</returns> /// <returns>Number of ACKs sent</returns>
private int SendAcks() private int SendAcks()

View file

@ -61,16 +61,27 @@ namespace OpenMetaverse
public int PatchIDs; public int PatchIDs;
public uint WordBits; public uint WordBits;
// true if PatchIDs are 32 bits and not 10
public bool LargeRegion { get; set; }
public int X public int X
{ {
get { return PatchIDs >> 5; } get { return PatchIDs >> (LargeRegion ? 16 : 5); }
set { PatchIDs += (value << 5); } set { PatchIDs += (value << (LargeRegion ? 16 : 5)); }
} }
public int Y public int Y
{ {
get { return PatchIDs & 0x1F; } get { return PatchIDs & (LargeRegion ? 0xffff : 0x1F); }
set { PatchIDs |= value & 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 /// simulator heightmap and an array of indices of patches to compress
/// </summary> /// </summary>
/// <param name="heightmap">A 256 * 256 array of floating point values /// <param name="heightmap">A 256 * 256 array of floating point values
/// specifying the height at each meter in the simulator</param> /// specifying the height at each meter in the simulator.
/// This can be larger if it is a varregion.</param>
/// <param name="patches">Array of indexes in the 16x16 grid of patches /// <param name="patches">Array of indexes in the 16x16 grid of patches
/// for this simulator. For example if 1 and 17 are specified, patches /// for this simulator. For example if 1 and 17 are specified, patches
/// x=1,y=0 and x=1,y=1 are sent</param> /// x=1,y=0 and x=1,y=1 are sent</param>
/// <returns></returns> /// <returns></returns>
public static LayerDataPacket CreateLandPacket(float[] heightmap, int[] patches) 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 TerrainPatch.GroupHeader header = new TerrainPatch.GroupHeader
{ {
@ -235,15 +250,19 @@ namespace OpenMetaverse
return layer; 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) if (patchData.Length != 16 * 16)
throw new ArgumentException("Patch data must be a 16x16 array"); throw new ArgumentException("Patch data must be a 16x16 array");
TerrainPatch.Header header = PrescanPatch(patchData); TerrainPatch.Header header = PrescanPatch(patchData);
header.LargeRegion = largeRegion;
header.QuantWBits = 136; header.QuantWBits = 136;
header.PatchIDs = (y & 0x1F); header.setPatchIDs(x, y);
header.PatchIDs += (x << 5);
// NOTE: No idea what prequant and postquant should be or what they do // NOTE: No idea what prequant and postquant should be or what they do
int[] patch = CompressPatch(patchData, header, 10); int[] patch = CompressPatch(patchData, header, 10);
@ -252,14 +271,18 @@ namespace OpenMetaverse
} }
public static void CreatePatch(BitPack output, float[,] patchData, int x, int y) 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) if (patchData.Length != 16 * 16)
throw new ArgumentException("Patch data must be a 16x16 array"); throw new ArgumentException("Patch data must be a 16x16 array");
var header = PrescanPatch(patchData); var header = PrescanPatch(patchData);
header.LargeRegion = largeRegion;
header.QuantWBits = 136; header.QuantWBits = 136;
header.PatchIDs = (y & 0x1F); header.setPatchIDs(x, y);
header.PatchIDs += (x << 5);
// NOTE: No idea what prequant and postquant should be or what they do // NOTE: No idea what prequant and postquant should be or what they do
int[] patch = CompressPatch(patchData, header, 10); int[] patch = CompressPatch(patchData, header, 10);
@ -278,6 +301,10 @@ namespace OpenMetaverse
/// <param name="y">Y offset of the patch to create, valid values are /// <param name="y">Y offset of the patch to create, valid values are
/// from 0 to 15</param> /// from 0 to 15</param>
public static void CreatePatchFromHeightmap(BitPack output, float[] heightmap, int x, int y) 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) if (heightmap.Length != 256 * 256)
throw new ArgumentException("Heightmap data must be 256x256"); 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"); throw new ArgumentException("X and Y patch offsets must be from 0 to 15");
var header = PrescanPatch(heightmap, x, y); var header = PrescanPatch(heightmap, x, y);
header.LargeRegion = largeRegion;
header.QuantWBits = 136; header.QuantWBits = 136;
header.PatchIDs = (y & 0x1F); header.setPatchIDs(x, y);
header.PatchIDs += (x << 5);
// NOTE: No idea what prequant and postquant should be or what they do // NOTE: No idea what prequant and postquant should be or what they do
int[] patch = CompressPatch(heightmap, x, y, header, 10); int[] patch = CompressPatch(heightmap, x, y, header, 10);
@ -296,6 +323,8 @@ namespace OpenMetaverse
EncodePatch(output, patch, 0, wbits); 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) private static TerrainPatch.Header PrescanPatch(float[] patch)
{ {
TerrainPatch.Header header = new TerrainPatch.Header(); TerrainPatch.Header header = new TerrainPatch.Header();
@ -318,6 +347,8 @@ namespace OpenMetaverse
return header; 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) private static TerrainPatch.Header PrescanPatch(float[,] patch)
{ {
TerrainPatch.Header header = new TerrainPatch.Header(); TerrainPatch.Header header = new TerrainPatch.Header();
@ -340,6 +371,8 @@ namespace OpenMetaverse
return header; 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) private static TerrainPatch.Header PrescanPatch(float[] heightmap, int patchX, int patchY)
{ {
TerrainPatch.Header header = new TerrainPatch.Header(); TerrainPatch.Header header = new TerrainPatch.Header();
@ -363,6 +396,11 @@ namespace OpenMetaverse
} }
public static TerrainPatch.Header DecodePatchHeader(BitPack bitpack) 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)}; TerrainPatch.Header header = new TerrainPatch.Header {QuantWBits = bitpack.UnpackBits(8)};
@ -377,7 +415,9 @@ namespace OpenMetaverse
header.Range = bitpack.UnpackBits(16); header.Range = bitpack.UnpackBits(16);
// Patch IDs (10 bits) // Patch IDs (10 bits)
header.PatchIDs = bitpack.UnpackBits(10);
header.LargeRegion = largeRegion;
header.PatchIDs = bitpack.UnpackBits(largeRegion ? 32 : 10);
// Word bits // Word bits
header.WordBits = (uint)((header.QuantWBits & 0x0f) + 2); header.WordBits = (uint)((header.QuantWBits & 0x0f) + 2);
@ -428,7 +468,7 @@ namespace OpenMetaverse
output.PackBits(header.QuantWBits, 8); output.PackBits(header.QuantWBits, 8);
output.PackFloat(header.DCOffset); output.PackFloat(header.DCOffset);
output.PackBits(header.Range, 16); 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; return wbits;
} }

View file

@ -67,7 +67,7 @@ namespace OpenMetaverse
Client.Network.RegisterCallback(PacketType.LayerData, LayerDataHandler); 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 x;
int y; int y;
@ -76,7 +76,7 @@ namespace OpenMetaverse
while (true) while (true)
{ {
TerrainPatch.Header header = TerrainCompressor.DecodePatchHeader(bitpack); TerrainPatch.Header header = TerrainCompressor.DecodePatchHeader(bitpack, largeRegion);
if (header.QuantWBits == TerrainCompressor.END_OF_PATCHES) if (header.QuantWBits == TerrainCompressor.END_OF_PATCHES)
break; break;
@ -84,7 +84,7 @@ namespace OpenMetaverse
x = header.X; x = header.X;
y = header.Y; 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( Logger.Log(String.Format(
"Invalid LayerData land packet, x={0}, y={1}, dc_offset={2}, range={3}, quant_wbits={4}, patchids={5}, count={6}", "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]; int[] patches = new int[32 * 32];
@ -131,12 +131,12 @@ namespace OpenMetaverse
// wind_direction = vec2(x,y) // wind_direction = vec2(x,y)
// X values // X values
TerrainPatch.Header header = TerrainCompressor.DecodePatchHeader(bitpack); TerrainPatch.Header header = TerrainCompressor.DecodePatchHeader(bitpack, largeRegion);
TerrainCompressor.DecodePatch(patches, bitpack, header, group.PatchSize); TerrainCompressor.DecodePatch(patches, bitpack, header, group.PatchSize);
float[] xvalues = TerrainCompressor.DecompressPatch(patches, header, group); float[] xvalues = TerrainCompressor.DecompressPatch(patches, header, group);
// Y values // Y values
header = TerrainCompressor.DecodePatchHeader(bitpack); header = TerrainCompressor.DecodePatchHeader(bitpack, largeRegion);
TerrainCompressor.DecodePatch(patches, bitpack, header, group.PatchSize); TerrainCompressor.DecodePatch(patches, bitpack, header, group.PatchSize);
float[] yvalues = TerrainCompressor.DecompressPatch(patches, header, group); float[] yvalues = TerrainCompressor.DecompressPatch(patches, header, group);
@ -172,6 +172,10 @@ namespace OpenMetaverse
if (m_LandPatchReceivedEvent != null || Client.Settings.STORE_LAND_PATCHES) if (m_LandPatchReceivedEvent != null || Client.Settings.STORE_LAND_PATCHES)
DecompressLand(e.Simulator, bitpack, header); DecompressLand(e.Simulator, bitpack, header);
break; 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: case TerrainPatch.LayerType.Water:
Logger.Log("Got a Water LayerData packet, implement me!", Helpers.LogLevel.Error, Client); Logger.Log("Got a Water LayerData packet, implement me!", Helpers.LogLevel.Error, Client);
break; break;

View file

@ -119,7 +119,7 @@ namespace OpenMetaverse
// kick off an async receive. The Start() method will return, the // kick off an async receive. The Start() method will return, the
// actual receives will occur asynchronously and will be caught in // actual receives will occur asynchronously and will be caught in
// AsyncEndRecieve(). // AsyncEndReceive().
AsyncBeginReceive(); AsyncBeginReceive();
} }

View file

@ -10023,6 +10023,9 @@ namespace OpenMetaverse.Packets
public byte[] SeedCapability; public byte[] SeedCapability;
public byte SimAccess; public byte SimAccess;
public uint TeleportFlags; public uint TeleportFlags;
// Sim/region size information sent in TeleportFinishMesssage
public uint RegionSizeX = Simulator.DefaultRegionSizeX;
public uint RegionSizeY = Simulator.DefaultRegionSizeY;
public override int Length public override int Length
{ {
@ -10075,6 +10078,7 @@ namespace OpenMetaverse.Packets
Buffer.BlockCopy(SeedCapability, 0, bytes, i, SeedCapability.Length); i += SeedCapability.Length; Buffer.BlockCopy(SeedCapability, 0, bytes, i, SeedCapability.Length); i += SeedCapability.Length;
bytes[i++] = SimAccess; bytes[i++] = SimAccess;
Utils.UIntToBytes(TeleportFlags, bytes, i); i += 4; Utils.UIntToBytes(TeleportFlags, bytes, i); i += 4;
// size information is not sent in the UDP packet
} }
} }

View file

@ -66,7 +66,7 @@ namespace SecondBotEvents.Commands
return Failure("Unknown group", new[] { group, avatar, state }); return Failure("Unknown group", new[] { group, avatar, state });
} }
ProcessAvatar(avatar); ProcessAvatar(avatar);
if(avataruuid == null) if(avataruuid == UUID.Zero)
{ {
return Failure("Unknown avatar", new[] { group, avatar, state }); return Failure("Unknown avatar", new[] { group, avatar, state });
} }
@ -75,8 +75,10 @@ namespace SecondBotEvents.Commands
{ {
Action = GroupBanAction.Unban; Action = GroupBanAction.Unban;
} }
List<UUID> avatarstoaction = new List<UUID>(); List<UUID> avatarstoaction = new()
avatarstoaction.Add(avataruuid); {
avataruuid
};
GetClient().Groups.RequestBanAction(groupuuid, Action, avatarstoaction.ToArray()); GetClient().Groups.RequestBanAction(groupuuid, Action, avatarstoaction.ToArray());
return BasicReply("Accepted"); return BasicReply("Accepted");
} }
@ -104,7 +106,7 @@ namespace SecondBotEvents.Commands
return Failure("Unknown group", new[] { group, avatar }); return Failure("Unknown group", new[] { group, avatar });
} }
ProcessAvatar(avatar); ProcessAvatar(avatar);
if (avataruuid == null) if (avataruuid == UUID.Zero)
{ {
return Failure("Unknown avatar", new[] { group, avatar}); return Failure("Unknown avatar", new[] { group, avatar});
} }
@ -172,12 +174,13 @@ namespace SecondBotEvents.Commands
{ {
return Failure("avatar lookup", new [] { group, avatar, role }); return Failure("avatar lookup", new [] { group, avatar, role });
} }
List<UUID> roles = new List<UUID>(); List<UUID> roles = new()
roles.Add(UUID.Zero);
if(role != "everyone")
{ {
UUID roleuuid = UUID.Zero; UUID.Zero
if (UUID.TryParse(role, out roleuuid) == false) };
if (role != "everyone")
{
if (UUID.TryParse(role, out UUID roleuuid) == false)
{ {
return Failure("Unable to process role UUID", new[] { group, avatar, role }); 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 }); return Failure("Message empty", new [] { group, title, message });
} }
GroupNotice NewNotice = new GroupNotice(); GroupNotice NewNotice = new()
NewNotice.Subject = title; {
NewNotice.Message = message; Subject = title,
NewNotice.OwnerID = GetClient().Self.AgentID; Message = message,
OwnerID = GetClient().Self.AgentID
};
GetClient().Groups.SendGroupNotice(groupuuid, NewNotice); GetClient().Groups.SendGroupNotice(groupuuid, NewNotice);
return BasicReply("Sending notice", new [] { group, title, message }); return BasicReply("Sending notice", new [] { group, title, message });
} }
@ -301,11 +306,13 @@ namespace SecondBotEvents.Commands
{ {
return Failure("Message empty", new [] { group, title, message, attachment }); return Failure("Message empty", new [] { group, title, message, attachment });
} }
GroupNotice NewNotice = new GroupNotice(); GroupNotice NewNotice = new()
NewNotice.Subject = title; {
NewNotice.Message = message; Subject = title,
NewNotice.OwnerID = GetClient().Self.AgentID; Message = message,
NewNotice.AttachmentID = inventoryuuid; OwnerID = GetClient().Self.AgentID,
AttachmentID = inventoryuuid
};
GetClient().Groups.SendGroupNotice(groupuuid, NewNotice); GetClient().Groups.SendGroupNotice(groupuuid, NewNotice);
return BasicReply("Sending notice with attachment", new [] { group, title, message, attachment }); 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")] [ArgHints("group", "the UUID of the group")]
public object GroupchatGroupHasUnread(string group) public object GroupchatGroupHasUnread(string group)
{ {
UUID groupUUID = UUID.Zero; if(UUID.TryParse(group,out UUID groupUUID) == false)
if(UUID.TryParse(group,out groupUUID) == false)
{ {
return Failure("group value is invaild", new [] { group }); return Failure("group value is invaild", new [] { group });
} }
@ -400,8 +406,7 @@ namespace SecondBotEvents.Commands
[ReturnHintsFailure("Unknown group")] [ReturnHintsFailure("Unknown group")]
public object Groupchat(string group, string message) public object Groupchat(string group, string message)
{ {
UUID groupUUID = UUID.Zero; if (UUID.TryParse(group, out UUID groupUUID) == false)
if (UUID.TryParse(group, out groupUUID) == false)
{ {
return Failure("group value is invaild", new [] { group, message }); return Failure("group value is invaild", new [] { group, message });
} }

View file

@ -44,8 +44,10 @@ namespace SecondBotEvents.Commands
break; break;
} }
} }
AssetSound S = new AssetSound(); AssetSound S = new()
S.AssetData = audioData; {
AssetData = audioData
};
S.Encode(); S.Encode();
GetClient().Inventory.RequestCreateItemFromAsset(S.AssetData, inventoryName, "", AssetType.Sound, InventoryType.Sound, AA.UUID, null); 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 }); return Failure("Cant find target folder", new [] { name });
} }
List<InventoryBase> contents = GetClient().Inventory.FolderContents(AA.UUID, GetClient().Self.AgentID, true, true, InventorySortOrder.ByName, 5 * 1000); List<InventoryBase> contents = GetClient().Inventory.FolderContents(AA.UUID, GetClient().Self.AgentID, true, true, InventorySortOrder.ByName, 5 * 1000);
List<InventoryItem> wareables = new List<InventoryItem>(); List<InventoryItem> wareables = new();
if (contents == null) if (contents == null)
{ {
return Failure("target folder is empty or so full I cant get it in 5 secs...", new [] { name }); 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"); return Failure("Unable to find notecard folder");
} }
List<UUID> purge_notecards = new List<UUID>(); List<UUID> purge_notecards = new();
List<InventoryBase> contents = GetClient().Inventory.FolderContents(NotecardFolder.UUID, GetClient().Self.AgentID, true, true, InventorySortOrder.ByDate, 40 * 1000); List<InventoryBase> contents = GetClient().Inventory.FolderContents(NotecardFolder.UUID, GetClient().Self.AgentID, true, true, InventorySortOrder.ByDate, 40 * 1000);
foreach (InventoryBase C in contents) 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<UUID>()); GetClient().Inventory.Remove(purge_notecards, new List<UUID>());
} }
@ -266,7 +268,7 @@ namespace SecondBotEvents.Commands
[ReturnHints("Asset UUID or UUID zero")] [ReturnHints("Asset UUID or UUID zero")]
[ReturnHints("Invaild item uuid")] [ReturnHints("Invaild item uuid")]
[ArgHints("item", "inventory level UUID of item")] [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) 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 }); return Failure("Unable to find inventory", new [] { item, objectuuid, running });
} }
Dictionary<uint, Primitive> objects_copy = GetClient().Network.CurrentSim.ObjectsPrimitives.Copy(); Dictionary<uint, Primitive> objects_copy = GetClient().Network.CurrentSim.ObjectsPrimitives.Copy();
KeyValuePair<uint, Primitive> RealObject = new KeyValuePair<uint, Primitive>(0,null); KeyValuePair<uint, Primitive> RealObject = new(0, null);
foreach (KeyValuePair<uint, Primitive> Obj in objects_copy) foreach (KeyValuePair<uint, Primitive> Obj in objects_copy)
{ {
if (Obj.Value.ID == objectUUID) 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.")] [ReturnHintsFailure("new folder name is too short, must be longer than 3 characters.")]
[ArgHints("parentFolder", "UUID of folder to create a subfolder in")] [ArgHints("parentFolder", "UUID of folder to create a subfolder in")]
[ArgHints("folderName", "name of the new folder")] [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) if (UUID.TryParse(parentFolder, out UUID parentFolderUUID) == false)
{ {

View file

@ -49,8 +49,8 @@ namespace SecondBotEvents.Commands
} }
targetparcel.SalePrice = amountvalue; targetparcel.SalePrice = amountvalue;
targetparcel.AuthBuyerID = avataruuid; targetparcel.AuthBuyerID = avataruuid;
parcel_static.ParcelSetFlag(ParcelFlags.ForSale, targetparcel, true); ParcelStatic.ParcelSetFlag(ParcelFlags.ForSale, targetparcel, true);
parcel_static.ParcelSetFlag(ParcelFlags.ForSaleObjects, targetparcel, false); ParcelStatic.ParcelSetFlag(ParcelFlags.ForSaleObjects, targetparcel, false);
targetparcel.Update(GetClient()); targetparcel.Update(GetClient());
return Failure("ok", new [] { amount, avatar }); return Failure("ok", new [] { amount, avatar });
} }
@ -167,8 +167,8 @@ namespace SecondBotEvents.Commands
{ {
return Failure(tests.Value); return Failure(tests.Value);
} }
Dictionary<string, ParcelFlags> flags = parcel_static.get_flags_list(); Dictionary<string, ParcelFlags> flags = ParcelStatic.GetFlagsList();
Dictionary<string, string> collection = new Dictionary<string, string>(); Dictionary<string, string> collection = new();
foreach (ParcelFlags cfg in flags.Values) foreach (ParcelFlags cfg in flags.Values)
{ {
collection.Add(cfg.ToString(), targetparcel.Flags.HasFlag(cfg).ToString()); 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 }); return BasicReply("Avatar is in the blacklist", new [] { avatar });
} }
ParcelAccessEntry entry = new ParcelAccessEntry(); ParcelAccessEntry entry = new()
entry.AgentID = avataruuid; {
entry.Flags = AccessList.Ban; AgentID = avataruuid,
entry.Time = new System.DateTime(3030, 03, 03); Flags = AccessList.Ban,
Time = new System.DateTime(3030, 03, 03)
};
targetparcel.AccessBlackList.Add(entry); targetparcel.AccessBlackList.Add(entry);
targetparcel.Update(GetClient()); targetparcel.Update(GetClient());
return BasicReply("ok", new [] { avatar }); return BasicReply("ok", new [] { avatar });
@ -266,7 +268,7 @@ namespace SecondBotEvents.Commands
return Failure("Invaild avatar", new [] { avatar }); return Failure("Invaild avatar", new [] { avatar });
} }
bool alreadyBanned = false; bool alreadyBanned = false;
ParcelAccessEntry removeentry = new ParcelAccessEntry(); ParcelAccessEntry removeentry = new();
foreach (ParcelAccessEntry E in targetparcel.AccessBlackList) foreach (ParcelAccessEntry E in targetparcel.AccessBlackList)
{ {
if (E.AgentID == avataruuid) if (E.AgentID == avataruuid)
@ -298,7 +300,7 @@ namespace SecondBotEvents.Commands
{ {
return Failure(tests.Value, new [] { musicurl }); 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 }); return BasicReply(status.ToString(), new [] { musicurl });
} }
@ -319,11 +321,11 @@ namespace SecondBotEvents.Commands
{ {
return Failure(tests.Value, new [] { escapedflagdata }); return Failure(tests.Value, new [] { escapedflagdata });
} }
List<string> acceptablewords = new List<string>(); List<string> acceptablewords = new();
Dictionary<string, ParcelFlags> flags = parcel_static.get_flags_list(); Dictionary<string, ParcelFlags> flags = ParcelStatic.GetFlagsList();
acceptablewords.AddRange(new[] { "True", "False" }); acceptablewords.AddRange(new[] { "True", "False" });
Dictionary<string, bool> setflags = new Dictionary<string, bool>(); Dictionary<string, bool> setflags = new();
string[] args = escapedflagdata.Split(":::"); string[] args = escapedflagdata.Split(":::");
foreach (string a in args) foreach (string a in args)
{ {
@ -348,7 +350,7 @@ namespace SecondBotEvents.Commands
{ {
return Failure("No accepted flags", new [] { escapedflagdata }); 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 }); return Failure("Incorrect perms to control parcel", new [] { escapedflagdata });
} }
@ -356,7 +358,7 @@ namespace SecondBotEvents.Commands
{ {
if (flags.ContainsKey(cfg.Key) == true) 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()); targetparcel.Update(GetClient());
@ -494,7 +496,7 @@ namespace SecondBotEvents.Commands
{ {
return Failure(tests.Value); return Failure(tests.Value);
} }
GetParcelBanlistObject reply = new GetParcelBanlistObject(); GetParcelBanlistObject reply = new();
int delays = 0; int delays = 0;
bool haslookup = true; bool haslookup = true;
while ((haslookup == true) && (delays < 3)) while ((haslookup == true) && (delays < 3))
@ -582,7 +584,7 @@ namespace SecondBotEvents.Commands
{ {
if (bits[0] == "MediaType") if (bits[0] == "MediaType")
{ {
UpdateParcel_MediaType(targetparcel, bits[1]); UpdateParcelMediaType(targetparcel, bits[1]);
} }
else if ((bits[0] == "MediaWidth") || (bits[0] == "MediaHeight")) else if ((bits[0] == "MediaWidth") || (bits[0] == "MediaHeight"))
{ {
@ -636,7 +638,7 @@ namespace SecondBotEvents.Commands
return BasicReply("ok", new [] { escapedflagdata }); 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") if (value == "IMG-PNG")
{ {
@ -670,7 +672,7 @@ namespace SecondBotEvents.Commands
public class GetParcelBanlistObject public class GetParcelBanlistObject
{ {
public Dictionary<UUID, string> entrys = new Dictionary<UUID, string>(); public Dictionary<UUID, string> entrys = new();
public string parcelName = ""; public string parcelName = "";
public string regionName = ""; public string regionName = "";
public int delay = 0; public int delay = 0;

View file

@ -1,28 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk;Microsoft.NET.Sdk.Publish">
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<StartupObject>SecondBotEvents.Startup</StartupObject> <StartupObject>SecondBotEvents.Startup</StartupObject>
<MSBuildGitHashCommand>git rev-parse --short HEAD</MSBuildGitHashCommand> <MSBuildGitHashCommand>git rev-parse --short HEAD</MSBuildGitHashCommand>
<MSBuildGitHashValidate>False</MSBuildGitHashValidate> <MSBuildGitHashValidate>False</MSBuildGitHashValidate>
<MSBuildGitHashSuppressDirtyWarning>False</MSBuildGitHashSuppressDirtyWarning> <MSBuildGitHashSuppressDirtyWarning>False</MSBuildGitHashSuppressDirtyWarning>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Discord.Net" Version="3.4.1" /> <PackageReference Include="Discord.Net" Version="3.11.0" />
<PackageReference Include="Discord.Net.WebSocket" Version="3.7.2" /> <PackageReference Include="Discord.Net.WebSocket" Version="3.11.0" />
<PackageReference Include="EmbedIO" Version="3.4.3" /> <PackageReference Include="EmbedIO" Version="3.5.2" />
<PackageReference Include="Microsoft.NET.Build.Containers" Version="7.0.306" />
<PackageReference Include="MSBuildGitHash" Version="2.0.2"> <PackageReference Include="MSBuildGitHash" Version="2.0.2">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="RestSharp" Version="107.3.0" /> <PackageReference Include="RestSharp" Version="110.2.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\LibreMetaverse\LibreMetaverse.csproj" /> <ProjectReference Include="..\LibreMetaverse\LibreMetaverse.csproj" />
</ItemGroup> </ItemGroup>
</Project>
</Project>

View file

@ -1,6 +1,7 @@
using OpenMetaverse; using OpenMetaverse;
using OpenMetaverse.Assets; using OpenMetaverse.Assets;
using SecondBotEvents.Config; using SecondBotEvents.Config;
using Swan;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
@ -200,7 +201,9 @@ namespace SecondBotEvents.Services
{ {
return "No sim"; 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;
} }
} }
} }

View file

@ -18,25 +18,25 @@ namespace SecondBotEvents.Services
myConfig = new DataStoreConfig(master.fromEnv,master.fromFolder); myConfig = new DataStoreConfig(master.fromEnv,master.fromFolder);
} }
protected Dictionary<string, UUID> avatarsName2Key = new Dictionary<string, UUID>(); protected Dictionary<string, UUID> avatarsName2Key = new();
protected Dictionary<UUID, long> avatarLastUsed = new Dictionary<UUID, long>(); protected Dictionary<UUID, long> avatarLastUsed = new();
protected Dictionary<UUID, string> groupsKey2Name = new Dictionary<UUID, string>(); protected Dictionary<UUID, string> groupsKey2Name = new();
protected Dictionary<UUID, List<UUID>> groupMembers = new Dictionary<UUID, List<UUID>>(); protected Dictionary<UUID, List<UUID>> groupMembers = new();
protected Dictionary<UUID, Dictionary<UUID, GroupRole>> groupRoles = new Dictionary<UUID, Dictionary<UUID, GroupRole>>(); protected Dictionary<UUID, Dictionary<UUID, GroupRole>> groupRoles = new();
protected List<string> localChatHistory = new List<string>(); protected List<string> localChatHistory = new();
protected Dictionary<UUID, List<string>> chatWindows = new Dictionary<UUID, List<string>>(); // sess, list chat protected Dictionary<UUID, List<string>> chatWindows = new(); // sess, list chat
protected Dictionary<UUID, bool> chatWindowsUnread = new Dictionary<UUID, bool>(); // sess, bool protected Dictionary<UUID, bool> chatWindowsUnread = new(); // sess, bool
protected Dictionary<UUID, bool> chatWindowsIsGroup = new Dictionary<UUID, bool>(); // sess, bool protected Dictionary<UUID, bool> chatWindowsIsGroup = new(); // sess, bool
protected Dictionary<UUID, UUID> chatWindowsOwner = new Dictionary<UUID, UUID>(); // sess, owner id protected Dictionary<UUID, UUID> chatWindowsOwner = new(); // sess, owner id
protected Dictionary<string, string> KeyValueStore = new Dictionary<string, string>(); protected Dictionary<string, string> KeyValueStore = new();
protected Dictionary<string, long> KeyValueStoreLastUsed = new Dictionary<string, long>(); protected Dictionary<string, long> KeyValueStoreLastUsed = new();
protected List<CommandHistory> commandHistories = new List<CommandHistory>(); protected List<CommandHistory> commandHistories = new();
protected long lastCleanupKeyValueStore = 0; protected long lastCleanupKeyValueStore = 0;
protected long lastCleanupAvatarStore = 0; protected long lastCleanupAvatarStore = 0;
@ -53,7 +53,7 @@ namespace SecondBotEvents.Services
return groupsKey2Name[group]; return groupsKey2Name[group];
} }
string reply = "lookup"; string reply = "lookup";
AutoResetEvent fetchEvent = new AutoResetEvent(false); AutoResetEvent fetchEvent = new(false);
void callback(object sender, CurrentGroupsEventArgs e) void callback(object sender, CurrentGroupsEventArgs e)
{ {
foreach(KeyValuePair<UUID,Group> entry in e.Groups) foreach(KeyValuePair<UUID,Group> entry in e.Groups)
@ -91,7 +91,7 @@ namespace SecondBotEvents.Services
if (dif > 125) if (dif > 125)
{ {
lastCleanupKeyValueStore = unixtime; lastCleanupKeyValueStore = unixtime;
List<string> clearentrys = new List<string>(); List<string> clearentrys = new();
foreach (KeyValuePair<string, long> entry in KeyValueStoreLastUsed) foreach (KeyValuePair<string, long> entry in KeyValueStoreLastUsed)
{ {
dif = unixtime - entry.Value; dif = unixtime - entry.Value;
@ -121,7 +121,7 @@ namespace SecondBotEvents.Services
if (dif > 75) if (dif > 75)
{ {
lastCleanupAvatarStore = unixtime; lastCleanupAvatarStore = unixtime;
Dictionary<UUID, string> clearLinks = new Dictionary<UUID, string>(); Dictionary<UUID, string> clearLinks = new();
foreach (KeyValuePair<string, UUID> entry in avatarsName2Key) foreach (KeyValuePair<string, UUID> entry in avatarsName2Key)
{ {
dif = unixtime - avatarLastUsed[entry.Value]; dif = unixtime - avatarLastUsed[entry.Value];
@ -141,10 +141,10 @@ namespace SecondBotEvents.Services
} }
} }
} }
int sum = commandHistories.Count() + KeyValueStoreLastUsed.Count() + KeyValueStore.Count() + int sum = commandHistories.Count + KeyValueStoreLastUsed.Count + KeyValueStore.Count +
chatWindowsOwner.Count() + chatWindowsIsGroup.Count() + chatWindowsUnread.Count() + chatWindowsOwner.Count + chatWindowsIsGroup.Count + chatWindowsUnread.Count +
chatWindows.Count() + localChatHistory.Count() + groupRoles.Count() + chatWindows.Count + localChatHistory.Count + groupRoles.Count +
groupMembers.Count() + groupsKey2Name.Count() + avatarsName2Key.Count(); groupMembers.Count + groupsKey2Name.Count + avatarsName2Key.Count;
return sum.ToString(); return sum.ToString();
} }
@ -152,7 +152,7 @@ namespace SecondBotEvents.Services
{ {
lock (commandHistories) lock (commandHistories)
{ {
CommandHistory A = new CommandHistory(status, command, args, SecondbotHelpers.UnixTimeNow()); CommandHistory A = new(status, command, args, SecondbotHelpers.UnixTimeNow());
commandHistories.Add(A); commandHistories.Add(A);
int c = commandHistories.Count; int c = commandHistories.Count;
while (c > myConfig.GetCommandHistoryLimit()) while (c > myConfig.GetCommandHistoryLimit())
@ -226,7 +226,7 @@ namespace SecondBotEvents.Services
public List<UUID> GetAllGroupsChatWithUnread() public List<UUID> GetAllGroupsChatWithUnread()
{ {
List<UUID> reply = new List<UUID>(); List<UUID> reply = new();
foreach(KeyValuePair<UUID, bool> windowState in chatWindowsUnread) foreach(KeyValuePair<UUID, bool> windowState in chatWindowsUnread)
{ {
if(windowState.Value == false) if(windowState.Value == false)
@ -299,11 +299,11 @@ namespace SecondBotEvents.Services
public Dictionary<UUID, string> GetGroupRoles(UUID group) public Dictionary<UUID, string> GetGroupRoles(UUID group)
{ {
Dictionary<UUID, string> reply = new Dictionary<UUID, string>(); Dictionary<UUID, string> reply = new();
if (groupRoles.ContainsKey(group) == false) if (groupRoles.ContainsKey(group) == false)
{ {
AutoResetEvent fetchEvent = new AutoResetEvent(false); AutoResetEvent fetchEvent = new(false);
void callback(object sender, GroupRolesDataReplyEventArgs e) void callback(object sender, GroupRolesDataReplyEventArgs e)
{ {
if (e.GroupID == group) if (e.GroupID == group)
@ -341,7 +341,7 @@ namespace SecondBotEvents.Services
if (groupMembers[group].Contains(avatar) == false) if (groupMembers[group].Contains(avatar) == false)
{ {
reply = false; reply = false;
AutoResetEvent fetchEvent = new AutoResetEvent(false); AutoResetEvent fetchEvent = new(false);
void callback(object sender, GroupMembersReplyEventArgs e) void callback(object sender, GroupMembersReplyEventArgs e)
{ {
if (e.GroupID == group) if (e.GroupID == group)
@ -395,7 +395,7 @@ namespace SecondBotEvents.Services
{ {
purgeLen = myConfig.GetGroupChatHistoryLimitPerGroup(); purgeLen = myConfig.GetGroupChatHistoryLimitPerGroup();
} }
int counter = chatWindows[sessionID].Count(); int counter = chatWindows[sessionID].Count;
while (counter > purgeLen) while (counter > purgeLen)
{ {
chatWindows[sessionID].RemoveAt(0); chatWindows[sessionID].RemoveAt(0);
@ -471,7 +471,7 @@ namespace SecondBotEvents.Services
} }
protected Dictionary<string, KeyValuePair<string, long>> notecardDataStore = new Dictionary<string, KeyValuePair<string, long>>(); protected Dictionary<string, KeyValuePair<string, long>> notecardDataStore = new();
public List<string> GetLocalChat() public List<string> GetLocalChat()
{ {
@ -532,7 +532,7 @@ namespace SecondBotEvents.Services
if(avatarsName2Key.ContainsValue(avatarId) == false) if(avatarsName2Key.ContainsValue(avatarId) == false)
{ {
bool hasReply = false; bool hasReply = false;
AutoResetEvent fetchEvent = new AutoResetEvent(false); AutoResetEvent fetchEvent = new(false);
void callback(object sender, UUIDNameReplyEventArgs e) void callback(object sender, UUIDNameReplyEventArgs e)
{ {
foreach (KeyValuePair<UUID, string> av in e.Names) foreach (KeyValuePair<UUID, string> av in e.Names)
@ -563,7 +563,7 @@ namespace SecondBotEvents.Services
UUID wantedReplyID = UUID.SecureRandom(); UUID wantedReplyID = UUID.SecureRandom();
bool hasReply = false; bool hasReply = false;
AutoResetEvent fetchEvent = new AutoResetEvent(false); AutoResetEvent fetchEvent = new(false);
void callback(object sender, AvatarPickerReplyEventArgs e) void callback(object sender, AvatarPickerReplyEventArgs e)
{ {
if (e.QueryID == wantedReplyID) if (e.QueryID == wantedReplyID)
@ -590,7 +590,7 @@ namespace SecondBotEvents.Services
public void GetAvatarNames(List<UUID> avatars) public void GetAvatarNames(List<UUID> avatars)
{ {
List<UUID> lookup = new List<UUID>(); List<UUID> lookup = new();
foreach (UUID id in avatars) foreach (UUID id in avatars)
{ {
if (avatarsName2Key.ContainsValue(id) == false) if (avatarsName2Key.ContainsValue(id) == false)
@ -664,7 +664,7 @@ namespace SecondBotEvents.Services
public Dictionary<UUID,string> GetAvatarImWindows() public Dictionary<UUID,string> GetAvatarImWindows()
{ {
Dictionary<UUID, string> windows = new Dictionary<UUID, string>(); Dictionary<UUID, string> windows = new();
foreach (KeyValuePair<UUID,bool> links in chatWindowsIsGroup) foreach (KeyValuePair<UUID,bool> links in chatWindowsIsGroup)
{ {
if(links.Value == true) if(links.Value == true)
@ -728,7 +728,7 @@ namespace SecondBotEvents.Services
public List<UUID> GetAvatarImWindowsUnread() public List<UUID> GetAvatarImWindowsUnread()
{ {
List<UUID> windows = new List<UUID>(); List<UUID> windows = new();
foreach (KeyValuePair<UUID, bool> links in chatWindowsIsGroup) foreach (KeyValuePair<UUID, bool> links in chatWindowsIsGroup)
{ {
if (links.Value == true) if (links.Value == true)
@ -834,8 +834,8 @@ namespace SecondBotEvents.Services
{ {
if (estateBanlist == null) if (estateBanlist == null)
{ {
List<UUID> reply = new List<UUID>(); List<UUID> reply = new();
AutoResetEvent fetchEvent = new AutoResetEvent(false); AutoResetEvent fetchEvent = new(false);
void callback(object sender, EstateBansReplyEventArgs e) void callback(object sender, EstateBansReplyEventArgs e)
{ {
reply = e.Banned; reply = e.Banned;
@ -1077,7 +1077,7 @@ namespace SecondBotEvents.Services
public class CommandHistory public class CommandHistory
{ {
public string Command = ""; public string Command = "";
public string[] Args = new string[] { }; public string[] Args = Array.Empty<string>();
public long Unixtime = 0; public long Unixtime = 0;
public bool status = false; public bool status = false;

View file

@ -46,11 +46,11 @@ namespace SecondBotEvents.Services
protected bool attemptedTeleportBackup = false; protected bool attemptedTeleportBackup = false;
protected long teleportActionLockout = 0; protected long teleportActionLockout = 0;
public void GoHome() public bool GoHome()
{ {
attemptedTeleportHome = true; attemptedTeleportHome = true;
LogFormater.Info("Teleporting to home sim"); 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() protected void Tick()
{ {
@ -85,8 +85,14 @@ namespace SecondBotEvents.Services
} }
if (simNickname == "") if (simNickname == "")
{ {
simNickname = "Someplace # "; if (GetClient().Network.CurrentSim != null)
return; {
simNickname = ""+ GetClient().Network.CurrentSim.Name+" # ";
}
else
{
simNickname = "Someplace # ";
}
} }
long dif = SecondbotHelpers.UnixTimeNow() - teleportActionLockout; long dif = SecondbotHelpers.UnixTimeNow() - teleportActionLockout;
if(dif < 30) if(dif < 30)
@ -96,7 +102,10 @@ namespace SecondBotEvents.Services
teleportActionLockout = SecondbotHelpers.UnixTimeNow(); teleportActionLockout = SecondbotHelpers.UnixTimeNow();
if (attemptedTeleportHome == false) if (attemptedTeleportHome == false)
{ {
GoHome(); if(GoHome() == false)
{
LogFormater.Warn("Unable to teleport to home sim");
}
return; return;
} }
else if(attemptedTeleportBackup == false) else if(attemptedTeleportBackup == false)
@ -104,7 +113,10 @@ namespace SecondBotEvents.Services
attemptedTeleportBackup = true; attemptedTeleportBackup = true;
LogFormater.Info("Teleporting to backup sim"); LogFormater.Info("Teleporting to backup sim");
teleportActionLockout = SecondbotHelpers.UnixTimeNow(); 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; return;
} }
attemptedTeleportHome = false; attemptedTeleportHome = false;

View file

@ -161,13 +161,16 @@ namespace SecondBotEvents.Services
string UUIDfetch = master.DataStoreService.GetAvatarUUID(avatar); string UUIDfetch = master.DataStoreService.GetAvatarUUID(avatar);
if (UUIDfetch != "lookup") if (UUIDfetch != "lookup")
{ {
UUID.TryParse(UUIDfetch, out avataruuid); if(UUID.TryParse(UUIDfetch, out avataruuid) == false)
{
avataruuid = UUID.Zero;
}
} }
} }
protected object BasicReply(string input) protected object BasicReply(string input)
{ {
return BasicReply(input, new string[] { }, GetCallingCommand()); return BasicReply(input, Array.Empty<string>(), GetCallingCommand());
} }
protected object BasicReply(string input, string[] args) protected object BasicReply(string input, string[] args)
@ -178,13 +181,13 @@ namespace SecondBotEvents.Services
protected object BasicReply(string input, string[] args, string command) protected object BasicReply(string input, string[] args, string command)
{ {
master.DataStoreService.AddCommandToHistory(true, command, args); 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) protected object Failure(string input, string command, string[] args, string whyfailed)
{ {
master.DataStoreService.AddCommandToHistory(false, command, args); 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) protected object Failure(string input, string[] args)
@ -194,10 +197,10 @@ namespace SecondBotEvents.Services
protected object Failure(string input) protected object Failure(string input)
{ {
return Failure(input, GetCallingCommand(), new string[] { }, null); return Failure(input, GetCallingCommand(), Array.Empty<string>(), null);
} }
protected string GetCallingCommand() protected static string GetCallingCommand()
{ {
return (new System.Diagnostics.StackTrace()).GetFrame(2).GetMethod().Name; 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) public string Run([FormField] string commandName, [FormField] string args, [FormField] string signing, [FormField] string unixtime)
{ {
string[] myArgs = new string[] { }; string[] myArgs = Array.Empty<string>();
if(args != null) if(args != null)
{ {
myArgs = args.Split("~#~", StringSplitOptions.RemoveEmptyEntries); myArgs = args.Split("~#~", StringSplitOptions.RemoveEmptyEntries);
@ -285,7 +288,7 @@ namespace SecondBotEvents.Services
{ {
return "No bot connected yet"; 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) if(C.accepted == false)
{ {
return "Command request rejected"; return "Command request rejected";

View file

@ -13,7 +13,7 @@ namespace SecondBotEvents.Services
{ {
protected RelayConfig myConfig; protected RelayConfig myConfig;
protected bool botConnected = false; protected bool botConnected = false;
protected List<RelaySys> Relays = new List<RelaySys>(); protected List<RelaySys> Relays = new();
public RelayService(EventsSecondBot setMaster) : base(setMaster) public RelayService(EventsSecondBot setMaster) : base(setMaster)
{ {
myConfig = new RelayConfig(master.fromEnv, master.fromFolder); myConfig = new RelayConfig(master.fromEnv, master.fromFolder);
@ -348,7 +348,7 @@ namespace SecondBotEvents.Services
readonly string[] vaildToOptions = new[] { "avatar", "group", "localchat", "discord", "http" }; readonly string[] vaildToOptions = new[] { "avatar", "group", "localchat", "discord", "http" };
readonly 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) public void TriggerWith(string sourceType, string message, string filterOption1, string filterOption2=null, string filterOption3 = null)
{ {
// avatarim, {message}, avatarUUID // avatarim, {message}, avatarUUID
@ -414,7 +414,7 @@ namespace SecondBotEvents.Services
case "http": case "http":
{ {
long unixtime = SecondbotHelpers.UnixTimeNow(); long unixtime = SecondbotHelpers.UnixTimeNow();
Dictionary<string, string> values = new Dictionary<string, string> Dictionary<string, string> values = new()
{ {
{ "fromType", fromType }, { "fromType", fromType },
{ "fromOption", fromOption }, { "fromOption", fromOption },

View file

@ -5,9 +5,9 @@ using System.Text;
namespace SecondBotEvents 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) if (p.MusicURL != url)
{ {
@ -27,7 +27,7 @@ namespace SecondBotEvents
p.Flags |= F; 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; bool has_perm = true;
if (P.OwnerID != bot.Self.AgentID) if (P.OwnerID != bot.Self.AgentID)
@ -54,30 +54,32 @@ namespace SecondBotEvents
return has_perm; return has_perm;
} }
public static string[] get_flag_names() public static string[] GetFlagNames()
{ {
System.Type enumType = typeof(ParcelFlags); System.Type enumType = typeof(ParcelFlags);
List<string> flagnames = new List<string>(System.Enum.GetNames(enumType)); List<string> flagnames = new(System.Enum.GetNames(enumType));
flagnames.Remove("None"); flagnames.Remove("None");
return flagnames.ToArray(); return flagnames.ToArray();
} }
public static Dictionary<string, string> get_media_list() public static Dictionary<string, string> GetMediaList()
{ {
Dictionary<string, string> flags = new Dictionary<string, string>(); Dictionary<string, string> flags = new()
flags.Add("MediaAutoScale", "Bool (True|False)"); {
flags.Add("MediaLoop", "Bool (True|False)"); { "MediaAutoScale", "Bool (True|False)" },
flags.Add("MediaID", "UUID (Texture)"); { "MediaLoop", "Bool (True|False)" },
flags.Add("MediaURL", "String"); { "MediaID", "UUID (Texture)" },
flags.Add("MediaDesc", "String"); { "MediaURL", "String" },
flags.Add("MediaHeight", "Int (256 to 1024)"); { "MediaDesc", "String" },
flags.Add("MediaWidth", "Int (256 to 1024)"); { "MediaHeight", "Int (256 to 1024)" },
flags.Add("MediaType", "String [\"IMG-PNG\",\"IMG-JPG\",\"VID-MP4\",\"VID-AVI\" or \"Custom-MIME_TYPE_CODE\"]"); { "MediaWidth", "Int (256 to 1024)" },
{ "MediaType", "String [\"IMG-PNG\",\"IMG-JPG\",\"VID-MP4\",\"VID-AVI\" or \"Custom-MIME_TYPE_CODE\"]" }
};
return flags; return flags;
} }
public static Dictionary<string, ParcelFlags> get_flags_list() public static Dictionary<string, ParcelFlags> GetFlagsList()
{ {
Dictionary<string, ParcelFlags> flags = new Dictionary<string, ParcelFlags>(); Dictionary<string, ParcelFlags> flags = new();
Type enumType = typeof(ParcelFlags); Type enumType = typeof(ParcelFlags);
Array enumValues = Enum.GetValues(enumType); Array enumValues = Enum.GetValues(enumType);
Array enumNames = Enum.GetNames(enumType); Array enumNames = Enum.GetNames(enumType);