diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 00000000..2cfaa256 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,34 @@ +name: "CodeQL" + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + schedule: + - cron: '40 14 * * 6' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + language: [ 'csharp' ] + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + with: + languages: ${{ matrix.language }} + + - name: Autobuild + uses: github/codeql-action/autobuild@v1 + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index e4301fef..97283b77 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -3,6 +3,7 @@ name: .NET on: push: branches: [ develop ] + pull_request: branches: [ develop ] @@ -12,14 +13,40 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 + - name: Setup .NET - uses: actions/setup-dotnet@v1 + uses: actions/setup-dotnet@v3 with: - dotnet-version: 5.0.x + dotnet-version: 6.0.x + - name: Restore dependencies run: dotnet restore + - name: Build - run: dotnet build --no-restore + run: dotnet build --no-restore -p:Configuration=Release + - name: Test - run: dotnet test --no-build --verbosity normal + run: dotnet test --no-restore --no-build --verbosity normal + + - name: Bump version and push tag + id: tag_version + uses: mathieudutour/github-tag-action@v6.1 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + + - name: Pack + run: dotnet pack -p:Configuration=Release NGC.LibOpenMetaverse + + - name: Publish Package + run: dotnet nuget push build/Release/*.nupkg --source https://nuget.pkg.github.com/OpenSim-NGC/index.json + + - name: Create Release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ steps.bump_version.outputs.new_tag }} + release_name: Release ${{ github.ref }} + body: ${{ steps.tag_version.outputs.changelog }} + diff --git a/CSJ2K/CSJ2K.csproj b/CSJ2K/CSJ2K.csproj index 19099d30..2defd4bf 100644 --- a/CSJ2K/CSJ2K.csproj +++ b/CSJ2K/CSJ2K.csproj @@ -1,7 +1,7 @@  Local - net48 + net6.0 CSJ2K CSJ2K JPEG2000 decoding library diff --git a/Directory.Build.props b/Directory.Build.props index 5614607e..8ac8092e 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,15 +1,17 @@ + - 0.10.0.0 OpenMetaverse Utopa Skye LLC, OpenMetaverse Developers Utopia Skye LLC - + 1.3.1 + 1.3.1 + 1.3.1 + 1.3.1 + + - 1.1.8 - 1.1.7 - 1.1.7 - 1.1.7 + LibOpenMetaverse is an OpenSim Core compatible Open Metaverse support library BSD-3-Clause https://github.com/OpenSim-NGC/libopenmetaverse false @@ -17,5 +19,13 @@ https://github.com/OpenSim-NGC/libopenmetaverse.git git master + true + + + + $(SolutionDir)\obj\$(Configuration)\$(MSBuildProjectName)\ + $(SolutionDir)\obj\$(Configuration)\$(MSBuildProjectName)\ + $(SolutionDir)\build\$(Configuration)\$(AssemblyName)\ + $(OutputPath) diff --git a/LICENSE.txt b/LICENSE.txt index 43b484b2..426f81ff 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,4 +1,7 @@ + Copyright (c) Opensimulator, http://opensimulator.org/ + All rights reserved. + Copyright (c) 2006-2016, openmetaverse.co All rights reserved. diff --git a/OpenMetaverse.GUI/AvatarList.cs b/OpenMetaverse.GUI/AvatarList.cs index 0276b7c0..b29d5f0e 100644 --- a/OpenMetaverse.GUI/AvatarList.cs +++ b/OpenMetaverse.GUI/AvatarList.cs @@ -97,10 +97,10 @@ public AvatarList() this.ListViewItemSorter = _ColumnSorter; EventHandler clickHandler = new EventHandler(defaultMenuItem_Click); - this.ContextMenu = new ContextMenu(); - this.ContextMenu.MenuItems.Add("Offer Teleport", clickHandler); - this.ContextMenu.MenuItems.Add("Teleport To", clickHandler); - this.ContextMenu.MenuItems.Add("Walk To", clickHandler); + this.ContextMenuStrip = new ContextMenuStrip(); + this.ContextMenuStrip.Items.Add("Offer Teleport", null, clickHandler); + this.ContextMenuStrip.Items.Add("Teleport To", null, clickHandler); + this.ContextMenuStrip.Items.Add("Walk To", null, clickHandler); this.DoubleBuffered = true; this.ListViewItemSorter = _ColumnSorter; @@ -360,7 +360,7 @@ private void UpdateCoarseInfo(Simulator sim, List newEntries, List r private void defaultMenuItem_Click(object sender, EventArgs e) { - MenuItem menuItem = (MenuItem)sender; + ToolStripItem menuItem = (ToolStripItem)sender; switch (menuItem.Text) { diff --git a/OpenMetaverse.GUI/InventoryTree.cs b/OpenMetaverse.GUI/InventoryTree.cs index 12e1352d..bea7c58d 100644 --- a/OpenMetaverse.GUI/InventoryTree.cs +++ b/OpenMetaverse.GUI/InventoryTree.cs @@ -38,13 +38,13 @@ namespace OpenMetaverse.GUI public class InventoryTree : TreeView { private GridClient _Client; - private ContextMenu _ContextMenu; + private ContextMenuStrip _ContextMenu; private UUID _SelectedItemID; /// /// Gets or sets the context menu associated with this control /// - public ContextMenu Menu + public ContextMenuStrip Menu { get { return _ContextMenu; } set { _ContextMenu = value; } @@ -65,9 +65,9 @@ public GridClient Client public InventoryTree() { EventHandler clickHandler = new EventHandler(defaultMenuItem_Click); - _ContextMenu = new ContextMenu(); - _ContextMenu.MenuItems.Add("Wear", clickHandler); - _ContextMenu.MenuItems.Add("Detach", clickHandler); + _ContextMenu = new ContextMenuStrip(); + _ContextMenu.Items.Add("Wear", null, clickHandler); + _ContextMenu.Items.Add("Detach", null, clickHandler); this.NodeMouseClick += new TreeNodeMouseClickEventHandler(InventoryTree_NodeMouseClick); this.BeforeExpand += new TreeViewCancelEventHandler(InventoryTree_BeforeExpand); @@ -172,7 +172,7 @@ private void InitializeClient(GridClient client) private void defaultMenuItem_Click(object sender, EventArgs e) { - MenuItem menuItem = (MenuItem)sender; + ToolStripItem menuItem = (ToolStripItem)sender; InventoryItem item = (InventoryItem)Client.Inventory.Store[_SelectedItemID]; diff --git a/OpenMetaverse.GUI/OpenMetaverse.GUI.csproj b/OpenMetaverse.GUI/OpenMetaverse.GUI.csproj index ca293378..2f56293c 100644 --- a/OpenMetaverse.GUI/OpenMetaverse.GUI.csproj +++ b/OpenMetaverse.GUI/OpenMetaverse.GUI.csproj @@ -1,18 +1,14 @@  Local - net48 + net6.0-windows + true 1591,1574,0419,0618 True - - - False - - diff --git a/OpenMetaverse.PrimMesher/OpenMetaverse.PrimMesher.csproj b/OpenMetaverse.PrimMesher/OpenMetaverse.PrimMesher.csproj index e5e844ae..0097f7e7 100644 --- a/OpenMetaverse.PrimMesher/OpenMetaverse.PrimMesher.csproj +++ b/OpenMetaverse.PrimMesher/OpenMetaverse.PrimMesher.csproj @@ -1,6 +1,6 @@  - net48 + net6.0 Dhalia Trimble, OpenSim Contributors, Cinder Roxley OpenMetaverse.PrimMesher OpenMetaverse.PrimMesher @@ -15,6 +15,6 @@ TRACE;VERTEX_INDEXER - + \ No newline at end of file diff --git a/OpenMetaverse.Rendering.Meshmerizer/OpenMetaverse.Rendering.Meshmerizer.csproj b/OpenMetaverse.Rendering.Meshmerizer/OpenMetaverse.Rendering.Meshmerizer.csproj index ef3a8ebe..02cdadad 100644 --- a/OpenMetaverse.Rendering.Meshmerizer/OpenMetaverse.Rendering.Meshmerizer.csproj +++ b/OpenMetaverse.Rendering.Meshmerizer/OpenMetaverse.Rendering.Meshmerizer.csproj @@ -1,7 +1,7 @@  Local - net48 + net6.0 True 1591,1574,0419,0618 true diff --git a/OpenMetaverse.Rendering.Simple/OpenMetaverse.Rendering.Simple.csproj b/OpenMetaverse.Rendering.Simple/OpenMetaverse.Rendering.Simple.csproj index 690861d8..794c4f26 100644 --- a/OpenMetaverse.Rendering.Simple/OpenMetaverse.Rendering.Simple.csproj +++ b/OpenMetaverse.Rendering.Simple/OpenMetaverse.Rendering.Simple.csproj @@ -1,7 +1,7 @@  Local - net48 + net6.0 True 1591,1574,0419,0618 true diff --git a/OpenMetaverse.StructuredData/JSON/OSDJson.cs b/OpenMetaverse.StructuredData/JSON/OSDJson.cs index 6205e2d9..5390a494 100644 --- a/OpenMetaverse.StructuredData/JSON/OSDJson.cs +++ b/OpenMetaverse.StructuredData/JSON/OSDJson.cs @@ -6,8 +6,6 @@ using System.Globalization; using System.IO; using System.Text; -using LitJson; -using OpenMetaverse; namespace OpenMetaverse.StructuredData { diff --git a/OpenMetaverse.StructuredData/LLSD/NotationLLSD.cs b/OpenMetaverse.StructuredData/LLSD/NotationLLSD.cs index 17c70f0e..9454c2e1 100644 --- a/OpenMetaverse.StructuredData/LLSD/NotationLLSD.cs +++ b/OpenMetaverse.StructuredData/LLSD/NotationLLSD.cs @@ -232,7 +232,7 @@ private static OSD DeserializeLLSDNotationElement(TextReader reader) if (reader.Read(uuidBuf, 0, 36) < 36) throw new OSDException("Notation LLSD parsing: Unexpected end of stream in UUID."); UUID lluuid; - if (!UUID.TryParse(new String(uuidBuf), out lluuid)) + if (!UUID.TryParse(new String(uuidBuf).AsSpan(), out lluuid)) throw new OSDException("Notation LLSD parsing: Invalid UUID discovered."); osd = OSD.FromUUID(lluuid); break; diff --git a/OpenMetaverse.StructuredData/LLSD/XmlLLSD.cs b/OpenMetaverse.StructuredData/LLSD/XmlLLSD.cs index 6c875442..a4bcf099 100644 --- a/OpenMetaverse.StructuredData/LLSD/XmlLLSD.cs +++ b/OpenMetaverse.StructuredData/LLSD/XmlLLSD.cs @@ -265,7 +265,7 @@ public static void EscapeToXML(string s, StringBuilder sb) case '"': sb.Append("""); break; - case '\\': + case '\'': sb.Append("'"); break; default: @@ -295,7 +295,7 @@ public static void EscapeASCIIToXML(osUTF8 ms, string s) case '"': ms.Append(osUTF8Const.XMLamp_quot); break; - case '\\': + case '\'': ms.Append(osUTF8Const.XMLamp_apos); break; default: @@ -325,7 +325,7 @@ public static void EscapeToXML(osUTF8 ms, string s) case '"': ms.Append(osUTF8Const.XMLamp_quot); break; - case '\\': + case '\'': ms.Append(osUTF8Const.XMLamp_apos); break; default: @@ -355,7 +355,7 @@ public static void EscapeToXML(osUTF8 ms, osUTF8 s) case (byte)'"': ms.Append(osUTF8Const.XMLamp_quot); break; - case (byte)'\\': + case (byte)'\'': ms.Append(osUTF8Const.XMLamp_apos); break; default: @@ -636,8 +636,7 @@ private static OSD ParseLLSDXmlElement(XmlTextReader reader) if (reader.Read()) { - int value = 0; - Int32.TryParse(reader.ReadString().Trim(), out value); + Int32.TryParse(reader.ReadString().Trim(), out int value); ret = OSD.FromInteger(value); break; } @@ -653,7 +652,7 @@ private static OSD ParseLLSDXmlElement(XmlTextReader reader) if (reader.Read()) { - double value = 0d; + double value; string str = reader.ReadString().Trim().ToLower(); if (str == "nan") @@ -676,8 +675,7 @@ private static OSD ParseLLSDXmlElement(XmlTextReader reader) if (reader.Read()) { - UUID value = UUID.Zero; - UUID.TryParse(reader.ReadString().Trim(), out value); + UUID.TryParse(reader.ReadString().AsSpan(), out UUID value); ret = OSD.FromUUID(value); break; } @@ -693,12 +691,12 @@ private static OSD ParseLLSDXmlElement(XmlTextReader reader) if (reader.Read()) { - DateTime value = Utils.Epoch; - DateTime.TryParse(reader.ReadString().Trim(), out value); - ret = OSD.FromDate(value); + if(DateTime.TryParse(reader.ReadString().Trim(), out DateTime value)) + ret = OSD.FromDate(value); + else + ret = OSD.FromDate(Utils.Epoch); break; } - ret = OSD.FromDate(Utils.Epoch); break; case "string": diff --git a/OpenMetaverse.StructuredData/OpenMetaverse.StructuredData.csproj b/OpenMetaverse.StructuredData/OpenMetaverse.StructuredData.csproj index ceb92dee..9e1770a4 100644 --- a/OpenMetaverse.StructuredData/OpenMetaverse.StructuredData.csproj +++ b/OpenMetaverse.StructuredData/OpenMetaverse.StructuredData.csproj @@ -1,7 +1,7 @@  Local - net48;netstandard2.0 + net6.0 1591,1574,0419,0618 true true @@ -12,4 +12,4 @@ - \ No newline at end of file + diff --git a/OpenMetaverse.StructuredData/StructuredData.cs b/OpenMetaverse.StructuredData/StructuredData.cs index 9015198b..549ea050 100644 --- a/OpenMetaverse.StructuredData/StructuredData.cs +++ b/OpenMetaverse.StructuredData/StructuredData.cs @@ -30,6 +30,7 @@ using System.IO; using System.Reflection; using System.Text; +using System.Runtime.CompilerServices; namespace OpenMetaverse.StructuredData { @@ -102,14 +103,13 @@ public virtual bool AsBoolean() double d = ((OSDReal)this).value; return (!Double.IsNaN(d) && d != 0); case OSDType.String: - string s = ((OSDString)this).value; - if (String.IsNullOrEmpty(s)) - return false; - if (s == "0" || s.ToLower() == "false") + if (string.IsNullOrEmpty(((OSDString)this).value) || + ((OSDString)this).value.Equals("0") || + ((OSDString)this).value.Equals("false", StringComparison.InvariantCultureIgnoreCase)) return false; return true; case OSDType.UUID: - return (((OSDUUID)this).value.IsZero()) ? false : true; + return ((OSDUUID)this).value.IsNotZero(); case OSDType.Map: return ((OSDMap)this).dicvalue.Count > 0; case OSDType.Array: @@ -145,16 +145,13 @@ public virtual int AsInteger() return Int32.MinValue; return (int)Math.Round(v); case OSDType.String: - string s = ((OSDString)this).value; - double dbl; - if (Double.TryParse(s, out dbl)) + if (Double.TryParse(((OSDString)this).value.AsSpan(), out double dbl)) return (int)Math.Floor(dbl); else return 0; case OSDType.OSDUTF8: - string us = ((OSDUTF8)this).value.ToString(); - double udbl; - if (Double.TryParse(us, out udbl)) + var us = ((OSDUTF8)this).value.ToString().AsSpan(); + if (Double.TryParse(us, out double udbl)) return (int)Math.Floor(udbl); else return 0; @@ -167,10 +164,12 @@ public virtual int AsInteger() List l = ((OSDArray)this).value; if (l.Count < 4) return 0; - byte[] by = new byte[4]; - for (int i = 0; i < 4; i++) - by[i] = (byte)l[i].AsInteger(); - return (by[0] << 24) | (by[1] << 16) | (by[2] << 8) | by[3]; + return + (byte)l[0].AsInteger() << 24 | + (byte)l[1].AsInteger() << 16 | + (byte)l[2].AsInteger() << 8 | + (byte)l[3].AsInteger(); + case OSDType.Date: return (int)Utils.DateTimeToUnixTime(((OSDDate)this).value); default: @@ -196,16 +195,12 @@ public virtual uint AsUInteger() return UInt32.MinValue; return (uint)Math.Round(v); case OSDType.String: - string s = ((OSDString)this).value; - double dbl; - if (Double.TryParse(s, out dbl)) + if (Double.TryParse(((OSDString)this).value.AsSpan(), out double dbl)) return (uint)Math.Floor(dbl); else return 0; case OSDType.OSDUTF8: - string us = ((OSDUTF8)this).value.ToString(); - double udbl; - if (Double.TryParse(us, out udbl)) + if (Double.TryParse(((OSDUTF8)this).value.ToString().AsSpan(), out double udbl)) return (uint)Math.Floor(udbl); else return 0; @@ -221,10 +216,11 @@ public virtual uint AsUInteger() List l = ((OSDArray)this).value; if (l.Count < 4) return 0; - byte[] by = new byte[4]; - for (int i = 0; i < 4; i++) - by[i] = (byte)l[i].AsInteger(); - return (uint)((by[0] << 24) | (by[1] << 16) | (by[2] << 8) | by[3]); + return ( + ((uint)(byte)l[0].AsInteger() << 24) | + ((uint)(byte)l[1].AsInteger() << 16) | + ((uint)(byte)l[2].AsInteger() << 8) | + (byte)l[3].AsInteger()); default: return 0; } @@ -248,16 +244,13 @@ public virtual long AsLong() return Int64.MinValue; return (long)Math.Round(v); case OSDType.String: - string s = ((OSDString)this).value; - double dbl; - if (Double.TryParse(s, out dbl)) + if (Double.TryParse(((OSDString)this).value, out double dbl)) return (long)Math.Floor(dbl); else return 0; case OSDType.OSDUTF8: - string us = ((OSDUTF8)this).value.ToString(); - double udbl; - if (Double.TryParse(us, out udbl)) + var us = ((OSDUTF8)this).value.ToString().AsSpan(); + if (Double.TryParse(us, out double udbl)) return (long)Math.Floor(udbl); else return 0; @@ -283,18 +276,15 @@ public virtual long AsLong() List l = ((OSDArray)this).value; if (l.Count < 8) return 0; - byte[] b = new byte[8]; - for (int i = 0; i < 8; i++) - b[i] = (byte)l[i].AsInteger(); - return ( - ((long)b[0] << 56) | - ((long)b[1] << 48) | - ((long)b[2] << 40) | - ((long)b[3] << 32) | - ((long)b[4] << 24) | - ((long)b[5] << 16) | - ((long)b[6] << 8) | - b[7]); + return + ((long)(byte)l[0].AsInteger() << 56) | + ((long)(byte)l[1].AsInteger() << 48) | + ((long)(byte)l[2].AsInteger() << 40) | + ((long)(byte)l[3].AsInteger() << 32) | + ((long)(byte)l[4].AsInteger() << 24) | + ((long)(byte)l[5].AsInteger() << 16) | + ((long)(byte)l[6].AsInteger() << 8) | + (byte)l[7].AsInteger(); } default: return 0; @@ -319,16 +309,12 @@ public virtual ulong AsULong() return UInt64.MinValue; return (ulong)Math.Round(v); case OSDType.String: - string s = ((OSDString)this).value; - double dbl; - if (Double.TryParse(s, out dbl)) + if (Double.TryParse(((OSDString)this).value.AsSpan(), out double dbl)) return (ulong)Math.Floor(dbl); else return 0; case OSDType.OSDUTF8: - string us = ((OSDUTF8)this).value.ToString(); - double udbl; - if (Double.TryParse(us, out udbl)) + if (Double.TryParse(((OSDUTF8)this).value.ToString().AsSpan(), out double udbl)) return (ulong)Math.Floor(udbl); else return 0; @@ -354,18 +340,15 @@ public virtual ulong AsULong() List l = ((OSDArray)this).value; if (l.Count < 8) return 0; - byte[] b = new byte[8]; - for (int i = 0; i < 8; i++) - b[i] = (byte)l[i].AsInteger(); return ( - ((ulong)b[0] << 56) | - ((ulong)b[1] << 48) | - ((ulong)b[2] << 40) | - ((ulong)b[3] << 32) | - ((ulong)b[4] << 24) | - ((ulong)b[5] << 16) | - ((ulong)b[6] << 8) | - b[7]); + ((ulong)(byte)l[0].AsInteger() << 56) | + ((ulong)(byte)l[1].AsInteger() << 48) | + ((ulong)(byte)l[2].AsInteger() << 40) | + ((ulong)(byte)l[3].AsInteger() << 32) | + ((ulong)(byte)l[4].AsInteger() << 24) | + ((ulong)(byte)l[5].AsInteger() << 16) | + ((ulong)(byte)l[6].AsInteger() << 8) | + (byte)l[7].AsInteger()); } default: return 0; @@ -383,16 +366,12 @@ public virtual double AsReal() case OSDType.Real: return ((OSDReal)this).value; case OSDType.String: - string s = ((OSDString)this).value; - double dbl; - if (Double.TryParse(s, out dbl)) + if (Double.TryParse(((OSDString)this).value.AsSpan(), out double dbl)) return dbl; else return 0; case OSDType.OSDUTF8: - string us = ((OSDUTF8)this).value.ToString(); - double udbl; - if (Double.TryParse(us, out udbl)) + if (Double.TryParse(((OSDUTF8)this).value.ToString().AsSpan(), out double udbl)) return udbl; else return 0; @@ -449,14 +428,13 @@ public virtual UUID AsUUID() switch (Type) { case OSDType.String: - UUID uuid; - if (UUID.TryParse(((OSDString)this).value, out uuid)) + if (UUID.TryParse(((OSDString)this).value.AsSpan(), out UUID uuid)) return uuid; else return UUID.Zero; case OSDType.OSDUTF8: UUID ouuid; - if (UUID.TryParse(((OSDUTF8)this).value.ToString(), out ouuid)) + if (UUID.TryParse(((OSDUTF8)this).value.ToString().AsSpan(), out ouuid)) return ouuid; else return UUID.Zero; @@ -577,19 +555,19 @@ public Vector3 AsVector3() switch (Type) { case OSDType.String: - return Vector3.Parse(((OSDString)this).value); + return Vector3.Parse(((OSDString)this).value.AsSpan()); case OSDType.OSDUTF8: - return Vector3.Parse(((OSDUTF8)this).value.ToString()); + return Vector3.Parse(((OSDUTF8)this).value.ToString().AsSpan()); case OSDType.Array: List l = ((OSDArray)this).value; - Vector3 vector = Vector3.Zero; if (l.Count == 3) { - vector.X = (float)l[0].AsReal(); - vector.Y = (float)l[1].AsReal(); - vector.Z = (float)l[2].AsReal(); + return new Vector3( + (float)l[0].AsReal(), + (float)l[1].AsReal(), + (float)l[2].AsReal()); } - return vector; + return Vector3.Zero; default: return Vector3.Zero; } @@ -600,9 +578,9 @@ public Vector3d AsVector3d() switch (Type) { case OSDType.String: - return Vector3d.Parse(((OSDString)this).value); + return Vector3d.Parse(((OSDString)this).value.AsSpan()); case OSDType.OSDUTF8: - return Vector3d.Parse(((OSDUTF8)this).value.ToString()); + return Vector3d.Parse(((OSDUTF8)this).value.ToString().AsSpan()); case OSDType.Array: List l = ((OSDArray)this).value; Vector3d vector = Vector3d.Zero; @@ -690,35 +668,22 @@ public virtual void Clear() { } public virtual OSD Copy() { - switch (Type) + return Type switch { - case OSDType.Boolean: - return new OSDBoolean(((OSDBoolean)this).value); - case OSDType.Integer: - return new OSDInteger(((OSDInteger)this).value); - case OSDType.Real: - return new OSDReal(((OSDReal)this).value); - case OSDType.String: - return new OSDString(((OSDString)this).value); - case OSDType.OSDUTF8: - return new OSDUTF8(((OSDUTF8)this).value); - case OSDType.UUID: - return new OSDUUID(((OSDUUID)this).value); - case OSDType.Date: - return new OSDDate(((OSDDate)this).value); - case OSDType.URI: - return new OSDUri(((OSDUri)this).value); - case OSDType.Binary: - return new OSDBinary(((OSDBinary)this).value); - case OSDType.Map: - return new OSDMap(((OSDMap)this).dicvalue); - case OSDType.Array: - return new OSDArray(((OSDArray)this).value); - case OSDType.LLSDxml: - return new OSDBoolean(((OSDBoolean)this).value); - default: - return new OSD(); - } + OSDType.Boolean => new OSDBoolean(((OSDBoolean)this).value), + OSDType.Integer => new OSDInteger(((OSDInteger)this).value), + OSDType.Real => new OSDReal(((OSDReal)this).value), + OSDType.String => new OSDString(((OSDString)this).value), + OSDType.OSDUTF8 => new OSDUTF8(((OSDUTF8)this).value), + OSDType.UUID => new OSDUUID(((OSDUUID)this).value), + OSDType.Date => new OSDDate(((OSDDate)this).value), + OSDType.URI => new OSDUri(((OSDUri)this).value), + OSDType.Binary => new OSDBinary(((OSDBinary)this).value), + OSDType.Map => new OSDMap(((OSDMap)this).dicvalue), + OSDType.Array => new OSDArray(((OSDArray)this).value), + OSDType.LLSDxml => new OSDBoolean(((OSDBoolean)this).value), + _ => new OSD(), + }; } public override string ToString() @@ -765,106 +730,109 @@ public override string ToString() return "undef"; } } - + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static OSD FromBoolean(bool value) { return new OSDBoolean(value); } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static OSD FromInteger(int value) { return new OSDInteger(value); } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static OSD FromInteger(uint value) { return new OSDInteger((int)value); } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static OSD FromInteger(short value) { return new OSDInteger((int)value); } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static OSD FromInteger(ushort value) { return new OSDInteger((int)value); } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static OSD FromInteger(sbyte value) { return new OSDInteger((int)value); } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static OSD FromInteger(byte value) { return new OSDInteger((int)value); } - public static OSD FromUInteger(uint value) { return new OSDBinary(value); } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static OSD FromUInteger(uint value) { return new OSDBinary(value); } public static OSD FromLong(long value) { return new OSDBinary(value); } - public static OSD FromULong(ulong value) { return new OSDBinary(value); } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static OSD FromULong(ulong value) { return new OSDBinary(value); } public static OSD FromReal(double value) { return new OSDReal(value); } - public static OSD FromReal(float value) { return new OSDReal((double)value); } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static OSD FromReal(float value) { return new OSDReal((double)value); } public static OSD FromString(string value) { return new OSDString(value); } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static OSD FromUUID(UUID value) { return new OSDUUID(value); } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static OSD FromDate(DateTime value) { return new OSDDate(value); } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static OSD FromUri(Uri value) { return new OSDUri(value); } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static OSD FromBinary(byte[] value) { return new OSDBinary(value); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static OSD FromVector2(Vector2 value) { - OSDArray array = new OSDArray(); - array.Add(OSD.FromReal(value.X)); - array.Add(OSD.FromReal(value.Y)); - return array; + return new OSDArray() { OSD.FromReal(value.X), OSD.FromReal(value.Y) }; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static OSD FromVector3(Vector3 value) { - OSDArray array = new OSDArray(); - array.Add(OSD.FromReal(value.X)); - array.Add(OSD.FromReal(value.Y)); - array.Add(OSD.FromReal(value.Z)); - return array; + return new OSDArray() { OSD.FromReal(value.X), OSD.FromReal(value.Y), OSD.FromReal(value.Z) }; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static OSD FromVector3d(Vector3d value) { - OSDArray array = new OSDArray(); - array.Add(OSD.FromReal(value.X)); - array.Add(OSD.FromReal(value.Y)); - array.Add(OSD.FromReal(value.Z)); - return array; + return new OSDArray() { OSD.FromReal(value.X), OSD.FromReal(value.Y), OSD.FromReal(value.Z) }; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static OSD FromVector4(Vector4 value) { - OSDArray array = new OSDArray(); - array.Add(OSD.FromReal(value.X)); - array.Add(OSD.FromReal(value.Y)); - array.Add(OSD.FromReal(value.Z)); - array.Add(OSD.FromReal(value.W)); - return array; + return new OSDArray() { OSD.FromReal(value.X), OSD.FromReal(value.Y), OSD.FromReal(value.Z), OSD.FromReal(value.W) }; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static OSD FromQuaternion(Quaternion value) { - OSDArray array = new OSDArray(); - array.Add(OSD.FromReal(value.X)); - array.Add(OSD.FromReal(value.Y)); - array.Add(OSD.FromReal(value.Z)); - array.Add(OSD.FromReal(value.W)); - return array; + return new OSDArray() { OSD.FromReal(value.X), OSD.FromReal(value.Y), OSD.FromReal(value.Z), OSD.FromReal(value.W) }; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static OSD FromColor4(Color4 value) { - OSDArray array = new OSDArray(); - array.Add(OSD.FromReal(value.R)); - array.Add(OSD.FromReal(value.G)); - array.Add(OSD.FromReal(value.B)); - array.Add(OSD.FromReal(value.A)); - return array; + return new OSDArray() { OSD.FromReal(value.R), OSD.FromReal(value.G), OSD.FromReal(value.B), OSD.FromReal(value.A) }; } public static OSD FromObject(object value) { if (value == null) { return new OSD(); } - else if (value is bool) { return new OSDBoolean((bool)value); } - else if (value is int) { return new OSDInteger((int)value); } - else if (value is uint) { return new OSDBinary((uint)value); } - else if (value is short) { return new OSDInteger((int)(short)value); } - else if (value is ushort) { return new OSDInteger((int)(ushort)value); } - else if (value is sbyte) { return new OSDInteger((int)(sbyte)value); } - else if (value is byte) { return new OSDInteger((int)(byte)value); } - else if (value is double) { return new OSDReal((double)value); } - else if (value is float) { return new OSDReal((double)(float)value); } - else if (value is string) { return new OSDString((string)value); } - else if (value is UUID) { return new OSDUUID((UUID)value); } - else if (value is DateTime) { return new OSDDate((DateTime)value); } - else if (value is Uri) { return new OSDUri((Uri)value); } - else if (value is byte[]) { return new OSDBinary((byte[])value); } - else if (value is long) { return new OSDBinary((long)value); } - else if (value is ulong) { return new OSDBinary((ulong)value); } - else if (value is Vector2) { return FromVector2((Vector2)value); } - else if (value is Vector3) { return FromVector3((Vector3)value); } - else if (value is Vector3d) { return FromVector3d((Vector3d)value); } - else if (value is Vector4) { return FromVector4((Vector4)value); } - else if (value is Quaternion) { return FromQuaternion((Quaternion)value); } - else if (value is Color4) { return FromColor4((Color4)value); } + else if (value is bool bv) { return new OSDBoolean(bv); } + else if (value is int iv) { return new OSDInteger(iv); } + else if (value is uint uiv) { return new OSDBinary(uiv); } + else if (value is short sv) { return new OSDInteger((int)sv); } + else if (value is ushort usv) { return new OSDInteger((int)usv); } + else if (value is sbyte sbv) { return new OSDInteger((int)sbv); } + else if (value is byte btv) { return new OSDInteger((int)btv); } + else if (value is double dv) { return new OSDReal(dv); } + else if (value is float fv) { return new OSDReal((double)fv); } + else if (value is string stv) { return new OSDString(stv); } + else if (value is UUID uidv) { return new OSDUUID(uidv); } + else if (value is DateTime dtmv) { return new OSDDate(dtmv); } + else if (value is Uri uriv) { return new OSDUri(uriv); } + else if (value is byte[] btav) { return new OSDBinary(btav); } + else if (value is long lv) { return new OSDBinary(lv); } + else if (value is ulong ulv) { return new OSDBinary(ulv); } + else if (value is Vector2 v2v) { return FromVector2(v2v); } + else if (value is Vector3 v3v) { return FromVector3(v3v); } + else if (value is Vector3d v3dv) { return FromVector3d(v3dv); } + else if (value is Vector4 v4v) { return FromVector4(v4v); } + else if (value is Quaternion qv) { return FromQuaternion(qv); } + else if (value is Color4 c4v) { return FromColor4(c4v); } else return new OSD(); } @@ -953,14 +921,14 @@ public static object ToObject(Type type, OSD value) } else if (type == typeof(OSDArray)) { - OSDArray newArray = new OSDArray(); + OSDArray newArray = new(); foreach (OSD o in (OSDArray)value) newArray.Add(o); return newArray; } else if (type == typeof(OSDMap)) { - OSDMap newMap = new OSDMap(); + OSDMap newMap = new(); foreach (KeyValuePair o in (OSDMap)value) newMap.Add(o); return newMap; @@ -973,46 +941,86 @@ public static object ToObject(Type type, OSD value) #region Implicit Conversions + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator OSD(bool value) { return new OSDBoolean(value); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator OSD(int value) { return new OSDInteger(value); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator OSD(uint value) { return new OSDInteger((int)value); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator OSD(short value) { return new OSDInteger((int)value); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator OSD(ushort value) { return new OSDInteger((int)value); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator OSD(sbyte value) { return new OSDInteger((int)value); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator OSD(byte value) { return new OSDInteger((int)value); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator OSD(long value) { return new OSDBinary(value); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator OSD(ulong value) { return new OSDBinary(value); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator OSD(double value) { return new OSDReal(value); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator OSD(float value) { return new OSDReal(value); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator OSD(string value) { return new OSDString(value); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator OSD(UUID value) { return new OSDUUID(value); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator OSD(DateTime value) { return new OSDDate(value); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator OSD(Uri value) { return new OSDUri(value); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator OSD(byte[] value) { return new OSDBinary(value); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator OSD(Vector2 value) { return OSD.FromVector2(value); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator OSD(Vector3 value) { return OSD.FromVector3(value); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator OSD(Vector3d value) { return OSD.FromVector3d(value); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator OSD(Vector4 value) { return OSD.FromVector4(value); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator OSD(Quaternion value) { return OSD.FromQuaternion(value); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator OSD(Color4 value) { return OSD.FromColor4(value); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator bool(OSD value) { return value.AsBoolean(); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator int(OSD value) { return value.AsInteger(); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator uint(OSD value) { return value.AsUInteger(); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator long(OSD value) { return value.AsLong(); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator ulong(OSD value) { return value.AsULong(); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator double(OSD value) { return value.AsReal(); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator float(OSD value) { return (float)value.AsReal(); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator string(OSD value) { return value.AsString(); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator UUID(OSD value) { return value.AsUUID(); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator DateTime(OSD value) { return value.AsDate(); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator Uri(OSD value) { return value.AsUri(); } - public static implicit operator byte[](OSD value) { return value.AsBinary(); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator Vector2(OSD value) { return value.AsVector2(); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator byte[](OSD value) { return value.AsBinary(); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator Vector3(OSD value) { return value.AsVector3(); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator Vector3d(OSD value) { return value.AsVector3d(); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator Vector4(OSD value) { return value.AsVector4(); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator Quaternion(OSD value) { return value.AsQuaternion(); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator Color4(OSD value) { return value.AsColor4(); } #endregion Implicit Conversions @@ -1029,7 +1037,7 @@ public static OSDMap SerializeMembers(object obj) Type t = obj.GetType(); FieldInfo[] fields = t.GetFields(); - OSDMap map = new OSDMap(fields.Length); + OSDMap map = new(fields.Length); for (int i = 0; i < fields.Length; i++) { @@ -1064,8 +1072,7 @@ public static void DeserializeMembers(ref object obj, OSDMap serialized) FieldInfo field = fields[i]; if (!Attribute.IsDefined(field, typeof(NonSerializedAttribute))) { - OSD serializedField; - if (serialized.TryGetValue(field.Name, out serializedField)) + if (serialized.TryGetValue(field.Name, out OSD serializedField)) field.SetValue(obj, ToObject(field.FieldType, serializedField)); } } @@ -1085,12 +1092,19 @@ public OSDBoolean(bool value) this.value = value; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override bool AsBoolean() { return value; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override int AsInteger() { return value ? 1 : 0; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override double AsReal() { return value ? 1d : 0d; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override string AsString() { return value ? "1" : "0"; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override byte[] AsBinary() { return value ? trueBinary : falseBinary; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override OSD Copy() { return new OSDBoolean(value); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override string ToString() { return AsString(); } } @@ -1107,15 +1121,25 @@ public OSDInteger(int value) this.value = value; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override bool AsBoolean() { return value != 0; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override int AsInteger() { return value; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override uint AsUInteger() { return (uint)value; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override long AsLong() { return value; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override ulong AsULong() { return (ulong)value; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override double AsReal() { return (double)value; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override string AsString() { return value.ToString(); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override byte[] AsBinary() { return Utils.IntToBytesBig(value); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override OSD Copy() { return new OSDInteger(value); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override string ToString() { return AsString(); } } @@ -1178,10 +1202,14 @@ public override ulong AsULong() return (ulong)Math.Round(value); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override double AsReal() { return value; } // "r" ensures the value will correctly round-trip back through Double.TryParse + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override string AsString() { return value.ToString("r", Utils.EnUsCulture); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override byte[] AsBinary() { return Utils.DoubleToBytesBig(value); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override string ToString() { return AsString(); } } @@ -1204,8 +1232,11 @@ public OSDllsdxml(string value) this.value = String.Empty; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override string AsString() { return value; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override byte[] AsBinary() { return Encoding.UTF8.GetBytes(value); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override string ToString() { return AsString(); } } @@ -1258,8 +1289,7 @@ public override bool AsBoolean() public override int AsInteger() { - double dbl; - if (Double.TryParse(value.ToString(), out dbl)) + if (Double.TryParse(value.ToString().AsSpan(), out double dbl)) return (int)Math.Floor(dbl); else return 0; @@ -1267,8 +1297,7 @@ public override int AsInteger() public override uint AsUInteger() { - double dbl; - if (Double.TryParse(value.ToString(), out dbl)) + if (Double.TryParse(value.ToString().AsSpan(), out double dbl)) return (uint)Math.Floor(dbl); else return 0; @@ -1276,8 +1305,7 @@ public override uint AsUInteger() public override long AsLong() { - double dbl; - if (Double.TryParse(value.ToString(), out dbl)) + if (Double.TryParse(value.ToString().AsSpan(), out double dbl)) return (long)Math.Floor(dbl); else return 0; @@ -1285,8 +1313,7 @@ public override long AsLong() public override ulong AsULong() { - double dbl; - if (Double.TryParse(value.ToString(), out dbl)) + if (Double.TryParse(value.ToString().AsSpan(), out double dbl)) return (ulong)Math.Floor(dbl); else return 0; @@ -1294,8 +1321,7 @@ public override ulong AsULong() public override double AsReal() { - double dbl; - if (Double.TryParse(value.ToString(), out dbl)) + if (Double.TryParse(value.ToString().AsSpan(), out double dbl)) return dbl; else return 0d; @@ -1306,8 +1332,7 @@ public override double AsReal() public override UUID AsUUID() { - UUID uuid; - if (UUID.TryParse(value.ToString(), out uuid)) + if (UUID.TryParse(value.ToString().AsSpan(), out UUID uuid)) return uuid; else return UUID.Zero; @@ -1315,8 +1340,7 @@ public override UUID AsUUID() public override DateTime AsDate() { - DateTime dt; - if (DateTime.TryParse(value.ToString(), out dt)) + if (DateTime.TryParse(value.ToString().AsSpan(), out DateTime dt)) return dt; else return Utils.Epoch; @@ -1324,8 +1348,7 @@ public override DateTime AsDate() public override Uri AsUri() { - Uri uri; - if (Uri.TryCreate(value.ToString(), UriKind.RelativeOrAbsolute, out uri)) + if (Uri.TryCreate(value.ToString(), UriKind.RelativeOrAbsolute, out Uri uri)) return uri; else return null; @@ -1344,10 +1367,7 @@ public OSDString(string value) { Type = OSDType.String; // Refuse to hold null pointers - if (value != null) - this.value = value; - else - this.value = String.Empty; + this.value = value ?? string.Empty; } public override bool AsBoolean() @@ -1355,7 +1375,7 @@ public override bool AsBoolean() if (String.IsNullOrEmpty(value)) return false; - if (value == "0" || value.ToLower() == "false") + if (value.Equals("0") || value.Equals( "false", StringComparison.InvariantCultureIgnoreCase)) return false; return true; @@ -1363,8 +1383,7 @@ public override bool AsBoolean() public override int AsInteger() { - double dbl; - if (Double.TryParse(value, out dbl)) + if (Double.TryParse(value, out double dbl)) return (int)Math.Floor(dbl); else return 0; @@ -1372,8 +1391,7 @@ public override int AsInteger() public override uint AsUInteger() { - double dbl; - if (Double.TryParse(value, out dbl)) + if (Double.TryParse(value, out double dbl)) return (uint)Math.Floor(dbl); else return 0; @@ -1381,8 +1399,7 @@ public override uint AsUInteger() public override long AsLong() { - double dbl; - if (Double.TryParse(value, out dbl)) + if (Double.TryParse(value, out double dbl)) return (long)Math.Floor(dbl); else return 0; @@ -1390,8 +1407,7 @@ public override long AsLong() public override ulong AsULong() { - double dbl; - if (Double.TryParse(value, out dbl)) + if (Double.TryParse(value, out double dbl)) return (ulong)Math.Floor(dbl); else return 0; @@ -1399,8 +1415,7 @@ public override ulong AsULong() public override double AsReal() { - double dbl; - if (Double.TryParse(value, out dbl)) + if (Double.TryParse(value, out double dbl)) return dbl; else return 0d; @@ -1411,8 +1426,7 @@ public override double AsReal() public override UUID AsUUID() { - UUID uuid; - if (UUID.TryParse(value, out uuid)) + if (UUID.TryParse(value.AsSpan(), out UUID uuid)) return uuid; else return UUID.Zero; @@ -1420,8 +1434,7 @@ public override UUID AsUUID() public override DateTime AsDate() { - DateTime dt; - if (DateTime.TryParse(value, out dt)) + if (DateTime.TryParse(value, out DateTime dt)) return dt; else return Utils.Epoch; @@ -1429,8 +1442,7 @@ public override DateTime AsDate() public override Uri AsUri() { - Uri uri; - if (Uri.TryCreate(value, UriKind.RelativeOrAbsolute, out uri)) + if (Uri.TryCreate(value, UriKind.RelativeOrAbsolute, out Uri uri)) return uri; else return null; @@ -1452,11 +1464,17 @@ public OSDUUID(UUID value) this.value = value; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override OSD Copy() { return new OSDUUID(value); } - public override bool AsBoolean() { return (value.IsZero()) ? false : true; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override bool AsBoolean() { return value.IsNotZero(); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override string AsString() { return value.ToString(); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override UUID AsUUID() { return value; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override byte[] AsBinary() { return value.GetBytes(); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override string ToString() { return AsString(); } } @@ -1699,8 +1717,7 @@ public OSD this[string key] { get { - OSD llsd; - if (dicvalue.TryGetValue(key, out llsd)) + if (dicvalue.TryGetValue(key, out OSD llsd)) return llsd; else return new OSD(); @@ -1708,36 +1725,43 @@ public OSD this[string key] set { dicvalue[key] = value; } } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool ContainsKey(string key) { return dicvalue.ContainsKey(key); } - + + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Add(string key, OSD llsd) { dicvalue.Add(key, llsd); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Add(KeyValuePair kvp) { dicvalue.Add(kvp.Key, kvp.Value); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Remove(string key) { return dicvalue.Remove(key); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool TryGetValue(string key, out OSD llsd) { return dicvalue.TryGetValue(key, out llsd); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override void Clear() { dicvalue.Clear(); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Contains(KeyValuePair kvp) { // This is a bizarre function... we don't really implement it @@ -1750,11 +1774,13 @@ public void CopyTo(KeyValuePair[] array, int index) throw new NotImplementedException(); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Remove(KeyValuePair kvp) { return dicvalue.Remove(kvp.Key); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public System.Collections.IDictionaryEnumerator GetEnumerator() { return dicvalue.GetEnumerator(); @@ -1973,36 +1999,43 @@ public OSD this[int index] set { this.value[index] = value; } } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public int IndexOf(OSD llsd) { return value.IndexOf(llsd); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Insert(int index, OSD llsd) { value.Insert(index, llsd); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void RemoveAt(int index) { value.RemoveAt(index); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Add(OSD llsd) { value.Add(llsd); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override void Clear() { value.Clear(); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Contains(OSD llsd) { return value.Contains(llsd); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Contains(string element) { for (int i = 0; i < value.Count; i++) @@ -2019,6 +2052,7 @@ public void CopyTo(OSD[] array, int index) throw new NotImplementedException(); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Remove(OSD llsd) { return value.Remove(llsd); diff --git a/OpenMetaverse.Tests/OpenMetaverse.Tests.csproj b/OpenMetaverse.Tests/OpenMetaverse.Tests.csproj index 1ec7eb15..ac4a41ec 100644 --- a/OpenMetaverse.Tests/OpenMetaverse.Tests.csproj +++ b/OpenMetaverse.Tests/OpenMetaverse.Tests.csproj @@ -1,7 +1,7 @@  Local - net48 + net6.0 True 1591,1574,0419,0618 diff --git a/OpenMetaverse.Types/Color4.cs b/OpenMetaverse.Types/Color4.cs index 99d0e7cf..9f132558 100644 --- a/OpenMetaverse.Types/Color4.cs +++ b/OpenMetaverse.Types/Color4.cs @@ -69,9 +69,7 @@ public Color4(float r, float g, float b, float a) // Quick check to see if someone is doing something obviously wrong // like using float values from 0.0 - 255.0 if (r > 1f || g > 1f || b > 1f || a > 1f) - throw new ArgumentException( - String.Format("Attempting to initialize Color4 with out of range values <{0},{1},{2},{3}>", - r, g, b, a)); + throw new ArgumentException($"Attempting to initialize Color4 with out of range values <{r},{g},{b},{a}>"); // Valid range is from 0.0 to 1.0 R = Utils.Clamp(r, 0f, 1f); @@ -248,17 +246,19 @@ public void ToBytes(byte[] dest, int pos) /// instead of 255) public void ToBytes(byte[] dest, int pos, bool inverted) { - dest[pos + 0] = Utils.FloatToByte(R, 0f, 1f); - dest[pos + 1] = Utils.FloatToByte(G, 0f, 1f); - dest[pos + 2] = Utils.FloatToByte(B, 0f, 1f); - dest[pos + 3] = Utils.FloatToByte(A, 0f, 1f); - - if (inverted) + if (!inverted) + { + dest[pos + 0] = Utils.FloatZeroOneToByte(R); + dest[pos + 1] = Utils.FloatZeroOneToByte(G); + dest[pos + 2] = Utils.FloatZeroOneToByte(B); + dest[pos + 3] = Utils.FloatZeroOneToByte(A); + } + else { - dest[pos + 0] = (byte)(255 - dest[pos + 0]); - dest[pos + 1] = (byte)(255 - dest[pos + 1]); - dest[pos + 2] = (byte)(255 - dest[pos + 2]); - dest[pos + 3] = (byte)(255 - dest[pos + 3]); + dest[pos + 0] = (byte)(255 - Utils.FloatZeroOneToByte(R)); + dest[pos + 1] = (byte)(255 - Utils.FloatZeroOneToByte(G)); + dest[pos + 2] = (byte)(255 - Utils.FloatZeroOneToByte(B)); + dest[pos + 3] = (byte)(255 - Utils.FloatZeroOneToByte(A)); } } @@ -280,8 +280,8 @@ public float GetHue() { const float HUE_MAX = 360f; - float max = Math.Max(Math.Max(R, G), B); - float min = Math.Min(Math.Min(R, B), B); + float max = MathF.Max(MathF.Max(R, G), B); + float min = MathF.Min(MathF.Min(R, B), B); if (max == min) { @@ -313,22 +313,17 @@ public float GetHue() /// public void ClampValues() { - if (R < 0f) - R = 0f; - if (G < 0f) - G = 0f; - if (B < 0f) - B = 0f; - if (A < 0f) - A = 0f; - if (R > 1f) - R = 1f; - if (G > 1f) - G = 1f; - if (B > 1f) - B = 1f; - if (A > 1f) - A = 1f; + if (R < 0f) R = 0f; + else if (R > 1f) R = 1f; + + if (G < 0f) G = 0f; + else if(G > 1f) G = 1f; + + if (B < 0f) B = 0f; + else if (B > 1f) B = 1f; + + if (A < 0f) A = 0f; + else if (A > 1f) A = 1f; } #endregion Public Methods @@ -444,12 +439,12 @@ public static Color4 Lerp(Color4 value1, Color4 value2, float amount) public override string ToString() { - return String.Format(Utils.EnUsCulture, "<{0}, {1}, {2}, {3}>", R, G, B, A); + return String.Format(Utils.EnUsCulture, $"<{R}, {G}, {B}, {A}>"); } public string ToRGBString() { - return String.Format(Utils.EnUsCulture, "<{0}, {1}, {2}>", R, G, B); + return String.Format(Utils.EnUsCulture, $"<{R}, {G}, {B}>"); } public override bool Equals(object obj) @@ -481,7 +476,7 @@ public override int GetHashCode() return !(lhs == rhs); } - public static Color4 operator +(Color4 lhs, Color4 rhs) + public static Color4 operator +(Color4 lhs, in Color4 rhs) { lhs.R += rhs.R; lhs.G += rhs.G; @@ -492,7 +487,7 @@ public override int GetHashCode() return lhs; } - public static Color4 operator -(Color4 lhs, Color4 rhs) + public static Color4 operator -(Color4 lhs, in Color4 rhs) { lhs.R -= rhs.R; lhs.G -= rhs.G; @@ -503,7 +498,7 @@ public override int GetHashCode() return lhs; } - public static Color4 operator *(Color4 lhs, Color4 rhs) + public static Color4 operator *(Color4 lhs, in Color4 rhs) { lhs.R *= rhs.R; lhs.G *= rhs.G; @@ -517,9 +512,9 @@ public override int GetHashCode() #endregion Operators /// A Color4 with zero RGB values and fully opaque (alpha 1.0) - public readonly static Color4 Black = new Color4(0f, 0f, 0f, 1f); + public readonly static Color4 Black = new(0f, 0f, 0f, 1f); /// A Color4 with full RGB values (1.0) and fully opaque (alpha 1.0) - public readonly static Color4 White = new Color4(1f, 1f, 1f, 1f); + public readonly static Color4 White = new(1f, 1f, 1f, 1f); } } diff --git a/OpenMetaverse.Types/Enums.cs b/OpenMetaverse.Types/Enums.cs index cfa5c346..e7bb202c 100644 --- a/OpenMetaverse.Types/Enums.cs +++ b/OpenMetaverse.Types/Enums.cs @@ -104,7 +104,9 @@ public enum AssetType : sbyte /// Linden mesh format Mesh = 49, - Settings = 56 + Settings = 56, + /// Render material + Material = 57 } /// @@ -170,6 +172,8 @@ public enum FolderType : sbyte MarkplaceStock = 54, /// Settings folder Settings = 56, + /// Render materials folder + Material = 57, /// Hypergrid Suitcase folder Suitcase = 100 } @@ -236,6 +240,8 @@ public enum InventoryType : sbyte Mesh = 22, Settings = 25, + + Material = 26 } /// diff --git a/OpenMetaverse.Types/EnumsPrimitive.cs b/OpenMetaverse.Types/EnumsPrimitive.cs index e0a94eb3..47d2568f 100644 --- a/OpenMetaverse.Types/EnumsPrimitive.cs +++ b/OpenMetaverse.Types/EnumsPrimitive.cs @@ -234,6 +234,9 @@ public enum ExtraParamType : ushort LightImage = 0x40, /// Whether this object is a mesh Mesh = 0x60, + MeshFlag = 0x70, + RenderMaterial = 0x80, + ReflectionProbe = 0x90 } /// diff --git a/OpenMetaverse.Types/Matrix3x3.cs b/OpenMetaverse.Types/Matrix3x3.cs index 4ffff538..a807808b 100644 --- a/OpenMetaverse.Types/Matrix3x3.cs +++ b/OpenMetaverse.Types/Matrix3x3.cs @@ -108,7 +108,7 @@ public Matrix3x3(float roll, float pitch, float yaw) this = CreateFromEulers(roll, pitch, yaw); } - public Matrix3x3( Matrix3x3 m) + public Matrix3x3(Matrix3x3 m) { M11 = m.M11; M12 = m.M12; @@ -157,25 +157,25 @@ public float Trace() /// Z euler angle public void GetEulerAngles(out float roll, out float pitch, out float yaw) { - double angleX, angleY, angleZ; - double cx, cy, cz; // cosines - double sx, sz; // sines + float angleX, angleY, angleZ; + float cx, cy, cz; // cosines + float sx, sz; // sines - angleY = Math.Asin(Utils.Clamp(M13, -1f, 1f)); - cy = Math.Cos(angleY); + angleY = MathF.Asin(Utils.Clamp(M13, -1f, 1f)); + cy = MathF.Cos(angleY); - if (Math.Abs(cy) > 0.005f) + if (MathF.Abs(cy) > 0.005f) { // No gimbal lock cx = M33 / cy; sx = (-M23) / cy; - angleX = (float)Math.Atan2(sx, cx); + angleX = MathF.Atan2(sx, cx); cz = M11 / cy; sz = (-M12) / cy; - angleZ = (float)Math.Atan2(sz, cz); + angleZ = MathF.Atan2(sz, cz); } else { @@ -185,13 +185,13 @@ public void GetEulerAngles(out float roll, out float pitch, out float yaw) cz = M22; sz = M21; - angleZ = Math.Atan2(sz, cz); + angleZ = MathF.Atan2(sz, cz); } // Return only positive angles in [0,360] - if (angleX < 0) angleX += 360d; - if (angleY < 0) angleY += 360d; - if (angleZ < 0) angleZ += 360d; + if (angleX < 0) angleX += 360f; + if (angleY < 0) angleY += 360f; + if (angleZ < 0) angleZ += 360f; roll = (float)angleX; pitch = (float)angleY; @@ -209,7 +209,7 @@ public Quaternion GetQuaternion() if (trace > Single.Epsilon) { - float s = 0.5f / (float)Math.Sqrt(trace); + float s = 0.5f / MathF.Sqrt(trace); quat.X = (M32 - M23) * s; quat.Y = (M13 - M31) * s; @@ -220,7 +220,7 @@ public Quaternion GetQuaternion() { if (M11 > M22 && M11 > M33) { - float s = 2.0f * (float)Math.Sqrt(1.0f + M11 - M22 - M33); + float s = 2.0f * MathF.Sqrt(1.0f + M11 - M22 - M33); quat.X = 0.25f * s; quat.Y = (M12 + M21) / s; @@ -229,7 +229,7 @@ public Quaternion GetQuaternion() } else if (M22 > M33) { - float s = 2.0f * (float)Math.Sqrt(1.0f + M22 - M11 - M33); + float s = 2.0f * MathF.Sqrt(1.0f + M22 - M11 - M33); quat.X = (M12 + M21) / s; quat.Y = 0.25f * s; @@ -238,7 +238,7 @@ public Quaternion GetQuaternion() } else { - float s = 2.0f * (float)Math.Sqrt(1.0f + M33 - M11 - M22); + float s = 2.0f * MathF.Sqrt(1.0f + M33 - M11 - M22); quat.X = (M13 + M31) / s; quat.Y = (M23 + M32) / s; @@ -252,9 +252,9 @@ public Quaternion GetQuaternion() public bool Decompose(out Vector3 scale, out Quaternion rotation) { - float sx = (float)Math.Sqrt(M11 * M11 + M12 * M12 + M13 * M13); - float sy = (float)Math.Sqrt(M21 * M21 + M22 * M22 + M23 * M23); - float sz = (float)Math.Sqrt(M31 * M31 + M32 * M32 + M33 * M33); + float sx = MathF.Sqrt(M11 * M11 + M12 * M12 + M13 * M13); + float sy = MathF.Sqrt(M21 * M21 + M22 * M22 + M23 * M23); + float sz = MathF.Sqrt(M31 * M31 + M32 * M32 + M33 * M33); scale = new Vector3(sx, sy, sz); if (sx == 0.0 || sy == 0.0 || sz == 0.0) @@ -276,7 +276,7 @@ public bool Decompose(out Vector3 scale, out Quaternion rotation) #region Static Methods - public static Matrix3x3 Add( Matrix3x3 matrix1, Matrix3x3 matrix2) + public static Matrix3x3 Add(Matrix3x3 matrix1, in Matrix3x3 matrix2) { return new Matrix3x3( matrix1.M11 + matrix2.M11, @@ -299,8 +299,8 @@ public static Matrix3x3 CreateFromAxisAngle(Vector3 axis, float angle) float x = axis.X; float y = axis.Y; float z = axis.Z; - float sin = (float)Math.Sin(angle); - float cos = (float)Math.Cos(angle); + float sin = MathF.Sin(angle); + float cos = MathF.Cos(angle); float xx = x * x; float yy = y * y; float zz = z * z; @@ -331,12 +331,12 @@ public static Matrix3x3 CreateFromAxisAngle(Vector3 axis, float angle) /// Z euler angle in radians public static Matrix3x3 CreateFromEulers(float roll, float pitch, float yaw) { - float a = (float)Math.Cos(roll); - float b = (float)Math.Sin(roll); - float c = (float)Math.Cos(pitch); - float d = (float)Math.Sin(pitch); - float e = (float)Math.Cos(yaw); - float f = (float)Math.Sin(yaw); + float a = MathF.Cos(roll); + float b = MathF.Sin(roll); + float c = MathF.Cos(pitch); + float d = MathF.Sin(pitch); + float e = MathF.Cos(yaw); + float f = MathF.Sin(yaw); float ad = a * d; float bd = b * d; @@ -388,8 +388,8 @@ public static Matrix3x3 CreateFromQuaternion(Quaternion rot) public static Matrix3x3 CreateRotationX(float radians) { - float cos = (float)Math.Cos(radians); - float sin = (float)Math.Sin(radians); + float cos = MathF.Cos(radians); + float sin = MathF.Sin(radians); return new Matrix3x3( 1f, 0f, 0f, @@ -400,8 +400,8 @@ public static Matrix3x3 CreateRotationX(float radians) public static Matrix3x3 CreateRotationY(float radians) { - float cos = (float)Math.Cos(radians); - float sin = (float)Math.Sin(radians); + float cos = MathF.Cos(radians); + float sin = MathF.Sin(radians); return new Matrix3x3( cos, 0f, -sin, @@ -412,8 +412,8 @@ public static Matrix3x3 CreateRotationY(float radians) public static Matrix3x3 CreateRotationZ(float radians) { - float cos = (float)Math.Cos(radians); - float sin = (float)Math.Sin(radians); + float cos = MathF.Cos(radians); + float sin = MathF.Sin(radians); return new Matrix3x3( cos, sin, 0f, @@ -431,7 +431,7 @@ public static Matrix3x3 CreateScale(Vector3 scale) ); } - public static Matrix3x3 Divide( Matrix3x3 matrix1, Matrix3x3 matrix2) + public static Matrix3x3 Divide(Matrix3x3 matrix1, Matrix3x3 matrix2) { return new Matrix3x3( matrix1.M11 / matrix2.M11, @@ -448,7 +448,7 @@ public static Matrix3x3 Divide( Matrix3x3 matrix1, Matrix3x3 matrix2) ); } - public static Matrix3x3 Divide( Matrix3x3 matrix1, float divider) + public static Matrix3x3 Divide(Matrix3x3 matrix1, float divider) { float oodivider = 1f / divider; return new Matrix3x3( @@ -466,7 +466,7 @@ public static Matrix3x3 Divide( Matrix3x3 matrix1, float divider) ); } - public static Matrix3x3 Lerp( Matrix3x3 matrix1, Matrix3x3 matrix2, float amount) + public static Matrix3x3 Lerp(Matrix3x3 matrix1, Matrix3x3 matrix2, float amount) { return new Matrix3x3( matrix1.M11 + ((matrix2.M11 - matrix1.M11) * amount), @@ -483,7 +483,7 @@ public static Matrix3x3 Lerp( Matrix3x3 matrix1, Matrix3x3 matrix2, float amou ); } - public static Matrix3x3 Multiply( Matrix3x3 matrix1, Matrix3x3 matrix2) + public static Matrix3x3 Multiply(Matrix3x3 matrix1, Matrix3x3 matrix2) { return new Matrix3x3( matrix1.M11 * matrix2.M11 + matrix1.M12 * matrix2.M21 + matrix1.M13 * matrix2.M31, @@ -500,7 +500,7 @@ public static Matrix3x3 Multiply( Matrix3x3 matrix1, Matrix3x3 matrix2) ); } - public static Matrix3x3 Multiply( Matrix3x3 matrix1, float scaleFactor) + public static Matrix3x3 Multiply(Matrix3x3 matrix1, float scaleFactor) { Matrix3x3 matrix; matrix.M11 = matrix1.M11 * scaleFactor; @@ -518,7 +518,7 @@ public static Matrix3x3 Multiply( Matrix3x3 matrix1, float scaleFactor) return matrix; } - public static Matrix3x3 Negate( Matrix3x3 matrix) + public static Matrix3x3 Negate(Matrix3x3 matrix) { return new Matrix3x3( -matrix.M11, -matrix.M12, -matrix.M13, @@ -527,7 +527,7 @@ public static Matrix3x3 Negate( Matrix3x3 matrix) ); } - public static Matrix3x3 Subtract( Matrix3x3 matrix1, Matrix3x3 matrix2) + public static Matrix3x3 Subtract(Matrix3x3 matrix1, Matrix3x3 matrix2) { return new Matrix3x3( matrix1.M11 - matrix2.M11, @@ -544,7 +544,7 @@ public static Matrix3x3 Subtract( Matrix3x3 matrix1, Matrix3x3 matrix2) ); } - public static Matrix3x3 Transform( Matrix3x3 value, Quaternion rotation) + public static Matrix3x3 Transform(Matrix3x3 value, Quaternion rotation) { float x2 = rotation.X + rotation.X; float y2 = rotation.Y + rotation.Y; @@ -598,20 +598,20 @@ public static Matrix3x3 Inverse3x3(Matrix3x3 matrix) return (Adjoint3x3(matrix) / matrix.Determinant3x3()); } - public static Matrix3x3 Adjoint3x3( Matrix3x3 matrix) + public static Matrix3x3 Adjoint3x3(Matrix3x3 matrix) { Matrix3x3 adjointMatrix = new Matrix3x3(); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) - adjointMatrix[i,j] = (float)(Math.Pow(-1, i + j) * (Minor(matrix, i, j).Determinant3x3())); + adjointMatrix[i,j] = MathF.Pow(-1, i + j) * (Minor(matrix, i, j).Determinant3x3()); } adjointMatrix = Transpose(adjointMatrix); return adjointMatrix; } - public static Matrix3x3 Inverse( Matrix3x3 matrix) + public static Matrix3x3 Inverse(Matrix3x3 matrix) { if (matrix.Determinant() == 0f) throw new ArgumentException("Singular matrix inverse not possible"); @@ -619,13 +619,13 @@ public static Matrix3x3 Inverse( Matrix3x3 matrix) return (Adjoint(matrix) / matrix.Determinant()); } - public static Matrix3x3 Adjoint( Matrix3x3 matrix) + public static Matrix3x3 Adjoint(Matrix3x3 matrix) { - Matrix3x3 adjointMatrix = new Matrix3x3(); + Matrix3x3 adjointMatrix = new(); for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) - adjointMatrix[i,j] = (float)(Math.Pow(-1, i + j) * ((Minor(matrix, i, j)).Determinant3x3())); + adjointMatrix[i,j] = MathF.Pow(-1, i + j) * ((Minor(matrix, i, j)).Determinant3x3()); } adjointMatrix = Transpose(adjointMatrix); @@ -634,7 +634,7 @@ public static Matrix3x3 Adjoint( Matrix3x3 matrix) public static Matrix3x3 Minor(Matrix3x3 matrix, int row, int col) { - Matrix3x3 minor = new Matrix3x3(); + Matrix3x3 minor = new(); int m = 0, n = 0; for (int i = 0; i < 3; i++) @@ -694,47 +694,47 @@ public override string ToString() #region Operators - public static bool operator ==( Matrix3x3 left, Matrix3x3 right) + public static bool operator ==(Matrix3x3 left, Matrix3x3 right) { return left.Equals(right); } - public static bool operator !=( Matrix3x3 left, Matrix3x3 right) + public static bool operator !=(Matrix3x3 left, Matrix3x3 right) { return !left.Equals(right); } - public static Matrix3x3 operator +( Matrix3x3 left, Matrix3x3 right) + public static Matrix3x3 operator +(Matrix3x3 left, Matrix3x3 right) { return Add(left, right); } - public static Matrix3x3 operator -( Matrix3x3 matrix) + public static Matrix3x3 operator -(Matrix3x3 matrix) { return Negate(matrix); } - public static Matrix3x3 operator -( Matrix3x3 left, Matrix3x3 right) + public static Matrix3x3 operator -(Matrix3x3 left, Matrix3x3 right) { return Subtract(left, right); } - public static Matrix3x3 operator *( Matrix3x3 left, Matrix3x3 right) + public static Matrix3x3 operator *(Matrix3x3 left, Matrix3x3 right) { return Multiply(left, right); } - public static Matrix3x3 operator *( Matrix3x3 left, float scalar) + public static Matrix3x3 operator *(Matrix3x3 left, float scalar) { return Multiply(left, scalar); } - public static Matrix3x3 operator /( Matrix3x3 left, Matrix3x3 right) + public static Matrix3x3 operator /(Matrix3x3 left, Matrix3x3 right) { return Divide(left, right); } - public static Matrix3x3 operator /( Matrix3x3 matrix, float divider) + public static Matrix3x3 operator /(Matrix3x3 matrix, float divider) { return Divide(matrix, divider); } @@ -875,10 +875,10 @@ public Vector3 this[int row] #endregion Operators /// A 3x3 matrix containing all zeroes - public static readonly Matrix3x3 Zero = new Matrix3x3(); + public static readonly Matrix3x3 Zero = new(); /// A 3x3 identity matrix - public static readonly Matrix3x3 Identity = new Matrix3x3( + public static readonly Matrix3x3 Identity = new( 1f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 1f); diff --git a/OpenMetaverse.Types/Matrix4.cs b/OpenMetaverse.Types/Matrix4.cs index 4321bb20..fb5d5edd 100644 --- a/OpenMetaverse.Types/Matrix4.cs +++ b/OpenMetaverse.Types/Matrix4.cs @@ -185,25 +185,25 @@ public float Trace() /// Z euler angle public void GetEulerAngles(out float roll, out float pitch, out float yaw) { - double angleX, angleY, angleZ; - double cx, cy, cz; // cosines - double sx, sz; // sines + float angleX, angleY, angleZ; + float cx, cy, cz; // cosines + float sx, sz; // sines - angleY = Math.Asin(Utils.Clamp(M13, -1f, 1f)); - cy = Math.Cos(angleY); + angleY = MathF.Asin(Utils.Clamp(M13, -1f, 1f)); + cy = MathF.Cos(angleY); - if (Math.Abs(cy) > 0.005f) + if (MathF.Abs(cy) > 0.005f) { // No gimbal lock cx = M33 / cy; sx = (-M23) / cy; - angleX = (float)Math.Atan2(sx, cx); + angleX = MathF.Atan2(sx, cx); cz = M11 / cy; sz = (-M12) / cy; - angleZ = (float)Math.Atan2(sz, cz); + angleZ = MathF.Atan2(sz, cz); } else { @@ -213,17 +213,17 @@ public void GetEulerAngles(out float roll, out float pitch, out float yaw) cz = M22; sz = M21; - angleZ = Math.Atan2(sz, cz); + angleZ = MathF.Atan2(sz, cz); } // Return only positive angles in [0,360] - if (angleX < 0) angleX += 360d; - if (angleY < 0) angleY += 360d; - if (angleZ < 0) angleZ += 360d; + if (angleX < 0) angleX += 360f; + if (angleY < 0) angleY += 360f; + if (angleZ < 0) angleZ += 360f; - roll = (float)angleX; - pitch = (float)angleY; - yaw = (float)angleZ; + roll = angleX; + pitch = angleY; + yaw = angleZ; } /// @@ -237,7 +237,7 @@ public Quaternion GetQuaternion() if (trace > Single.Epsilon) { - float s = 0.5f / (float)Math.Sqrt(trace); + float s = 0.5f / MathF.Sqrt(trace); quat.X = (M32 - M23) * s; quat.Y = (M13 - M31) * s; @@ -248,7 +248,7 @@ public Quaternion GetQuaternion() { if (M11 > M22 && M11 > M33) { - float s = 2.0f * (float)Math.Sqrt(1.0f + M11 - M22 - M33); + float s = 2.0f * MathF.Sqrt(1.0f + M11 - M22 - M33); quat.X = 0.25f * s; quat.Y = (M12 + M21) / s; @@ -257,7 +257,7 @@ public Quaternion GetQuaternion() } else if (M22 > M33) { - float s = 2.0f * (float)Math.Sqrt(1.0f + M22 - M11 - M33); + float s = 2.0f * MathF.Sqrt(1.0f + M22 - M11 - M33); quat.X = (M12 + M21) / s; quat.Y = 0.25f * s; @@ -266,7 +266,7 @@ public Quaternion GetQuaternion() } else { - float s = 2.0f * (float)Math.Sqrt(1.0f + M33 - M11 - M22); + float s = 2.0f * MathF.Sqrt(1.0f + M33 - M11 - M22); quat.X = (M13 + M31) / s; quat.Y = (M23 + M32) / s; @@ -286,9 +286,9 @@ public bool Decompose(out Vector3 scale, out Quaternion rotation, out Vector3 tr float ys = (Math.Sign(M21 * M22 * M23 * M24) < 0) ? -1 : 1; float zs = (Math.Sign(M31 * M32 * M33 * M34) < 0) ? -1 : 1; - xs *= (float)Math.Sqrt(M11 * M11 + M12 * M12 + M13 * M13); - ys *= (float)Math.Sqrt(M21 * M21 + M22 * M22 + M23 * M23); - zs *= (float)Math.Sqrt(M31 * M31 + M32 * M32 + M33 * M33); + xs *= MathF.Sqrt(M11 * M11 + M12 * M12 + M13 * M13); + ys *= MathF.Sqrt(M21 * M21 + M22 * M22 + M23 * M23); + zs *= MathF.Sqrt(M31 * M31 + M32 * M32 + M33 * M33); scale = new Vector3(xs, ys, zs); @@ -343,8 +343,8 @@ public static Matrix4 CreateFromAxisAngle(Vector3 axis, float angle) float x = axis.X; float y = axis.Y; float z = axis.Z; - float sin = (float)Math.Sin(angle); - float cos = (float)Math.Cos(angle); + float sin = MathF.Sin(angle); + float cos = MathF.Cos(angle); float xx = x * x; float yy = y * y; float zz = z * z; @@ -386,12 +386,12 @@ public static Matrix4 CreateFromEulers(float roll, float pitch, float yaw) float a, b, c, d, e, f; float ad, bd; - a = (float)Math.Cos(roll); - b = (float)Math.Sin(roll); - c = (float)Math.Cos(pitch); - d = (float)Math.Sin(pitch); - e = (float)Math.Cos(yaw); - f = (float)Math.Sin(yaw); + a = MathF.Cos(roll); + b = MathF.Sin(roll); + c = MathF.Cos(pitch); + d = MathF.Sin(pitch); + e = MathF.Cos(yaw); + f = MathF.Sin(yaw); ad = a * d; bd = b * d; @@ -491,8 +491,8 @@ public static Matrix4 CreateRotationX(float radians) { Matrix4 matrix; - float cos = (float)Math.Cos(radians); - float sin = (float)Math.Sin(radians); + float cos = MathF.Cos(radians); + float sin = MathF.Sin(radians); matrix.M11 = 1f; matrix.M12 = 0f; @@ -521,8 +521,8 @@ public static Matrix4 CreateRotationY(float radians) { Matrix4 matrix; - float cos = (float)Math.Cos(radians); - float sin = (float)Math.Sin(radians); + float cos = MathF.Cos(radians); + float sin = MathF.Sin(radians); matrix.M11 = cos; matrix.M12 = 0f; @@ -551,8 +551,8 @@ public static Matrix4 CreateRotationZ(float radians) { Matrix4 matrix; - float cos = (float)Math.Cos(radians); - float sin = (float)Math.Sin(radians); + float cos = MathF.Cos(radians); + float sin = MathF.Sin(radians); matrix.M11 = cos; matrix.M12 = sin; @@ -933,7 +933,7 @@ public static Matrix4 Adjoint3x3(Matrix4 matrix) for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) - adjointMatrix[i, j] = (float)(Math.Pow(-1, i + j) * (Minor(matrix, i, j).Determinant3x3())); + adjointMatrix[i,j] = MathF.Pow(-1, i + j) * (Minor(matrix, i, j).Determinant3x3()); } adjointMatrix = Transpose(adjointMatrix); @@ -954,7 +954,7 @@ public static Matrix4 Adjoint(Matrix4 matrix) for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) - adjointMatrix[i, j] = (float)(Math.Pow(-1, i + j) * ((Minor(matrix, i, j)).Determinant3x3())); + adjointMatrix[i,j] = MathF.Pow(-1, i + j) * ((Minor(matrix, i, j)).Determinant3x3()); } adjointMatrix = Transpose(adjointMatrix); @@ -1260,7 +1260,7 @@ public Vector4 this[int row] public static readonly Matrix4 Zero = new Matrix4(); /// A 4x4 identity matrix - public static readonly Matrix4 Identity = new Matrix4( + public static readonly Matrix4 Identity = new( 1f, 0f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 0f, 1f, 0f, diff --git a/OpenMetaverse.Types/OSUTF8.cs b/OpenMetaverse.Types/OSUTF8.cs index 02cdf759..27b48b94 100644 --- a/OpenMetaverse.Types/OSUTF8.cs +++ b/OpenMetaverse.Types/OSUTF8.cs @@ -38,6 +38,8 @@ Ubit Umarov (Leal Duarte) 2020 using System.Text; using System.Collections.Generic; using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics.X86; +using System.Runtime.Intrinsics; namespace OpenMetaverse { @@ -182,7 +184,7 @@ public override bool Equals(object obj) public unsafe bool Equals(osUTF8Slice o) { - if (o == null || m_len != o.m_len) + if (o is null || m_len != o.m_len) return false; byte[] otherdata = o.m_data; @@ -237,7 +239,7 @@ public unsafe bool Equals(byte[] o) public unsafe bool Equals(osUTF8 o) { - if (o == null || m_len != o.m_len) + if (o is null || m_len != o.m_len) return false; byte[] otherdata = o.m_data; @@ -266,6 +268,22 @@ public bool Equals(string s) return Equals(o); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator ==(osUTF8 value1, osUTF8 value2) + { + if (value1 is null) + return value2 is null; + return value1.Equals(value2); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(osUTF8 value1, osUTF8 value2) + { + if (value1 is null) + return !(value2 is null); + return !value1.Equals(value2); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(char c) { @@ -274,7 +292,7 @@ public bool Equals(char c) public unsafe bool ACSIILowerEquals(osUTF8 o) { - if (o == null || m_len != o.m_len) + if (o is null || m_len != o.m_len) return false; fixed (byte* a = m_data, b = o.m_data) @@ -299,7 +317,7 @@ public unsafe bool ACSIILowerEquals(osUTF8 o) public unsafe bool ACSIILowerEquals(osUTF8Slice o) { - if (o == null || m_len != o.m_len) + if (o is null || m_len != o.m_len) return false; fixed (byte* a = m_data, b = o.m_data) @@ -543,7 +561,7 @@ public unsafe void AppendUUID(UUID u) { CheckCapacity(36); fixed (byte* d = m_data) - Utils.UUIDToByteDashString(ref u, d + m_len); + Utils.UUIDToByteDashString(u, d + m_len); m_len += 36; } @@ -987,43 +1005,113 @@ public unsafe static bool TryParseUUID(osUTF8 inp, out UUID result) if (val[13] != '-' || val[18] != '-' || val[23] != '-') return false; + if (Sse42.IsSupported) + { + Vector128 input = Unsafe.As>(ref Unsafe.AsRef(val)); + Vector128 upper = Ssse3.Shuffle(input, Vector128.Create(0, 2, 4, 6, 9, 11, 14, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff)); + Vector128 lower = Ssse3.Shuffle(input, Vector128.Create(1, 3, 5, 7, 10, 12, 15, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff)); + input = Unsafe.As>(ref Unsafe.AddByteOffset(ref Unsafe.AsRef(val), 16 + 3)); + Vector128 upperhalf = Ssse3.Shuffle(input, Vector128.Create(0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 2, 5, 7, 9, 11, 13, 15)); + Vector128 lowerhalf = Ssse3.Shuffle(input, Vector128.Create(0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1, 3, 6, 8, 10, 12, 14, 0xff)); + upper = Sse2.Or(upper, upperhalf); + lower = Sse2.Or(lower, lowerhalf); + + upper = Sse41.Insert(upper, Unsafe.As(ref Unsafe.AddByteOffset(ref Unsafe.AsRef(val), 16)), 7); + lower = Sse41.Insert(lower, Unsafe.As(ref Unsafe.AddByteOffset(ref Unsafe.AsRef(val), 17)), 7); + lower = Sse41.Insert(lower, Unsafe.As(ref Unsafe.AddByteOffset(ref Unsafe.AsRef(val), 35)), 15); + + Vector128 charf = Vector128.Create((byte)'f'); + Vector128 tmpcmp = Sse2.Subtract(charf, lower); + int cmp = Sse2.MoveMask(tmpcmp); + if (cmp != 0) + throw new Exception("bad"); + + tmpcmp = Sse2.Subtract(charf, upper); + cmp = Sse2.MoveMask(tmpcmp); + if (cmp != 0) + throw new Exception("bad"); + + Vector128 charTolower = Vector128.Create((byte)0x20); + Vector128 lowerLetters = Sse2.Or(lower, charTolower); + Vector128 upperLetters = Sse2.Or(upper, charTolower); + + Vector128 letterTohex = Vector128.Create((byte)('a' - '0' - 10)); + lowerLetters = Sse2.Subtract(lowerLetters, letterTohex); + upperLetters = Sse2.Subtract(upperLetters, letterTohex); + + Vector128 char9 = Vector128.Create((byte)'9'); + Vector128 above9lower = (Sse2.CompareGreaterThan(lower.AsSByte(), char9.AsSByte())).AsByte(); + + Vector128 ten = Vector128.Create((byte)('0' + 10)); + tmpcmp = Sse2.Subtract(lowerLetters, ten); + tmpcmp = Sse2.And(tmpcmp, above9lower); + cmp = Sse2.MoveMask(tmpcmp); + if (cmp != 0) + throw new Exception("bad"); + Vector128 above9upper = (Sse2.CompareGreaterThan(upper.AsSByte(), char9.AsSByte())).AsByte(); + + tmpcmp = Sse2.Subtract(upperLetters, ten); + tmpcmp = Sse2.And(tmpcmp, above9upper); + cmp = Sse2.MoveMask(tmpcmp); + if (cmp != 0) + throw new Exception("bad"); + + lower = Sse41.BlendVariable(lower, lowerLetters, above9lower); + upper = Sse41.BlendVariable(upper, upperLetters, above9upper); + Vector128 charzero = Vector128.Create((byte)'0'); + lower = Sse2.Subtract(lower, charzero); + cmp = Sse2.MoveMask(lower); + if (cmp != 0) + throw new Exception("bad"); + upper = Sse2.Subtract(upper, charzero); + cmp = Sse2.MoveMask(upper); + if (cmp != 0) + throw new Exception("bad"); + upper = Sse2.ShiftLeftLogical(upper.AsUInt16(), 4).AsByte(); + lower = Sse2.Or(lower, upper); + if (BitConverter.IsLittleEndian) + lower = Ssse3.Shuffle(lower, Vector128.Create((byte)0x03, 0x02, 0x01, 0x00, 0x05, 0x04, 0x07, 0x06, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F)); + Unsafe.As>(ref Unsafe.AsRef(in result)) = lower; + return true; + } + if (BitConverter.IsLittleEndian) { - result.bytea3 = (byte)Utils.HexToByte(val, 0); - result.bytea2 = (byte)Utils.HexToByte(val, 2); - result.bytea1 = (byte)Utils.HexToByte(val, 4); - result.bytea0 = (byte)Utils.HexToByte(val, 6); + result.bytea3 = Utils.HexToByte(val, 0); + result.bytea2 = Utils.HexToByte(val, 2); + result.bytea1 = Utils.HexToByte(val, 4); + result.bytea0 = Utils.HexToByte(val, 6); - result.byteb1 = (byte)Utils.HexToByte(val, 9); - result.byteb0 = (byte)Utils.HexToByte(val, 11); + result.byteb1 = Utils.HexToByte(val, 9); + result.byteb0 = Utils.HexToByte(val, 11); - result.bytec1 = (byte)Utils.HexToByte(val, 14); - result.bytec0 = (byte)Utils.HexToByte(val, 16); + result.bytec1 = Utils.HexToByte(val, 14); + result.bytec0 = Utils.HexToByte(val, 16); } else { - result.bytea0 = (byte)Utils.HexToByte(val, 0); - result.bytea1 = (byte)Utils.HexToByte(val, 2); - result.bytea2 = (byte)Utils.HexToByte(val, 4); - result.bytea3 = (byte)Utils.HexToByte(val, 6); + result.bytea0 = Utils.HexToByte(val, 0); + result.bytea1 = Utils.HexToByte(val, 2); + result.bytea2 = Utils.HexToByte(val, 4); + result.bytea3 = Utils.HexToByte(val, 6); - result.byteb0 = (byte)Utils.HexToByte(val, 9); - result.byteb1 = (byte)Utils.HexToByte(val, 11); + result.byteb0 = Utils.HexToByte(val, 9); + result.byteb1 = Utils.HexToByte(val, 11); - result.bytec0 = (byte)Utils.HexToByte(val, 14); - result.bytec1 = (byte)Utils.HexToByte(val, 16); + result.bytec0 = Utils.HexToByte(val, 14); + result.bytec1 = Utils.HexToByte(val, 16); } - result.d = (byte)Utils.HexToByte(val, 19); - result.e = (byte)Utils.HexToByte(val, 21); + result.d = Utils.HexToByte(val, 19); + result.e = Utils.HexToByte(val, 21); - result.f = (byte)Utils.HexToByte(val, 24); - result.g = (byte)Utils.HexToByte(val, 26); - result.h = (byte)Utils.HexToByte(val, 28); - result.i = (byte)Utils.HexToByte(val, 30); - result.j = (byte)Utils.HexToByte(val, 32); - result.k = (byte)Utils.HexToByte(val, 34); + result.f = Utils.HexToByte(val, 24); + result.g = Utils.HexToByte(val, 26); + result.h = Utils.HexToByte(val, 28); + result.i = Utils.HexToByte(val, 30); + result.j = Utils.HexToByte(val, 32); + result.k = Utils.HexToByte(val, 34); return true; } else @@ -1128,17 +1216,17 @@ public static byte[] GetASCIIBytes(string s) public static bool IsNullOrEmpty(osUTF8 u) { - return (u == null || u.m_len == 0); + return (u is null || u.m_len == 0); } public static bool IsEmpty(osUTF8 u) { - return (u == null || u.m_len == 0); + return (u is null || u.m_len == 0); } public static unsafe bool IsNullOrWhitespace(osUTF8 u) { - if(u == null || u.m_len == 0) + if(u is null || u.m_len == 0) return true; byte[] data = u.m_data; for (int i = 0; i < u.m_len; ++i) diff --git a/OpenMetaverse.Types/OSUTF8Constants.cs b/OpenMetaverse.Types/OSUTF8Constants.cs index 5840a8f8..25213dd3 100644 --- a/OpenMetaverse.Types/OSUTF8Constants.cs +++ b/OpenMetaverse.Types/OSUTF8Constants.cs @@ -130,9 +130,9 @@ public static class osUTF8Const public static readonly byte[] XMLelement_sale_info_Mid = osUTF8.GetASCIIBytes("sale_type"); public static readonly byte[] XMLelement_sale_info_End = osUTF8.GetASCIIBytes(""); - public static readonly byte[] OSUTF8null = osUTF8.GetASCIIBytes("null"); - public static readonly byte[] OSUTF8true = osUTF8.GetASCIIBytes("true"); - public static readonly byte[] OSUTF8false = osUTF8.GetASCIIBytes("false"); + public static readonly byte[] OSUTF8null = { (byte)'n', (byte)'u', (byte)'l', (byte)'l' }; + public static readonly byte[] OSUTF8true = { (byte)'t', (byte)'r', (byte)'u', (byte)'e' }; + public static readonly byte[] OSUTF8false = { (byte)'f', (byte)'a', (byte)'l', (byte)'s', (byte)'e' }; public static readonly byte[] base64Bytes = {(byte)'A',(byte)'B',(byte)'C',(byte)'D',(byte)'E',(byte)'F',(byte)'G',(byte)'H',(byte)'I',(byte)'J',(byte)'K',(byte)'L',(byte)'M',(byte)'N',(byte)'O', (byte)'P',(byte)'Q',(byte)'R',(byte)'S',(byte)'T',(byte)'U',(byte)'V',(byte)'W',(byte)'X',(byte)'Y',(byte)'Z',(byte)'a',(byte)'b',(byte)'c',(byte)'d', diff --git a/OpenMetaverse.Types/OSUTF8Slice.cs b/OpenMetaverse.Types/OSUTF8Slice.cs index c9b42b7f..21c5947d 100644 --- a/OpenMetaverse.Types/OSUTF8Slice.cs +++ b/OpenMetaverse.Types/OSUTF8Slice.cs @@ -38,6 +38,9 @@ Ubit Umarov (Leal Duarte) 2020 using System.Text; using System.Collections.Generic; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics.X86; +using System.Runtime.Intrinsics; namespace OpenMetaverse { @@ -132,7 +135,7 @@ public byte this[int i] i = 0; else if (i >= m_data.Length) i = m_data.Length - 1; - return m_data[i]; + return Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(m_data), i)); } set { @@ -140,7 +143,7 @@ public byte this[int i] { i += m_offset; if(i < m_len) - m_data[i] = value; + Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(m_data), i)) = value; } } } @@ -202,22 +205,22 @@ public void FromBytes(byte[] source, int offset, int len) public static bool IsNullOrEmpty(osUTF8Slice u) { - return (u == null || u.m_len == 0); + return (u is null || u.m_len == 0); } public static bool IsEmpty(osUTF8Slice u) { - return (u == null || u.m_len == 0); + return (u is null || u.m_len == 0); } public static unsafe bool IsNullOrWhitespace(osUTF8Slice u) { - if (u == null || u.m_len == 0) + if (u is null || u.m_len == 0) return true; byte[] data = u.m_data; for (int i = u.m_offset; i < u.m_offset + u.m_len; ++i) { - if (data[i] != 0x20) + if (Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(data), i)) != 0x20) return false; } return true; @@ -226,26 +229,11 @@ public static unsafe bool IsNullOrWhitespace(osUTF8Slice u) public unsafe override int GetHashCode() { int hash = m_len; - if (m_len < 8) + for (int i = m_offset; i < m_offset + m_len; ++i) { - for (int i = m_offset; i < m_offset + m_len; ++i) - { - hash += m_data[i]; - hash <<= 3; - hash += hash >> 26; - } - } - else - { - fixed (byte* a = &m_data[m_offset]) - { - for (int i = 0; i < m_len; ++i) - { - hash += a[i]; - hash <<= 5; - hash += hash >> 26; - } - } + hash += Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(m_data), i)); + hash <<= 3; + hash += hash >> 26; } return hash & 0x7fffffff; } @@ -260,103 +248,64 @@ public override string ToString() public override bool Equals(object obj) { - if (obj == null) + if (obj is null) return false; - if (obj is osUTF8) - return Equals((osUTF8)obj); + if (obj is osUTF8 o8) + return Equals(o8); - if (obj is osUTF8Slice) - return Equals((osUTF8Slice)obj); + if (obj is osUTF8Slice o8s) + return Equals(o8s); - if (obj is string) - return Equals((string)obj); + if (obj is string os) + return Equals(os); - if (obj is byte[]) - return Equals((byte[])obj); + if (obj is byte[] oba) + return Equals(oba); return false; } - public unsafe bool Equals(osUTF8Slice o) + public bool Equals(osUTF8Slice o) { - if (o == null || m_len != o.m_len) + if (o is null || m_len != o.m_len) return false; byte[] otherdata = o.m_data; - - if (m_len < 8) - { - for (int i = m_offset, j = o.m_offset; i < m_offset + m_len; ++i, ++j) - { - if (m_data[i] != otherdata[j]) - return false; - } - return true; - } - - fixed (byte* a = &m_data[m_offset], b = &otherdata[o.m_offset]) + for (int i = m_offset, j = o.m_offset; i < m_offset + m_len; ++i, ++j) { - for (int i = 0; i < m_len; ++i) - { - if (a[i] != b[i]) - return false; - } + if (Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(m_data), i)) != + Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(otherdata), j))) + return false; } - return true; } - public unsafe bool Equals(osUTF8 o) + public bool Equals(osUTF8 o) { - if (o == null || m_len != o.m_len) + if (o is null || m_len != o.m_len) return false; byte[] otherdata = o.m_data; - - if (m_len < 8) + for (int i = m_offset, j = 0; i < m_offset + m_len; ++i, ++j) { - for (int i = m_offset, j = 0; i < m_offset + m_len; ++i, ++j) - { - if (m_data[i] != otherdata[j]) - return false; - } - return true; - } - - fixed (byte* a = &m_data[m_offset], b = otherdata) - { - for (int i = 0; i < m_len; ++i) - { - if (a[i] != b[i]) - return false; - } + if (Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(m_data), i)) != + Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(otherdata), j))) + return false; } return true; } - public unsafe bool Equals(byte[] o) + public bool Equals(byte[] o) { if (o == null || m_len != o.Length) return false; - if (m_len < 8) + for (int i = m_offset, j = 0; i < m_offset + m_len; ++i, ++j) { - for (int i = m_offset, j = 0; i < m_offset + m_len; ++i, ++j) - { - if (m_data[i] != o[j]) - return false; - } - return true; - } - - fixed (byte* a = &m_data[m_offset], b = o) - { - for (int i = 0; i < m_len; ++i) - { - if (a[i] != b[i]) - return false; - } + if (Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(m_data), i)) != + Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(o), j))) + return false; } return true; } @@ -365,19 +314,36 @@ public bool Equals(string s) { if(string.IsNullOrEmpty(s)) return m_len == 0; - osUTF8 o = new osUTF8(s); + osUTF8 o = new(s); return Equals(o); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator ==(osUTF8Slice value1, osUTF8Slice value2) + { + if (value1 is null) + return value2 is null; + return value1.Equals(value2); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(osUTF8Slice value1, osUTF8Slice value2) + { + if (value1 is null) + return value2 is not null; + return !value1.Equals(value2); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(char c) { - return m_len == 1 && m_data[m_offset] == (byte)c; + return m_len == 1 && + Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(m_data), m_offset)) == (byte)c; } public unsafe bool ACSIILowerEquals(osUTF8 o) { - if (o == null || m_len != o.m_len) + if (o is null || m_len != o.m_len) return false; fixed (byte* a = &m_data[m_offset], b = o.m_data) @@ -522,7 +488,7 @@ public void AppendASCII(char c) { int indx = m_offset + m_len; CheckCapacity(ref indx, 1); - m_data[indx] = (byte)c; + Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(m_data), indx)) = (byte)c; ++m_len; } @@ -647,22 +613,22 @@ public osUTF8Slice SubUTF8(int start, int len) int last = start + len - 1; // cut at code points; - if (start > 0 && (m_data[start] & 0x80) != 0) + if (start > 0 && (Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(m_data), start)) & 0x80) != 0) { do { --last; } - while (start > 0 && (m_data[start] & 0xc0) != 0xc0); + while (start > 0 && (Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(m_data), start)) & 0xc0) != 0xc0); } - if (last > start && (m_data[last] & 0x80) != 0) + if (last > start && (Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(m_data), last)) & 0x80) != 0) { do { --last; } - while (last > start && (m_data[last] & 0xc0) != 0xc0); + while (last > start && (Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(m_data), last)) & 0xc0) != 0xc0); } return new osUTF8Slice(m_data, start, last - start + 1); @@ -709,22 +675,22 @@ public void SubUTF8Self(int start, int len) int last = start + len - 1; // cut at code points; - if (start > 0 && (m_data[start] & 0x80) != 0) + if (start > 0 && (Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(m_data), start)) & 0x80) != 0) { do { --last; } - while (start > 0 && (m_data[start] & 0xc0) != 0xc0); + while (start > 0 && (Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(m_data), start)) & 0xc0) != 0xc0); } - if (last > start && (m_data[last] & 0x80) != 0) + if (last > start && (Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(m_data), last)) & 0x80) != 0) { do { --last; } - while (last > start && (m_data[last] & 0xc0) != 0xc0); + while (last > start && (Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(m_data), last)) & 0xc0) != 0xc0); } m_offset = start; @@ -770,7 +736,7 @@ private bool checkAny(byte b, char[] chars) // inplace remove white spaces at start public void SelfTrimStart() { - while (m_len > 0 && m_data[m_offset] == 0x20) + while (m_len > 0 && Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(m_data), m_offset)) == 0x20) { ++m_offset; --m_len; @@ -779,7 +745,7 @@ public void SelfTrimStart() public void SelfTrimStart(byte b) { - while (m_len > 0 && m_data[m_offset] == b) + while (m_len > 0 && Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(m_data), m_offset)) == b) { ++m_offset; --m_len; @@ -788,7 +754,7 @@ public void SelfTrimStart(byte b) public void SelfTrimStart(byte[] b) { - while (m_len > 0 && checkAny(m_data[m_offset], b)) + while (m_len > 0 && checkAny(Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(m_data), m_offset)), b)) { ++m_offset; --m_len; @@ -797,7 +763,7 @@ public void SelfTrimStart(byte[] b) public void SelfTrimStart(char[] b) { - while (m_len > 0 && checkAny(m_data[m_offset], b)) + while (m_len > 0 && checkAny(Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(m_data), m_offset)), b)) { ++m_offset; --m_len; @@ -809,7 +775,7 @@ public void SelfTrimEnd() if (m_len == 0) return; int last = m_offset + m_len - 1; - while (m_len > 0 && m_data[last] == 0x20) + while (m_len > 0 && Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(m_data), last)) == 0x20) { --last; --m_len; @@ -821,7 +787,7 @@ public void SelfTrimEnd(byte b) if (m_len == 0) return; int last = m_offset + m_len - 1; - while (m_len > 0 && m_data[last] == b) + while (m_len > 0 && Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(m_data), last)) == b) { --last; --m_len; @@ -833,7 +799,7 @@ public void SelfTrimEnd(byte[] b) if (m_len == 0) return; int last = m_offset + m_len - 1; - while (m_len > 0 && checkAny(m_data[last], b)) + while (m_len > 0 && checkAny(Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(m_data), last)), b)) { --last; --m_len; @@ -845,7 +811,7 @@ public void SelfTrimEnd(char[] b) if (m_len == 0) return; int last = m_offset + m_len - 1; - while (m_len > 0 && checkAny(m_data[last], b)) + while (m_len > 0 && checkAny(Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(m_data), last)), b)) { --last; --m_len; @@ -1023,22 +989,22 @@ public bool StartsWith(string s) public bool StartsWith(byte b) { - return m_data[m_offset] == b; + return Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(m_data), m_offset)) == b; } public bool StartsWith(char b) { - return m_data[m_offset] == (byte)b; + return Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(m_data), m_offset)) == (byte)b; } public bool EndsWith(byte b) { - return m_data[m_offset + m_len - 1] == b; + return Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(m_data), m_offset + m_len - 1)) == b; } public bool EndsWith(char b) { - return m_data[m_offset + m_len - 1] == (byte)b; + return Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(m_data), m_offset + m_len - 1)) == (byte)b; } public unsafe bool EndsWith(osUTF8Slice other) @@ -1100,22 +1066,9 @@ public bool EndsWith(string s) public unsafe int IndexOf(byte b) { - if (m_len > 8) - { - fixed (byte* a = &m_data[m_offset]) - { - for (int i = 0; i < m_len; ++i) - { - if (a[i] == b) - return i; - } - return -1; - } - } - for (int i = m_offset; i < m_offset + m_len; ++i) { - if (m_data[i] == b) + if (Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(m_data), i)) == b) return i - m_offset; } return -1; @@ -1210,48 +1163,24 @@ public int IndexOf(string s) return IndexOf(o); } - public unsafe int IndexOfAny(byte[] b) + public int IndexOfAny(byte[] b) { - if (m_len < 8) - { - for (int i = m_offset; i < m_offset + m_len; ++i) - { - if (checkAny(m_data[i], b)) - return i - m_offset; - } - return -1; - } - fixed (byte* a = &m_data[m_offset]) + for (int i = m_offset; i < m_offset + m_len; ++i) { - for (int i = 0; i < m_len; ++i) - { - if (checkAny(a[i], b)) - return i; - } - return -1; + if (checkAny(Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(m_data), i)), b)) + return i - m_offset; } + return -1; } - public unsafe int IndexOfAny(char[] b) + public int IndexOfAny(char[] b) { - if (m_len < 8) - { - for (int i = m_offset; i < m_offset + m_len; ++i) - { - if (checkAny(m_data[i], b)) - return i - m_offset; - } - return -1; - } - fixed (byte* a = &m_data[m_offset]) + for (int i = m_offset; i < m_offset + m_len; ++i) { - for (int i = 0; i < m_len; ++i) - { - if (checkAny(a[i], b)) - return i; - } - return -1; + if (checkAny(Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(m_data), i)), b)) + return i - m_offset; } + return -1; } public bool Contains(osUTF8Slice other) @@ -1363,35 +1292,15 @@ public unsafe bool ReadLine(out osUTF8Slice line) int lineend = -1; byte b = 0; - if (m_len < 8) - { - for (int i = m_offset; i < m_offset + m_len; ++i) - { - b = m_data[i]; - if (b == (byte)'\r' || b == (byte)'\n') - { - if (i > 0 && m_data[i - 1] == (byte)'\\') - continue; - lineend = i; - break; - } - } - } - else + for (int i = m_offset; i < m_offset + m_len; ++i) { - fixed (byte* a = &m_data[m_offset]) + b = Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(m_data), i)); + if (b == (byte)'\r' || b == (byte)'\n') { - for (int i = 0; i < m_len; ++i) - { - b = a[i]; - if (b == (byte)'\r' || b == (byte)'\n') - { - if (i > 0 && a[i - 1] == (byte)'\\') - continue; - lineend = i + m_offset; - break; - } - } + if (i > 0 && Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(m_data), i - 1)) == (byte)'\\') + continue; + lineend = i; + break; } } @@ -1425,7 +1334,7 @@ public unsafe bool ReadLine(out osUTF8Slice line) if (b == (byte)'\r') { - if (m_data[m_offset] == (byte)'\n') + if (Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(m_data), m_offset)) == (byte)'\n') { ++m_offset; --m_len; @@ -1445,35 +1354,15 @@ public unsafe bool SkipLine() int lineend = -1; byte b = 0; - if (m_len < 8) + for (int i = m_offset; i < m_offset + m_len; ++i) { - for (int i = m_offset; i < m_offset + m_len; ++i) + b = Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(m_data), i)); + if (b == (byte)'\r' || b == (byte)'\n') { - b = m_data[i]; - if (b == (byte)'\r' || b == (byte)'\n') - { - if (i > 0 && m_data[i - 1] == (byte)'\\') - continue; - lineend = i; - break; - } - } - } - else - { - fixed (byte* a = &m_data[m_offset]) - { - for (int i = 0; i < m_len; ++i) - { - b = a[i]; - if (b == (byte)'\r' || b == (byte)'\n') - { - if (i > 0 && a[i - 1] == (byte)'\\') - continue; - lineend = i + m_offset; - break; - } - } + if (i > 0 && Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(m_data), i - 1)) == (byte)'\\') + continue; + lineend = i; + break; } } @@ -1504,7 +1393,7 @@ public unsafe bool SkipLine() if (b == (byte)'\r') { - if (m_data[m_offset] == (byte)'\n') + if (Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(m_data), m_offset)) == (byte)'\n') { ++m_offset; --m_len; @@ -1581,12 +1470,12 @@ public bool TryParseInt(out int res) len += start; bool neg = false; - if (m_data[start] == (byte)'-') + if (Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(m_data), start)) == (byte)'-') { neg = true; ++start; } - else if (m_data[start] == (byte)'+') + else if (Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(m_data), start)) == (byte)'+') ++start; int b; @@ -1594,7 +1483,7 @@ public bool TryParseInt(out int res) { while (start < len) { - b = m_data[start]; + b = Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(m_data), start)); b -= (byte)'0'; if (b < 0 || b > 9) break; @@ -1625,12 +1514,12 @@ public static bool TryParseInt(osUTF8Slice t, out int res) len += start; bool neg = false; - if (data[start] == (byte)'-') + if (Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(data), start)) == (byte)'-') { neg = true; ++start; } - else if (data[start] == (byte)'+') + else if (Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(data), start)) == (byte)'+') ++start; int b; @@ -1638,7 +1527,7 @@ public static bool TryParseInt(osUTF8Slice t, out int res) { while (start < len) { - b = data[start]; + b = Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(data), start)); b -= (byte)'0'; if (b < 0 || b > 9) break; @@ -1684,43 +1573,113 @@ public unsafe static bool TryParseUUID(osUTF8Slice inp, out UUID result) if (val[13] != '-' || val[18] != '-' || val[23] != '-') return false; + if (Sse42.IsSupported) + { + Vector128 input = Unsafe.As>(ref Unsafe.AsRef(val)); + Vector128 upper = Ssse3.Shuffle(input, Vector128.Create(0, 2, 4, 6, 9, 11, 14, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff)); + Vector128 lower = Ssse3.Shuffle(input, Vector128.Create(1, 3, 5, 7, 10, 12, 15, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff)); + input = Unsafe.As>(ref Unsafe.AddByteOffset(ref Unsafe.AsRef(val), 16 + 3)); + Vector128 upperhalf = Ssse3.Shuffle(input, Vector128.Create(0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 2, 5, 7, 9, 11, 13, 15)); + Vector128 lowerhalf = Ssse3.Shuffle(input, Vector128.Create(0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1, 3, 6, 8, 10, 12, 14, 0xff)); + upper = Sse2.Or(upper, upperhalf); + lower = Sse2.Or(lower, lowerhalf); + + upper = Sse41.Insert(upper, Unsafe.As(ref Unsafe.AddByteOffset(ref Unsafe.AsRef(val), 16)), 7); + lower = Sse41.Insert(lower, Unsafe.As(ref Unsafe.AddByteOffset(ref Unsafe.AsRef(val), 17)), 7); + lower = Sse41.Insert(lower, Unsafe.As(ref Unsafe.AddByteOffset(ref Unsafe.AsRef(val), 35)), 15); + + Vector128 charf = Vector128.Create((byte)'f'); + Vector128 tmpcmp = Sse2.Subtract(charf, lower); + int cmp = Sse2.MoveMask(tmpcmp); + if (cmp != 0) + throw new Exception("bad"); + + tmpcmp = Sse2.Subtract(charf, upper); + cmp = Sse2.MoveMask(tmpcmp); + if (cmp != 0) + throw new Exception("bad"); + + Vector128 charTolower = Vector128.Create((byte)0x20); + Vector128 lowerLetters = Sse2.Or(lower, charTolower); + Vector128 upperLetters = Sse2.Or(upper, charTolower); + + Vector128 letterTohex = Vector128.Create((byte)('a' - '0' - 10)); + lowerLetters = Sse2.Subtract(lowerLetters, letterTohex); + upperLetters = Sse2.Subtract(upperLetters, letterTohex); + + Vector128 char9 = Vector128.Create((byte)'9'); + Vector128 above9lower = (Sse2.CompareGreaterThan(lower.AsSByte(), char9.AsSByte())).AsByte(); + + Vector128 ten = Vector128.Create((byte)('0' + 10)); + tmpcmp = Sse2.Subtract(lowerLetters, ten); + tmpcmp = Sse2.And(tmpcmp, above9lower); + cmp = Sse2.MoveMask(tmpcmp); + if (cmp != 0) + throw new Exception("bad"); + Vector128 above9upper = (Sse2.CompareGreaterThan(upper.AsSByte(), char9.AsSByte())).AsByte(); + + tmpcmp = Sse2.Subtract(upperLetters, ten); + tmpcmp = Sse2.And(tmpcmp, above9upper); + cmp = Sse2.MoveMask(tmpcmp); + if (cmp != 0) + throw new Exception("bad"); + + lower = Sse41.BlendVariable(lower, lowerLetters, above9lower); + upper = Sse41.BlendVariable(upper, upperLetters, above9upper); + Vector128 charzero = Vector128.Create((byte)'0'); + lower = Sse2.Subtract(lower, charzero); + cmp = Sse2.MoveMask(lower); + if (cmp != 0) + throw new Exception("bad"); + upper = Sse2.Subtract(upper, charzero); + cmp = Sse2.MoveMask(upper); + if (cmp != 0) + throw new Exception("bad"); + upper = Sse2.ShiftLeftLogical(upper.AsUInt16(), 4).AsByte(); + lower = Sse2.Or(lower, upper); + if (BitConverter.IsLittleEndian) + lower = Ssse3.Shuffle(lower, Vector128.Create((byte)0x03, 0x02, 0x01, 0x00, 0x05, 0x04, 0x07, 0x06, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F)); + Unsafe.As>(ref Unsafe.AsRef(in result)) = lower; + return true; + } + if (BitConverter.IsLittleEndian) { - result.bytea3 = (byte)Utils.HexToByte(val, 0); - result.bytea2 = (byte)Utils.HexToByte(val, 2); - result.bytea1 = (byte)Utils.HexToByte(val, 4); - result.bytea0 = (byte)Utils.HexToByte(val, 6); + result.bytea3 = Utils.HexToByte(val, 0); + result.bytea2 = Utils.HexToByte(val, 2); + result.bytea1 = Utils.HexToByte(val, 4); + result.bytea0 = Utils.HexToByte(val, 6); - result.byteb1 = (byte)Utils.HexToByte(val, 9); - result.byteb0 = (byte)Utils.HexToByte(val, 11); + result.byteb1 = Utils.HexToByte(val, 9); + result.byteb0 = Utils.HexToByte(val, 11); - result.bytec1 = (byte)Utils.HexToByte(val, 14); - result.bytec0 = (byte)Utils.HexToByte(val, 16); + result.bytec1 = Utils.HexToByte(val, 14); + result.bytec0 = Utils.HexToByte(val, 16); } else { - result.bytea0 = (byte)Utils.HexToByte(val, 0); - result.bytea1 = (byte)Utils.HexToByte(val, 2); - result.bytea2 = (byte)Utils.HexToByte(val, 4); - result.bytea3 = (byte)Utils.HexToByte(val, 6); + result.bytea0 = Utils.HexToByte(val, 0); + result.bytea1 = Utils.HexToByte(val, 2); + result.bytea2 = Utils.HexToByte(val, 4); + result.bytea3 = Utils.HexToByte(val, 6); - result.byteb0 = (byte)Utils.HexToByte(val, 9); - result.byteb1 = (byte)Utils.HexToByte(val, 11); + result.byteb0 = Utils.HexToByte(val, 9); + result.byteb1 = Utils.HexToByte(val, 11); - result.bytec0 = (byte)Utils.HexToByte(val, 14); - result.bytec1 = (byte)Utils.HexToByte(val, 16); + result.bytec0 = Utils.HexToByte(val, 14); + result.bytec1 = Utils.HexToByte(val, 16); } - result.d = (byte)Utils.HexToByte(val, 19); - result.e = (byte)Utils.HexToByte(val, 21); + result.d = Utils.HexToByte(val, 19); + result.e = Utils.HexToByte(val, 21); - result.f = (byte)Utils.HexToByte(val, 24); - result.g = (byte)Utils.HexToByte(val, 26); - result.h = (byte)Utils.HexToByte(val, 28); - result.i = (byte)Utils.HexToByte(val, 30); - result.j = (byte)Utils.HexToByte(val, 32); - result.k = (byte)Utils.HexToByte(val, 34); + result.f = Utils.HexToByte(val, 24); + result.g = Utils.HexToByte(val, 26); + result.h = Utils.HexToByte(val, 28); + result.i = Utils.HexToByte(val, 30); + result.j = Utils.HexToByte(val, 32); + result.k = Utils.HexToByte(val, 34); return true; } else diff --git a/OpenMetaverse.Types/OpenMetaverse.Types.csproj b/OpenMetaverse.Types/OpenMetaverse.Types.csproj index cd2892d1..8356b85c 100644 --- a/OpenMetaverse.Types/OpenMetaverse.Types.csproj +++ b/OpenMetaverse.Types/OpenMetaverse.Types.csproj @@ -1,7 +1,7 @@  Local - net48;netstandard2.0 + net6.0 OpenMetaverse 1591,1574,0419,0618 True @@ -13,4 +13,4 @@ - \ No newline at end of file + diff --git a/OpenMetaverse.Types/Quaternion.cs b/OpenMetaverse.Types/Quaternion.cs index be4d5475..2a462e81 100644 --- a/OpenMetaverse.Types/Quaternion.cs +++ b/OpenMetaverse.Types/Quaternion.cs @@ -28,6 +28,9 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Globalization; +using System.Text; +using System.Runtime.Intrinsics.X86; +using System.Runtime.Intrinsics; namespace OpenMetaverse { @@ -44,6 +47,13 @@ public struct Quaternion : IEquatable /// W value public float W; + public enum MainAxis : int + { + X = 0, + Y = 1, + Z = 2 + } + #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -78,7 +88,7 @@ public Quaternion(float x, float y, float z) Z = z; float xyzsum = 1f - (X * X) - (Y * Y) - (Z * Z); - W = (xyzsum > 1e-6f) ? (float)Math.Sqrt(xyzsum) : 0; + W = (xyzsum > 1e-6f) ? MathF.Sqrt(xyzsum) : 0; } /// @@ -100,46 +110,103 @@ public Quaternion(byte[] byteArray, int pos, bool normalized) [MethodImpl(MethodImplOptions.AggressiveInlining)] public Quaternion(Quaternion q) { - X = q.X; - Y = q.Y; - Z = q.Z; - W = q.W; + this = q; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Quaternion(Vector128 q) : this() + { + Unsafe.As>(ref Unsafe.AsRef(this)) = q; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Quaternion(MainAxis BaseAxis, float angle) + { + switch (BaseAxis) + { + case MainAxis.X: + W = MathF.Cos(0.5f * angle); + X = MathF.Sqrt(1.0f - W * W); + Y = 0; + Z = 0; + break; + case MainAxis.Y: + W = MathF.Cos(0.5f * angle); + Y = MathF.Sqrt(1.0f - W * W); + X = 0; + Z = 0; + break; + case MainAxis.Z: + W = MathF.Cos(0.5f * angle); + Z = MathF.Sqrt(1.0f - W * W); + X = 0; + Y = 0; + break; + default: //error + X = 0; + Y = 0; + Z = 0; + W = 1; + break; + } } #endregion Constructors #region Public Methods [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool ApproxEquals(Quaternion quat) + public readonly bool ApproxEquals(Quaternion quat) { // assume normalized - return Math.Abs(quat.X - X) < 1e-6f && - Math.Abs(quat.Y - Y) < 1e-6f && - Math.Abs(quat.Z - Z) < 1e-6f; + return MathF.Abs(quat.W - W) < 1e-6f && + MathF.Abs(quat.Z - Z) < 1e-6f && + MathF.Abs(quat.X - X) < 1e-6f; } + /* not faster + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly bool ApproxEquals2(in Quaternion quat) + { + if (Sse.IsSupported) + { + Vector128 tol = Vector128.Create(1e-6f); + + Vector128 a = Unsafe.As>(ref Unsafe.AsRef(this)); + Vector128 c = Sse.CompareEqual(tol, tol); + + Vector128 b = Unsafe.As>(ref Unsafe.AsRef(quat)); + c = Sse2.ShiftRightLogical(c.AsInt32(), 1).AsSingle(); + + a = Sse.Subtract(a, b); + a = Sse.And(a, c); + a = Sse.CompareLessThan(a, tol); + int res = Sse.MoveMask(a); + return res == 0x0f; + } + // assume normalized + return MathF.Abs(quat.X - X) < 1e-6f && + MathF.Abs(quat.Y - Y) < 1e-6f && + MathF.Abs(quat.Z - Z) < 1e-6f; + } + */ [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool ApproxEquals(Quaternion quat, float tolerance) + public readonly bool ApproxEquals(Quaternion quat, float tolerance) { // assume normalized - return Math.Abs(quat.X - X) < tolerance && - Math.Abs(quat.Y - Y) < tolerance && - Math.Abs(quat.Z - Z) < tolerance; + return MathF.Abs(quat.W - W) < tolerance && + MathF.Abs(quat.Z - Z) < tolerance && + MathF.Abs(quat.X - X) < tolerance; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsIdentity() + public readonly bool IsIdentity() { // assume normalized - if(W > (1.0f - 1e-6f)) - return true; - if (W < -(1.0f - 1e-6f)) - return true; - return false; + return MathF.Abs(W) > (1.0f - 1e-6f); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsIdentityOrZero() + public readonly bool IsIdentityOrZero() { // assume normalized if (X != 0) @@ -152,27 +219,60 @@ public bool IsIdentityOrZero() } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public float Length() + public readonly unsafe float Length() { - return (float)Math.Sqrt((X * X) + (Y * Y) + (Z * Z) + (W * W)); + if (Sse41.IsSupported) + { + Vector128 q = Unsafe.As>(ref Unsafe.AsRef(this)); + q = Sse41.DotProduct(q, q, 0xf1); + return MathF.Sqrt(q.ToScalar()); + } + else + return MathF.Sqrt((X * X) + (Y * Y) + (Z * Z) + (W * W)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public float LengthSquared() + public readonly unsafe float LengthSquared() { - return (X * X) + (Y * Y) + (Z * Z) + (W * W); + if (Sse41.IsSupported) + { + Vector128 q = Unsafe.As>(ref Unsafe.AsRef(this)); + q = Sse41.DotProduct(q, q, 0xf1); + return q.ToScalar(); + } + else + return (X * X) + (Y * Y) + (Z * Z) + (W * W); } /// /// Normalizes the quaternion /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Normalize() + public unsafe void Normalize() { + if (Sse41.IsSupported) + { + Vector128 q = Unsafe.As>(ref Unsafe.AsRef(this)); + Vector128 d = Sse41.DotProduct(q, q, 0xff); + float m = d.ToScalar(); + if (m > 1e-6f) + { + d = Sse.Sqrt(d); + q = Sse.Divide(q, d); + //d = Sse.ReciprocalSqrt(d); + //q = Sse.Multiply(q, d); + Unsafe.As>(ref this) = q; + return; + } + q = Vector128.Create(0f, 0f, 0f, 1f); + Unsafe.As>(ref this) = q; + return; + } + float mag = LengthSquared(); if (mag > 1e-6f) { - float oomag = 1f / (float)Math.Sqrt(mag); + float oomag = 1f / MathF.Sqrt(mag); X *= oomag; Y *= oomag; Z *= oomag; @@ -202,10 +302,10 @@ public void Invert() if (len > 1e-6f) { len = -1.0f / len; - X = X * len; - Y = Y * len; - Z = Z * len; - W = -W * len; + X *= len; + Y *= len; + Z *= len; + W *= -len; } else { @@ -217,33 +317,54 @@ public void Invert() } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public float Dot(Quaternion q2) - { - return (X * q2.X) + (Y * q2.Y) + (Z * q2.Z) + (W * q2.W); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public float Dot(ref Quaternion q2) + public readonly float Dot(Quaternion q2) { + if (Sse41.IsSupported) + { + Vector128 q = Unsafe.As>(ref Unsafe.AsRef(this)); + Vector128 d = Unsafe.As>(ref q2); + d = Sse41.DotProduct(q, d, 0xf1); + return d.ToScalar(); + } return (X * q2.X) + (Y * q2.Y) + (Z * q2.Z) + (W * q2.W); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Add(Quaternion quaternion2) + public void Add(in Quaternion quaternion2) { - X += quaternion2.X; - Y += quaternion2.Y; - Z += quaternion2.Z; - W += quaternion2.W; + if (Sse41.IsSupported) + { + Vector128 q = Unsafe.As>(ref Unsafe.AsRef(this)); + Vector128 d = Unsafe.As>(ref Unsafe.AsRef(quaternion2)); + d = Sse.Add(q, d); + Unsafe.As>(ref Unsafe.AsRef(this)) = d; + } + else + { + X += quaternion2.X; + Y += quaternion2.Y; + Z += quaternion2.Z; + W += quaternion2.W; + } } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Sub(Quaternion quaternion2) + public void Sub(in Quaternion quaternion2) { - X -= quaternion2.X; - Y -= quaternion2.Y; - Z -= quaternion2.Z; - W -= quaternion2.W; + if (Sse41.IsSupported) + { + Vector128 q = Unsafe.As>(ref Unsafe.AsRef(this)); + Vector128 d = Unsafe.As>(ref Unsafe.AsRef(quaternion2)); + d = Sse.Subtract(q, d); + Unsafe.As>(ref Unsafe.AsRef(this)) = d; + } + else + { + X -= quaternion2.X; + Y -= quaternion2.Y; + Z -= quaternion2.Z; + W -= quaternion2.W; + } } /// @@ -262,7 +383,7 @@ public void FromBytes(byte[] byteArray, int pos, bool normalized) if (normalized) { float xyzsum = 1f - (X * X) - (Y * Y) - (Z * Z); - W = (xyzsum > 1e-6f) ? (float)Math.Sqrt(xyzsum) : 0f; + W = (xyzsum > 1e-6f) ? MathF.Sqrt(xyzsum) : 0f; } else { @@ -275,16 +396,16 @@ public void FromBytes(byte[] byteArray, int pos, bool normalized) /// /// A 12 byte array containing normalized X, Y, and Z floating /// point values in order using little endian byte ordering - public byte[] GetBytes() + public readonly byte[] GetBytes() { byte[] bytes = new byte[12]; float norm = LengthSquared(); if (norm > 1e-6f || W < 0.9999f) { if (W < 0f) - norm = -1f / (float)Math.Sqrt(norm); + norm = -1f / MathF.Sqrt(norm); else - norm = 1f / (float)Math.Sqrt(norm); + norm = 1f / MathF.Sqrt(norm); Utils.FloatToBytesSafepos(norm * X, bytes, 0); Utils.FloatToBytesSafepos(norm * Y, bytes, 4); Utils.FloatToBytesSafepos(norm * Z, bytes, 8); @@ -304,24 +425,159 @@ public byte[] GetBytes() /// Destination byte array /// Position in the destination array to start /// writing. Must be at least 12 bytes before the end of the array - public void ToBytes(byte[] dest, int pos) + public readonly unsafe void ToBytes(byte[] dest, int pos) { float norm = LengthSquared(); if (norm > 1e-6f || norm < 0.9999f) { if (W < 0f) - norm = -1f / (float)Math.Sqrt(norm); + norm = -1f / MathF.Sqrt(norm); else - norm = 1f / (float)Math.Sqrt(norm); - Utils.FloatToBytesSafepos(norm * X, dest, pos); - Utils.FloatToBytesSafepos(norm * Y, dest, pos + 4); - Utils.FloatToBytesSafepos(norm * Z, dest, pos + 8); + norm = 1f / MathF.Sqrt(norm); + if (Utils.CanDirectCopyLE) + { + fixed (byte* d = &dest[0]) + { + *(float*)(d + pos) = norm * X; + *(float*)(d + pos + 4) = norm * Y; + *(float*)(d + pos + 8) = norm * Z; + } + } + else + { + Utils.FloatToBytesSafepos(norm * X, dest, pos); + Utils.FloatToBytesSafepos(norm * Y, dest, pos + 4); + Utils.FloatToBytesSafepos(norm * Z, dest, pos + 8); + } } else { - Utils.FloatToBytesSafepos(0, dest, pos); - Utils.FloatToBytesSafepos(0, dest, pos + 4); - Utils.FloatToBytesSafepos(0, dest, pos + 8); + if (Utils.CanDirectCopyLE) + { + fixed (byte* d = &dest[0]) + { + *(long*)(d + pos) = 0; + *(int*)(d + pos + 8) = 0; + } + } + else + { + Utils.FloatToBytesSafepos(0, dest, pos); + Utils.FloatToBytesSafepos(0, dest, pos + 4); + Utils.FloatToBytesSafepos(0, dest, pos + 8); + } + } + } + + public readonly unsafe void ToBytes(byte* dest) + { + float norm = LengthSquared(); + if (norm > 1e-6f || norm < 0.9999f) + { + if (W < 0f) + norm = -1f / MathF.Sqrt(norm); + else + norm = 1f / MathF.Sqrt(norm); + if (Utils.CanDirectCopyLE) + { + *(float*)(dest) = norm * X; + *(float*)(dest + 4) = norm * Y; + *(float*)(dest + 8) = norm * Z; + } + else + { + Utils.FloatToBytes(norm * X, dest); + Utils.FloatToBytes(norm * Y, dest + 4); + Utils.FloatToBytes(norm * Z, dest + 8); + } + } + else + { + if (Utils.CanDirectCopyLE) + { + *(long*)dest = 0; + *(int*)(dest + 8) = 0; + } + else + { + Utils.FloatToBytes(0, dest); + Utils.FloatToBytes(0, dest + 4); + Utils.FloatToBytes(0, dest + 8); + } + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly unsafe void ToShortsBytes(byte[] dest, int pos) + { + ushort sx = Utils.FloatToUnitUInt16(X); + ushort sy = Utils.FloatToUnitUInt16(Y); + ushort sz = Utils.FloatToUnitUInt16(Z); + ushort sw = Utils.FloatToUnitUInt16(W); + + if (Utils.CanDirectCopyLE) + { + fixed (byte* d = &dest[0]) + { + *(ushort*)(d + pos) = sx; + *(ushort*)(d + pos + 2) = sy; + *(ushort*)(d + pos + 4) = sz; + *(ushort*)(d + pos + 6) = sw; + } + } + else + { + Utils.UInt16ToBytes(sx, dest, pos); + Utils.UInt16ToBytes(sy, dest, pos + 2); + Utils.UInt16ToBytes(sz, dest, pos + 4); + Utils.UInt16ToBytes(sw, dest, pos + 6); + } + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly unsafe void ToShortsBytes(byte* dest, int pos) + { + ushort sx = Utils.FloatToUnitUInt16(X); + ushort sy = Utils.FloatToUnitUInt16(Y); + ushort sz = Utils.FloatToUnitUInt16(Z); + ushort sw = Utils.FloatToUnitUInt16(W); + + if (Utils.CanDirectCopyLE) + { + *(ushort*)(dest + pos) = sx; + *(ushort*)(dest + pos + 2) = sy; + *(ushort*)(dest + pos + 4) = sz; + *(ushort*)(dest + pos + 6) = sw; + } + else + { + Utils.UInt16ToBytes(sx, dest, pos); + Utils.UInt16ToBytes(sy, dest, pos + 2); + Utils.UInt16ToBytes(sz, dest, pos + 4); + Utils.UInt16ToBytes(sw, dest, pos + 6); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly unsafe void ToShortsBytes(byte* dest) + { + ushort sx = Utils.FloatToUnitUInt16(X); + ushort sy = Utils.FloatToUnitUInt16(Y); + ushort sz = Utils.FloatToUnitUInt16(Z); + ushort sw = Utils.FloatToUnitUInt16(W); + + if (Utils.CanDirectCopyLE) + { + *(ushort*)(dest) = sx; + *(ushort*)(dest + 2) = sy; + *(ushort*)(dest + 4) = sz; + *(ushort*)(dest + 6) = sw; + } + else + { + Utils.UInt16ToBytes(sx, dest); + Utils.UInt16ToBytes(sy, dest + 2); + Utils.UInt16ToBytes(sz, dest + 4); + Utils.UInt16ToBytes(sw, dest + 6); } } @@ -331,8 +587,10 @@ public void ToBytes(byte[] dest, int pos) /// X euler angle /// Y euler angle /// Z euler angle - public void GetEulerAngles(out float roll, out float pitch, out float yaw) + public readonly void GetEulerAngles(out float roll, out float pitch, out float yaw) { + const float halfpi = MathF.PI / 2f; + roll = 0f; pitch = 0f; yaw = 0f; @@ -345,7 +603,7 @@ public void GetEulerAngles(out float roll, out float pitch, out float yaw) float tZ = Z * Z; float tW = W * W; float m = tX + tY + tZ + tW; - if (Math.Abs(m) < 0.0001f) + if (MathF.Abs(m) < 0.0001f) return; float n = 2 * (Y * W + X * Z); @@ -353,21 +611,21 @@ public void GetEulerAngles(out float roll, out float pitch, out float yaw) if (p > 0f) { - roll = (float)Math.Atan2(2.0f * (X * W - Y * Z), (-tX - tY + tZ + tW)); - pitch = (float)Math.Atan2(n, Math.Sqrt(p)); - yaw = (float)Math.Atan2(2.0f * (Z * W - X * Y), tX - tY - tZ + tW); + roll = MathF.Atan2(2.0f * (X * W - Y * Z), (-tX - tY + tZ + tW)); + pitch = MathF.Atan2(n, MathF.Sqrt(p)); + yaw = MathF.Atan2(2.0f * (Z * W - X * Y), tX - tY - tZ + tW); } else if (n > 0f) { roll = 0f; - pitch = (float)(Math.PI / 2d); + pitch = halfpi; yaw = (float)Math.Atan2((Z * W + X * Y), 0.5f - tX - tY); } else { roll = 0f; - pitch = -(float)(Math.PI / 2d); - yaw = (float)Math.Atan2((Z * W + X * Y), 0.5f - tX - tZ); + pitch = -halfpi; + yaw = MathF.Atan2((Z * W + X * Y), 0.5f - tX - tZ); } } @@ -376,9 +634,9 @@ public void GetEulerAngles(out float roll, out float pitch, out float yaw) /// /// Unit vector describing the axis /// Angle around the axis, in radians - public void GetAxisAngle(out Vector3 axis, out float angle) + public readonly void GetAxisAngle(out Vector3 axis, out float angle) { - Normalize(); + //Normalize(); float ww = W * W; if (ww > 0.9999f) { @@ -392,19 +650,19 @@ public void GetAxisAngle(out Vector3 axis, out float angle) axis = new Vector3(-X, -Y, -Z); else axis = new Vector3(X, Y, Z); - angle = (float)Math.PI; + angle = MathF.PI; return; } - float sin = (float)Math.Sqrt(1.0f - ww); + float sin = MathF.Sqrt(1.0f - ww); float invSin = 1.0f / sin; if (W < 0) invSin = -invSin; axis = new Vector3(X, Y, Z) * invSin; - angle = 2.0f * (float)Math.Acos(W); - if (angle > Math.PI) - angle = 2.0f * (float)Math.PI - angle; + angle = 2.0f * MathF.Acos(W); + if (angle > MathF.PI) + angle = 2.0f * MathF.PI - angle; } #endregion Public Methods @@ -412,8 +670,16 @@ public void GetAxisAngle(out Vector3 axis, out float angle) #region Static Methods [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Quaternion Add(Quaternion quaternion1, Quaternion quaternion2) + public static Quaternion Add(in Quaternion quaternion1, in Quaternion quaternion2) { + if (Sse.IsSupported) + { + Vector128 a = Unsafe.As>(ref Unsafe.AsRef(quaternion1)); + Vector128 b = Unsafe.As>(ref Unsafe.AsRef(quaternion2)); + a = Sse.Add(a, b); + return new Quaternion(a); + } + return new Quaternion( quaternion1.X + quaternion2.X, quaternion1.Y + quaternion2.Y, @@ -425,9 +691,16 @@ public static Quaternion Add(Quaternion quaternion1, Quaternion quaternion2) /// Returns the conjugate (spatial inverse) of a quaternion /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Quaternion Conjugate(Quaternion quaternion) + public static Quaternion Conjugate(in Quaternion quaternion) { - return new Quaternion( -quaternion.X, -quaternion.Y, -quaternion.Z, quaternion.W); + if (Sse.IsSupported) + { + Vector128 d = Unsafe.As>(ref Unsafe.AsRef(quaternion)); + Vector128 Mask = Vector128.Create(0x80000000, 0x80000000, 0x80000000, 0).AsSingle(); + d = Sse.Xor(d, Mask); + return new Quaternion(d); + } + return new Quaternion(-quaternion.X, -quaternion.Y, -quaternion.Z, quaternion.W); } /// @@ -437,7 +710,7 @@ public static Quaternion Conjugate(Quaternion quaternion) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quaternion CreateFromAxisAngle(float axisX, float axisY, float axisZ, float angle) { - Vector3 axis = new Vector3(axisX, axisY, axisZ); + Vector3 axis = new(axisX, axisY, axisZ); return CreateFromAxisAngle(axis, angle); } @@ -453,8 +726,8 @@ public static Quaternion CreateFromAxisAngle(Vector3 axis, float angle) axis.Normalize(); angle *= 0.5f; - float c = (float)Math.Cos(angle); - float s = (float)Math.Sin(angle); + float c = MathF.Cos(angle); + float s = MathF.Sin(angle); return new Quaternion(axis.X * s, axis.Y * s, axis.Z * s, c); } @@ -463,8 +736,8 @@ public static Quaternion CreateFromAxisAngle(Vector3 axis, float angle) public static Quaternion CreateRotationX(float angle) { angle *= 0.5f; - float c = (float)Math.Cos(angle); - float s = (float)Math.Sin(angle); + float c = MathF.Cos(angle); + float s = MathF.Sin(angle); return new Quaternion(s, 0, 0, c); } @@ -473,8 +746,8 @@ public static Quaternion CreateRotationX(float angle) public static Quaternion CreateRotationY(float angle) { angle *= 0.5f; - float c = (float)Math.Cos(angle); - float s = (float)Math.Sin(angle); + float c = MathF.Cos(angle); + float s = MathF.Sin(angle); return new Quaternion(0, s, 0, c); } @@ -483,8 +756,8 @@ public static Quaternion CreateRotationY(float angle) public static Quaternion CreateRotationZ(float angle) { angle *= 0.5f; - float c = (float)Math.Cos(angle); - float s = (float)Math.Sin(angle); + float c = MathF.Cos(angle); + float s = MathF.Sin(angle); return new Quaternion(0, 0, s, c); } @@ -516,22 +789,22 @@ public static Quaternion CreateFromEulers(float roll, float pitch, float yaw) throw new ArgumentException("Euler angles must be in radians"); roll *= 0.5f; - double atCos = Math.Cos(roll); - double atSin = Math.Sin(roll); + float atCos = MathF.Cos(roll); + float atSin = MathF.Sin(roll); pitch *= 0.5f; - double leftCos = Math.Cos(pitch); - double leftSin = Math.Sin(pitch); + float leftCos = MathF.Cos(pitch); + float leftSin = MathF.Sin(pitch); yaw *= 0.5f; - double upCos = Math.Cos(yaw); - double upSin = Math.Sin(yaw); + float upCos = MathF.Cos(yaw); + float upSin = MathF.Sin(yaw); - double atLeftCos = atCos * leftCos; - double atLeftSin = atSin * leftSin; + float atLeftCos = atCos * leftCos; + float atLeftSin = atSin * leftSin; return new Quaternion( - (float)(atSin * leftCos * upCos + atCos * leftSin * upSin), - (float)(atCos * leftSin * upCos - atSin * leftCos * upSin), - (float)(atLeftCos * upSin + atLeftSin * upCos), - (float)(atLeftCos * upCos - atLeftSin * upSin) + atSin * leftCos * upCos + atCos * leftSin * upSin, + atCos * leftSin * upCos - atSin * leftCos * upSin, + atLeftCos * upSin + atLeftSin * upCos, + atLeftCos * upCos - atLeftSin * upSin ); } @@ -541,7 +814,7 @@ public static Quaternion CreateFromRotationMatrix(Matrix3x3 matrix) float n2; if (num >= 0f) { - num = (float)Math.Sqrt((num + 1f)); + num = MathF.Sqrt((num + 1f)); n2 = 0.5f / num; return new Quaternion( (matrix.M23 - matrix.M32) * n2, @@ -551,7 +824,7 @@ public static Quaternion CreateFromRotationMatrix(Matrix3x3 matrix) } if ((matrix.M11 >= matrix.M22) && (matrix.M11 >= matrix.M33)) { - num = (float)Math.Sqrt((((1f + matrix.M11) - matrix.M22) - matrix.M33)); + num = MathF.Sqrt((((1f + matrix.M11) - matrix.M22) - matrix.M33)); n2 = 0.5f / num; return new Quaternion( 0.5f * num, @@ -561,7 +834,7 @@ public static Quaternion CreateFromRotationMatrix(Matrix3x3 matrix) } if (matrix.M22 > matrix.M33) { - num = (float)Math.Sqrt((((1f + matrix.M22) - matrix.M11) - matrix.M33)); + num = MathF.Sqrt((((1f + matrix.M22) - matrix.M11) - matrix.M33)); n2 = 0.5f / num; return new Quaternion( (matrix.M21 + matrix.M12) * n2, @@ -570,7 +843,7 @@ public static Quaternion CreateFromRotationMatrix(Matrix3x3 matrix) (matrix.M31 - matrix.M13) * n2); } - num = (float)Math.Sqrt((((1f + matrix.M33) - matrix.M11) - matrix.M22)); + num = MathF.Sqrt((((1f + matrix.M33) - matrix.M11) - matrix.M22)); n2 = 0.5f / num; return new Quaternion( (matrix.M31 + matrix.M13) * n2, @@ -585,7 +858,7 @@ public static Quaternion CreateFromRotationMatrix(Matrix4 matrix) float n2; if (num >= 0f) { - num = (float)Math.Sqrt((num + 1f)); + num = MathF.Sqrt((num + 1f)); n2 = 0.5f / num; return new Quaternion( (matrix.M23 - matrix.M32) * n2, @@ -595,7 +868,7 @@ public static Quaternion CreateFromRotationMatrix(Matrix4 matrix) } if ((matrix.M11 >= matrix.M22) && (matrix.M11 >= matrix.M33)) { - num = (float)Math.Sqrt((((1f + matrix.M11) - matrix.M22) - matrix.M33)); + num = MathF.Sqrt((((1f + matrix.M11) - matrix.M22) - matrix.M33)); n2 = 0.5f / num; return new Quaternion( 0.5f * num, @@ -605,7 +878,7 @@ public static Quaternion CreateFromRotationMatrix(Matrix4 matrix) } if (matrix.M22 > matrix.M33) { - num = (float)Math.Sqrt((((1f + matrix.M22) - matrix.M11) - matrix.M33)); + num = MathF.Sqrt((((1f + matrix.M22) - matrix.M11) - matrix.M33)); n2 = 0.5f / num; return new Quaternion( (matrix.M21 + matrix.M12) * n2, @@ -614,7 +887,7 @@ public static Quaternion CreateFromRotationMatrix(Matrix4 matrix) (matrix.M31 - matrix.M13) * n2); } - num = (float)Math.Sqrt((((1f + matrix.M33) - matrix.M11) - matrix.M22)); + num = MathF.Sqrt((((1f + matrix.M33) - matrix.M11) - matrix.M22)); n2 = 0.5f / num; return new Quaternion( (matrix.M31 + matrix.M13) * n2, @@ -632,6 +905,13 @@ public static Quaternion Divide(Quaternion q1, Quaternion q2) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Dot(Quaternion q1, Quaternion q2) { + if (Sse41.IsSupported) + { + Vector128 q = Unsafe.As>(ref q1); + Vector128 d = Unsafe.As>(ref q2); + d = Sse41.DotProduct(q, d, 0xf1); + return d.ToScalar(); + } return (q1.X * q2.X) + (q1.Y * q2.Y) + (q1.Z * q2.Z) + (q1.W * q2.W); } @@ -657,7 +937,7 @@ public static Quaternion Inverse(Quaternion quaternion) /// /// Spherical linear interpolation between two quaternions /// - public static Quaternion Slerp(Quaternion q1, Quaternion q2, float amount) + public static Quaternion Slerp(Quaternion q1, in Quaternion q2, float amount) { float angle = Dot(q1, q2); @@ -675,10 +955,10 @@ public static Quaternion Slerp(Quaternion q1, Quaternion q2, float amount) if ((1f - angle) >= 0.05f) { // slerp - float theta = (float)Math.Acos(angle); - float invsintheta = 1f / (float)Math.Sin(theta); - scale = (float)Math.Sin(theta * (1f - amount)) * invsintheta; - invscale = (float)Math.Sin(theta * amount) * invsintheta; + float theta = MathF.Acos(angle); + float invsintheta = 1f / MathF.Sin(theta); + scale = MathF.Sin(theta * (1f - amount)) * invsintheta; + invscale = MathF.Sin(theta * amount) * invsintheta; } else { @@ -689,13 +969,14 @@ public static Quaternion Slerp(Quaternion q1, Quaternion q2, float amount) } else { - q2.X = -q1.Y; - q2.Y = q1.X; - q2.Z = -q1.W; - q2.W = q1.Z; - - scale = (float)Math.Sin(Utils.PI * (0.5f - amount)); - invscale = (float)Math.Sin(Utils.PI * amount); + scale = MathF.Sin(Utils.PI * (0.5f - amount)); + invscale = MathF.Sin(Utils.PI * amount); + return new Quaternion( + q1.X * scale - q1.Y * invscale, + q1.Y * scale + q1.X * invscale, + q1.Z * scale - q1.W * invscale, + q1.W * scale + q1.Z * invscale + ); } return new Quaternion( @@ -753,7 +1034,7 @@ public static Quaternion Normalize(Quaternion q) float mag = q.LengthSquared(); if (mag > 1e-6f) { - float oomag = 1f / (float)Math.Sqrt(mag); + float oomag = 1f / MathF.Sqrt(mag); return new Quaternion( q.X * oomag, q.Y * oomag, @@ -763,50 +1044,202 @@ public static Quaternion Normalize(Quaternion q) return Quaternion.Identity; } - public static Quaternion Parse(string val) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + + public unsafe static Quaternion Parse(string val) + { + return Parse(val.AsSpan()); + } + + public static Quaternion Parse(ReadOnlySpan sp) { - char[] splitChar = { ',' }; - string[] split = val.Replace("<", String.Empty).Replace(">", String.Empty).Split(splitChar); - if (split.Length == 3) + if (sp.Length < 7) + throw new FormatException("Invalid Quaternion"); + + int start = 0; + int comma = 0; + char c; + do { - return new Quaternion( - float.Parse(split[0].Trim(), Utils.EnUsCulture), - float.Parse(split[1].Trim(), Utils.EnUsCulture), - float.Parse(split[2].Trim(), Utils.EnUsCulture)); + c = Unsafe.Add(ref MemoryMarshal.GetReference(sp), comma); + if (c == ',' || c == '<') + break; } - else + while (++comma < sp.Length); + + if (c == '<') { - return new Quaternion( - float.Parse(split[0].Trim(), Utils.EnUsCulture), - float.Parse(split[1].Trim(), Utils.EnUsCulture), - float.Parse(split[2].Trim(), Utils.EnUsCulture), - float.Parse(split[3].Trim(), Utils.EnUsCulture)); + start = ++comma; + while (++comma < sp.Length) + { + if (Unsafe.Add(ref MemoryMarshal.GetReference(sp), comma) == ',') + break; + } } + if (comma > sp.Length - 5) + throw new FormatException("Invalid Quaternion"); + + if (!float.TryParse(sp[start..comma], NumberStyles.Float, Utils.EnUsCulture, out float x)) + throw new FormatException("Invalid Quaternion"); + + start = ++comma; + while (++comma < sp.Length) + { + if (Unsafe.Add(ref MemoryMarshal.GetReference(sp), comma) == ',') + break; + } + if (comma > sp.Length - 3) + throw new FormatException("Invalid Quaternion"); + if (!float.TryParse(sp[start..comma], NumberStyles.Float, Utils.EnUsCulture, out float y)) + throw new FormatException("Invalid Quaternion"); + + start = ++comma; + while (++comma < sp.Length) + { + c = Unsafe.Add(ref MemoryMarshal.GetReference(sp), comma); + if (c == ',' || c == '>') + break; + } + if (comma >= sp.Length) + throw new FormatException("Invalid Quaternion"); + + if (!float.TryParse(sp[start..comma], NumberStyles.Float, Utils.EnUsCulture, out float z)) + throw new FormatException("Invalid Quaternion"); + + if (c == '>') + return new Quaternion(x, y, z); + + start = ++comma; + while (++comma < sp.Length) + { + c = Unsafe.Add(ref MemoryMarshal.GetReference(sp), comma); + if (c == ' ' || c == '>') + break; + } + + if (!float.TryParse(sp[start..comma], NumberStyles.Float, Utils.EnUsCulture, out float w)) + throw new FormatException("Invalid Quaternion"); + + return new Quaternion(x, y, z, w); } - public static bool TryParse(string val, out Quaternion result) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public unsafe static bool TryParse(string val, out Quaternion result) + { + return TryParse(val.AsSpan(), out result); + } + + public static bool TryParse(ReadOnlySpan sp, out Quaternion result) { - try + if (sp.Length < 7) + { + result = Identity; + return false; + } + + int start = 0; + int comma = 0; + char c; + + do + { + c = Unsafe.Add(ref MemoryMarshal.GetReference(sp), comma); + if (c == ',' || c == '<') + break; + } + while (++comma < sp.Length); + + if (c == '<') + { + start = ++comma; + while (++comma < sp.Length) + { + if (Unsafe.Add(ref MemoryMarshal.GetReference(sp), comma) == ',') + break; + } + } + if (comma > sp.Length - 5) + { + result = Identity; + return false; + } + + if (!float.TryParse(sp[start..comma], NumberStyles.Float, Utils.EnUsCulture, out float x)) + { + result = Identity; + return false; + } + + start = ++comma; + while (++comma < sp.Length) + { + if (Unsafe.Add(ref MemoryMarshal.GetReference(sp), comma) == ',') + break; + } + if (comma > sp.Length - 3) + { + result = Identity; + return false; + } + if (!float.TryParse(sp[start..comma], NumberStyles.Float, Utils.EnUsCulture, out float y)) { - result = Parse(val); + result = Identity; + return false; + } + + start = ++comma; + while (++comma < sp.Length) + { + c = Unsafe.Add(ref MemoryMarshal.GetReference(sp), comma); + if (c == '>' || c == ',') + break; + } + if (comma >= sp.Length) + { + result = Identity; + return false; + } + + if (!float.TryParse(sp[start..comma], NumberStyles.Float, Utils.EnUsCulture, out float z)) + { + result = Identity; + return false; + } + + if (c == '>') + { + result = new Quaternion(x, y, z); return true; } - catch (Exception) + + comma++; + start = comma; + while (++comma < sp.Length) + { + c = Unsafe.Add(ref MemoryMarshal.GetReference(sp), comma); + if (c == ' ' || c == '>') + break; + } + + if (!float.TryParse(sp[start..comma], NumberStyles.Float, Utils.EnUsCulture, out float w)) { - result = new Quaternion(); + result = Identity; return false; } + + result = new Quaternion(x, y, z, w); + return true; } #endregion Static Methods #region Overrides - public override bool Equals(object obj) + public readonly override bool Equals(object obj) { - if(!(obj is Quaternion)) + if(obj is not Quaternion other) return false; - Quaternion other = (Quaternion)obj; + if (X != other.X) return false; if (Y != other.Y) @@ -819,7 +1252,7 @@ public override bool Equals(object obj) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Quaternion other) + public readonly bool Equals(Quaternion other) { if (X != other.X) return false; @@ -833,7 +1266,7 @@ public bool Equals(Quaternion other) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool NotEqual(Quaternion other) + public readonly bool NotEqual(Quaternion other) { if (X != other.X) return true; @@ -847,7 +1280,7 @@ public bool NotEqual(Quaternion other) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() + public readonly override int GetHashCode() { int hash = X.GetHashCode(); hash = Utils.CombineHash(hash, Y.GetHashCode()); @@ -856,9 +1289,19 @@ public override int GetHashCode() return hash; } - public override string ToString() + public readonly override string ToString() { - return String.Format(Utils.EnUsCulture, "<{0}, {1}, {2}, {3}>", X, Y, Z, W); + StringBuilder sb = new(); + sb.Append('<'); + sb.Append(X.ToString(Utils.EnUsCulture)); + sb.Append(", "); + sb.Append(Y.ToString(Utils.EnUsCulture)); + sb.Append(", "); + sb.Append(Z.ToString(Utils.EnUsCulture)); + sb.Append(", "); + sb.Append(W.ToString(Utils.EnUsCulture)); + sb.Append('>'); + return sb.ToString(); } /// @@ -866,12 +1309,20 @@ public override string ToString() /// decimal digits and separated by spaces only /// /// Raw string representation of the quaternion - public string ToRawString() + public readonly string ToRawString() { - CultureInfo enUs = new CultureInfo("en-us"); + CultureInfo enUs = new("en-us"); enUs.NumberFormat.NumberDecimalDigits = 3; - return String.Format(enUs, "{0} {1} {2} {3}", X, Y, Z, W); + StringBuilder sb = new(); + sb.Append(X.ToString(enUs)); + sb.Append(' '); + sb.Append(Y.ToString(enUs)); + sb.Append(' '); + sb.Append(Z.ToString(enUs)); + sb.Append(' '); + sb.Append(W.ToString(enUs)); + return sb.ToString(); } #endregion Overrides @@ -954,6 +1405,6 @@ public string ToRawString() #endregion Operators /// A quaternion with a value of 0,0,0,1 - public readonly static Quaternion Identity = new Quaternion(0f, 0f, 0f, 1f); + public readonly static Quaternion Identity = new(0f, 0f, 0f, 1f); } } diff --git a/OpenMetaverse.Types/UUID.cs b/OpenMetaverse.Types/UUID.cs index cb0ba250..88813a49 100644 --- a/OpenMetaverse.Types/UUID.cs +++ b/OpenMetaverse.Types/UUID.cs @@ -29,6 +29,8 @@ using System.Collections.Generic; using System.Runtime.InteropServices; using System.Xml.Serialization; +using System.Runtime.Intrinsics.X86; +using System.Runtime.Intrinsics; namespace OpenMetaverse { @@ -41,8 +43,6 @@ namespace OpenMetaverse [Serializable()] public struct UUID : IComparable,IComparable, IEquatable, IEqualityComparer { - // still a big piece of *** because how stupid .net structs are. - // .net5 unsafe may remove the need for this union [XmlIgnore] [NonSerialized()] [FieldOffset(0)] public int a; [XmlIgnore] [NonSerialized()] [FieldOffset(4)] public short b; [XmlIgnore] [NonSerialized()] [FieldOffset(6)] public short c; @@ -71,45 +71,39 @@ public struct UUID : IComparable,IComparable, IEquatable, IEqualityC [XmlIgnore] [NonSerialized()] [FieldOffset(8)] public int intc; [XmlIgnore] [NonSerialized()] [FieldOffset(12)] public int intd; - [XmlIgnore] [NonSerialized()] [FieldOffset(0)] public ulong ulonga; + [XmlIgnore] [NonSerialized()][FieldOffset(0)] public ulong ulonga; [XmlIgnore] [NonSerialized()] [FieldOffset(8)] public ulong ulongb; [FieldOffset(0)] public Guid Guid; #region Constructors - + /* + public Guid Guid + { + get + { + return Unsafe.As(ref this); + } + set + { + Unsafe.As(ref this) = value; + } + } + */ /// /// Constructor that takes a string UUID representation /// /// A string representation of a UUID, case /// insensitive and can either be hyphenated or non-hyphenated /// UUID("11f8aa9c-b071-4242-836b-13b7abe0d489") - /* [MethodImpl(MethodImplOptions.AggressiveInlining)] - public unsafe UUID(string val) + public UUID(string sval) : this(sval.AsSpan()) { - if (!string.IsNullOrEmpty(val)) - { - try - { - if (Guid.TryParse(val, out Guid gg)) - { - this = *(UUID*)≫ - return; - } - } - catch { } - } - this = new UUID(); } - */ - public unsafe UUID(string sval) + public unsafe UUID(ReadOnlySpan sval) { this = new UUID(); - if (sval == null) - throw new FormatException("Invalid UUID"); - int len = sval.Length; if (len < 32) throw new FormatException("Invalid UUID"); @@ -132,63 +126,130 @@ public unsafe UUID(string sval) if (len < 36) throw new Exception(); - while (--len > 35) + if (val[13] != '-' || val[18] != '-' || val[23] != '-') + throw new Exception(); + + if (Sse42.IsSupported) { - if (val[len] != ' ') + Vector128 input = Unsafe.As>(ref Unsafe.AsRef(val)); + Vector128 upper = Ssse3.Shuffle(input, Vector128.Create(0, 4, 8, 12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff)); + Vector128 lower = Ssse3.Shuffle(input, Vector128.Create(2, 6, 10, 14, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff)); + + input = Unsafe.As>(ref Unsafe.AddByteOffset(ref Unsafe.AsRef(val), 18)); + Vector128 uppertmp = Ssse3.Shuffle(input, Vector128.Create(0xff, 0xff, 0xff, 0xff, 0, 4, 10, 14, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff)); + Vector128 lowerhalf = Ssse3.Shuffle(input, Vector128.Create(0xff, 0xff, 0xff, 0xff, 2, 6, 12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff)); + upper = Sse2.Or(upper, uppertmp); + lower = Sse2.Or(lower, lowerhalf); + + lower = Sse41.Insert(lower, Unsafe.As(ref Unsafe.AddByteOffset(ref Unsafe.AsRef(val), 34)), 7); + + input = Unsafe.As>(ref Unsafe.AddByteOffset(ref Unsafe.AsRef(val), 38)); + uppertmp = Ssse3.Shuffle(input, Vector128.Create(0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 4, 10, 14, 0xff, 0xff, 0xff, 0xff)); + lowerhalf = Ssse3.Shuffle(input, Vector128.Create(0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 2, 6, 12, 0xff, 0xff, 0xff, 0xff, 0xff)); + upper = Sse2.Or(upper, uppertmp); + lower = Sse2.Or(lower, lowerhalf); + + lower = Sse41.Insert(lower, Unsafe.As(ref Unsafe.AddByteOffset(ref Unsafe.AsRef(val), 54)), 11); + + input = Unsafe.As>(ref Unsafe.AddByteOffset(ref Unsafe.AsRef(val), 56)); + uppertmp = Ssse3.Shuffle(input, Vector128.Create(0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 4, 8, 12)); + lowerhalf = Ssse3.Shuffle(input, Vector128.Create(0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 2, 6, 10, 14)); + + upper = Sse2.Or(upper, uppertmp); + lower = Sse2.Or(lower, lowerhalf); + + Vector128 charTolower = Vector128.Create((byte)0x20); + Vector128 upperLetters = Sse2.Or(upper, charTolower); + Vector128 lowerLetters = Sse2.Or(lower, charTolower); + + Vector128 letterTohex = Vector128.Create((byte)('a' - '0' - 10)); + upperLetters = Sse2.Subtract(upperLetters, letterTohex); + lowerLetters = Sse2.Subtract(lowerLetters, letterTohex); + + Vector128 char9 = Vector128.Create((byte)'9'); + Vector128 above9upper = (Sse2.CompareGreaterThan(upper.AsSByte(), char9.AsSByte())).AsByte(); + Vector128 above9lower = (Sse2.CompareGreaterThan(lower.AsSByte(), char9.AsSByte())).AsByte(); + + Vector128 ten = Vector128.Create((byte)('0' + 10)); + Vector128 tmpcmpA = Sse2.Subtract(upperLetters, ten); + Vector128 tmpcmpB = Sse2.Subtract(lowerLetters, ten); + + Vector128 fifteen = Vector128.Create((byte)('0' + 15)); + Vector128 tmpcmpC = Sse2.Subtract(fifteen, upperLetters); + Vector128 tmpcmpD = Sse2.Subtract(fifteen, lowerLetters); + + tmpcmpA = Sse2.Or(tmpcmpC, tmpcmpA); + tmpcmpB = Sse2.Or(tmpcmpD, tmpcmpB); + + tmpcmpA = Sse2.And(tmpcmpA, above9upper); + tmpcmpB = Sse2.And(tmpcmpB, above9lower); + + tmpcmpA = Sse2.Or(tmpcmpB, tmpcmpA); + int cmp = Sse2.MoveMask(tmpcmpA); + if (cmp != 0) throw new Exception(); - } - if (val[13] != '-' || val[18] != '-' || val[23] != '-') - throw new Exception(); + upper = Sse41.BlendVariable(upper, upperLetters, above9upper); + lower = Sse41.BlendVariable(lower, lowerLetters, above9lower); + + Vector128 charzero = Vector128.Create((byte)'0'); + upper = Sse2.Subtract(upper, charzero); + lower = Sse2.Subtract(lower, charzero); + + tmpcmpA = Sse2.Or(lower, upper); + cmp = Sse2.MoveMask(tmpcmpA); + if (cmp != 0) + throw new Exception(); + + upper = Sse2.ShiftLeftLogical(upper.AsUInt16(), 4).AsByte(); + lower = Sse2.Or(lower, upper); + if (BitConverter.IsLittleEndian) + lower = Ssse3.Shuffle(lower, Vector128.Create((byte)0x03, 0x02, 0x01, 0x00, 0x05, 0x04, 0x07, 0x06, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F)); + Unsafe.As>(ref Unsafe.AsRef(in this)) = lower; + return; + } if (BitConverter.IsLittleEndian) { - bytea3 = (byte)Utils.HexToByte(val, 0); - bytea2 = (byte)Utils.HexToByte(val, 2); - bytea1 = (byte)Utils.HexToByte(val, 4); - bytea0 = (byte)Utils.HexToByte(val, 6); + bytea3 = Utils.HexToByte(val, 0); + bytea2 = Utils.HexToByte(val, 2); + bytea1 = Utils.HexToByte(val, 4); + bytea0 = Utils.HexToByte(val, 6); - byteb1 = (byte)Utils.HexToByte(val, 9); - byteb0 = (byte)Utils.HexToByte(val, 11); + byteb1 = Utils.HexToByte(val, 9); + byteb0 = Utils.HexToByte(val, 11); - bytec1 = (byte)Utils.HexToByte(val, 14); - bytec0 = (byte)Utils.HexToByte(val, 16); + bytec1 = Utils.HexToByte(val, 14); + bytec0 = Utils.HexToByte(val, 16); } else { - bytea0 = (byte)Utils.HexToByte(val, 0); - bytea1 = (byte)Utils.HexToByte(val, 2); - bytea2 = (byte)Utils.HexToByte(val, 4); - bytea3 = (byte)Utils.HexToByte(val, 6); + bytea0 = Utils.HexToByte(val, 0); + bytea1 = Utils.HexToByte(val, 2); + bytea2 = Utils.HexToByte(val, 4); + bytea3 = Utils.HexToByte(val, 6); - byteb0 = (byte)Utils.HexToByte(val, 9); - byteb1 = (byte)Utils.HexToByte(val, 11); + byteb0 = Utils.HexToByte(val, 9); + byteb1 = Utils.HexToByte(val, 11); - bytec0 = (byte)Utils.HexToByte(val, 14); - bytec1 = (byte)Utils.HexToByte(val, 16); + bytec0 = Utils.HexToByte(val, 14); + bytec1 = Utils.HexToByte(val, 16); } - - d = (byte)Utils.HexToByte(val, 19); - e = (byte)Utils.HexToByte(val, 21); + d = Utils.HexToByte(val, 19); + e = Utils.HexToByte(val, 21); - f = (byte)Utils.HexToByte(val, 24); - g = (byte)Utils.HexToByte(val, 26); - h = (byte)Utils.HexToByte(val, 28); - i = (byte)Utils.HexToByte(val, 30); - j = (byte)Utils.HexToByte(val, 32); - k = (byte)Utils.HexToByte(val, 34); + f = Utils.HexToByte(val, 24); + g = Utils.HexToByte(val, 26); + h = Utils.HexToByte(val, 28); + i = Utils.HexToByte(val, 30); + j = Utils.HexToByte(val, 32); + k = Utils.HexToByte(val, 34); return; } else { - while (--len > 31) - { - if (val[len] != ' ') - throw new Exception(); - } - if (BitConverter.IsLittleEndian) { bytea3 = Utils.HexToByte(val, 0); @@ -260,6 +321,15 @@ public unsafe UUID(ulong _la, ulong _lb) : this() [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe UUID(byte[] source, int pos) : this() { + if(Ssse3.IsSupported) + { + Vector128 rawval = Unsafe.As>(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(source), pos)); + if (BitConverter.IsLittleEndian) + rawval = Ssse3.Shuffle(rawval, Vector128.Create((byte)0x03, 0x02, 0x01, 0x00, 0x05, 0x04, 0x07, 0x06, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F)); + Unsafe.As>(ref this) = rawval; + return; + } + fixed (byte* ptr = &source[pos]) { if (BitConverter.IsLittleEndian) @@ -332,13 +402,12 @@ public UUID(UUID val) /// /// IComparable.CompareTo implementation /// - public int CompareTo(object val) + public readonly int CompareTo(object val) { if (val == null) return 1; UUID id = (UUID)val; - if (id.a != a) return (uint)id.a > (uint)a ? -1 : 1; if (id.b != b) @@ -365,7 +434,7 @@ public int CompareTo(object val) return 0; } - public int CompareTo(UUID id) + public readonly int CompareTo(UUID id) { if (id.a != a) return (uint)id.a > (uint)a ? -1 : 1; @@ -401,6 +470,15 @@ public int CompareTo(UUID id) [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe void FromBytes(byte[] source, int pos) { + if (Ssse3.IsSupported) + { + Vector128 rawval = Unsafe.As>(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(source), pos)); + if (BitConverter.IsLittleEndian) + rawval = Ssse3.Shuffle(rawval, Vector128.Create((byte)0x03, 0x02, 0x01, 0x00, 0x05, 0x04, 0x07, 0x06, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F)); + Unsafe.As>(ref this) = rawval; + return; + } + fixed (byte* ptr = &source[pos]) { if (BitConverter.IsLittleEndian) @@ -437,36 +515,10 @@ public unsafe void FromBytes(byte[] source, int pos) /// /// A 16 byte array containing this UUID [MethodImpl(MethodImplOptions.AggressiveInlining)] - public unsafe byte[] GetBytes() + public readonly unsafe byte[] GetBytes() { byte[] dest = new byte[16]; - fixed (byte* ptr = &dest[0]) - { - if (BitConverter.IsLittleEndian) - { - *ptr = bytea3; - *(ptr + 1) = bytea2; - *(ptr + 2) = bytea1; - *(ptr + 3) = bytea0; - *(ptr + 4) = byteb1; - *(ptr + 5) = byteb0; - *(ptr + 6) = bytec1; - *(ptr + 7) = bytec0; - *(ulong*)(ptr + 8) = ulongb; - } - else - { - *(ulong*)(ptr) = ulonga; - *(ptr + 8) = d; - *(ptr + 9) = e; - *(ptr + 10) = f; - *(ptr + 11) = g; - *(ptr + 12) = h; - *(ptr + 13) = i; - *(ptr + 14) = j; - *(ptr + 15) = k; - } - } + ToBytes(dest, 0); return dest; } @@ -477,8 +529,16 @@ public unsafe byte[] GetBytes() /// Position in the destination array to start /// writing. Must be at least 16 bytes before the end of the array [MethodImpl(MethodImplOptions.AggressiveInlining)] - public unsafe void ToBytes(byte[] dest, int pos) + public readonly unsafe void ToBytes(byte[] dest, int pos) { + if (Ssse3.IsSupported) + { + Vector128 val = Unsafe.As>(ref Unsafe.AsRef(in this)); + if (BitConverter.IsLittleEndian) + val = Ssse3.Shuffle(val, Vector128.Create((byte)0x03, 0x02, 0x01, 0x00, 0x05, 0x04, 0x07, 0x06, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F)); + Unsafe.As>(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(dest), pos)) = val; + return; + } fixed (byte* ptr = &dest[pos]) { if (BitConverter.IsLittleEndian) @@ -508,12 +568,41 @@ public unsafe void ToBytes(byte[] dest, int pos) } } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly unsafe void ToBytes(byte* ptr) + { + if (BitConverter.IsLittleEndian) + { + *ptr = bytea3; + *(ptr + 1) = bytea2; + *(ptr + 2) = bytea1; + *(ptr + 3) = bytea0; + *(ptr + 4) = byteb1; + *(ptr + 5) = byteb0; + *(ptr + 6) = bytec1; + *(ptr + 7) = bytec0; + *(ulong*)(ptr + 8) = ulongb; + } + else + { + *(ulong*)(ptr) = ulonga; + *(ptr + 8) = d; + *(ptr + 9) = e; + *(ptr + 10) = f; + *(ptr + 11) = g; + *(ptr + 12) = h; + *(ptr + 13) = i; + *(ptr + 14) = j; + *(ptr + 15) = k; + } + } + /// /// Calculate an LLCRC (cyclic redundancy check) for this UUID /// /// The CRC checksum for this UUID [MethodImpl(MethodImplOptions.AggressiveInlining)] - public uint CRC() + public readonly uint CRC() { return (uint)a + (uint)intb + (uint)intc + (uint)intd; } @@ -522,7 +611,8 @@ public uint CRC() /// Create a 64-bit integer representation from the second half of this UUID /// /// An integer created from the last eight bytes of this UUID - public ulong GetULong() + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly ulong GetULong() { if (BitConverter.IsLittleEndian) return ulongb; @@ -547,20 +637,17 @@ public ulong GetULong() /// A string representation of a UUID, case /// insensitive and can either be hyphenated or non-hyphenated /// UUID.Parse("11f8aa9c-b071-4242-836b-13b7abe0d489") - /* - public static UUID Parse(string val) - { - Guid gg = Guid.Parse(val); - return new UUID(gg); - } - */ + + [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static UUID Parse(string sval) { - UUID result = new UUID(); - if (sval == null) - throw new FormatException("Invalid UUID"); + return Parse(sval.AsSpan()); + } + public unsafe static UUID Parse(ReadOnlySpan sval) + { + UUID result = new(); int len = sval.Length; if (len < 32) throw new FormatException("Invalid UUID"); @@ -581,62 +668,131 @@ public unsafe static UUID Parse(string sval) { if (len < 36) throw new Exception(); - while (--len > 35) - { - if (val[len] != ' ') - throw new Exception(); - } if (val[13] != '-' || val[18] != '-' || val[23] != '-') throw new Exception(); + if (Sse42.IsSupported) + { + Vector128 input = Unsafe.As>(ref Unsafe.AsRef(val)); + Vector128 upper = Ssse3.Shuffle(input, Vector128.Create(0, 4, 8, 12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff)); + Vector128 lower = Ssse3.Shuffle(input, Vector128.Create(2, 6, 10, 14, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff)); + + input = Unsafe.As>(ref Unsafe.AddByteOffset(ref Unsafe.AsRef(val), 18)); + Vector128 uppertmp = Ssse3.Shuffle(input, Vector128.Create(0xff, 0xff, 0xff, 0xff, 0, 4, 10, 14, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff)); + Vector128 lowerhalf = Ssse3.Shuffle(input, Vector128.Create(0xff, 0xff, 0xff, 0xff, 2, 6, 12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff)); + upper = Sse2.Or(upper, uppertmp); + lower = Sse2.Or(lower, lowerhalf); + + lower = Sse41.Insert(lower, Unsafe.As(ref Unsafe.AddByteOffset(ref Unsafe.AsRef(val), 34)), 7); + + input = Unsafe.As>(ref Unsafe.AddByteOffset(ref Unsafe.AsRef(val), 38)); + uppertmp = Ssse3.Shuffle(input, Vector128.Create(0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 4, 10, 14, 0xff, 0xff, 0xff, 0xff)); + lowerhalf = Ssse3.Shuffle(input, Vector128.Create(0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 2, 6, 12, 0xff, 0xff, 0xff, 0xff, 0xff)); + upper = Sse2.Or(upper, uppertmp); + lower = Sse2.Or(lower, lowerhalf); + + lower = Sse41.Insert(lower, Unsafe.As(ref Unsafe.AddByteOffset(ref Unsafe.AsRef(val), 54)), 11); + + input = Unsafe.As>(ref Unsafe.AddByteOffset(ref Unsafe.AsRef(val), 56)); + uppertmp = Ssse3.Shuffle(input, Vector128.Create(0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 4, 8, 12)); + lowerhalf = Ssse3.Shuffle(input, Vector128.Create(0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 2, 6, 10, 14)); + + upper = Sse2.Or(upper, uppertmp); + lower = Sse2.Or(lower, lowerhalf); + + Vector128 charTolower = Vector128.Create((byte)0x20); + Vector128 upperLetters = Sse2.Or(upper, charTolower); + Vector128 lowerLetters = Sse2.Or(lower, charTolower); + + Vector128 letterTohex = Vector128.Create((byte)('a' - '0' - 10)); + upperLetters = Sse2.Subtract(upperLetters, letterTohex); + lowerLetters = Sse2.Subtract(lowerLetters, letterTohex); + + Vector128 char9 = Vector128.Create((byte)'9'); + Vector128 above9upper = (Sse2.CompareGreaterThan(upper.AsSByte(), char9.AsSByte())).AsByte(); + Vector128 above9lower = (Sse2.CompareGreaterThan(lower.AsSByte(), char9.AsSByte())).AsByte(); + + Vector128 ten = Vector128.Create((byte)('0' + 10)); + Vector128 tmpcmpA = Sse2.Subtract(upperLetters, ten); + Vector128 tmpcmpB = Sse2.Subtract(lowerLetters, ten); + + Vector128 fifteen = Vector128.Create((byte)('0' + 15)); + Vector128 tmpcmpC = Sse2.Subtract(fifteen, upperLetters); + Vector128 tmpcmpD = Sse2.Subtract(fifteen, lowerLetters); + + tmpcmpA = Sse2.Or(tmpcmpC, tmpcmpA); + tmpcmpB = Sse2.Or(tmpcmpD, tmpcmpB); + + tmpcmpA = Sse2.And(tmpcmpA, above9upper); + tmpcmpB = Sse2.And(tmpcmpB, above9lower); + + tmpcmpA = Sse2.Or(tmpcmpB, tmpcmpA); + int cmp = Sse2.MoveMask(tmpcmpA); + if (cmp != 0) + throw new Exception(); + + upper = Sse41.BlendVariable(upper, upperLetters, above9upper); + lower = Sse41.BlendVariable(lower, lowerLetters, above9lower); + + Vector128 charzero = Vector128.Create((byte)'0'); + upper = Sse2.Subtract(upper, charzero); + lower = Sse2.Subtract(lower, charzero); + + tmpcmpA = Sse2.Or(lower, upper); + cmp = Sse2.MoveMask(tmpcmpA); + if (cmp != 0) + throw new Exception(); + + upper = Sse2.ShiftLeftLogical(upper.AsUInt16(), 4).AsByte(); + lower = Sse2.Or(lower, upper); + if (BitConverter.IsLittleEndian) + lower = Ssse3.Shuffle(lower, Vector128.Create((byte)0x03, 0x02, 0x01, 0x00, 0x05, 0x04, 0x07, 0x06, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F)); + Unsafe.As>(ref Unsafe.AsRef(in result)) = lower; + return result; + } + if (BitConverter.IsLittleEndian) { - result.bytea3 = (byte)Utils.HexToByte(val, 0); - result.bytea2 = (byte)Utils.HexToByte(val, 2); - result.bytea1 = (byte)Utils.HexToByte(val, 4); - result.bytea0 = (byte)Utils.HexToByte(val, 6); + result.bytea3 = Utils.HexToByte(val, 0); + result.bytea2 = Utils.HexToByte(val, 2); + result.bytea1 = Utils.HexToByte(val, 4); + result.bytea0 = Utils.HexToByte(val, 6); - result.byteb1 = (byte)Utils.HexToByte(val, 9); - result.byteb0 = (byte)Utils.HexToByte(val, 11); + result.byteb1 = Utils.HexToByte(val, 9); + result.byteb0 = Utils.HexToByte(val, 11); - result.bytec1 = (byte)Utils.HexToByte(val, 14); - result.bytec0 = (byte)Utils.HexToByte(val, 16); + result.bytec1 = Utils.HexToByte(val, 14); + result.bytec0 = Utils.HexToByte(val, 16); } else { - result.bytea0 = (byte)Utils.HexToByte(val, 0); - result.bytea1 = (byte)Utils.HexToByte(val, 2); - result.bytea2 = (byte)Utils.HexToByte(val, 4); - result.bytea3 = (byte)Utils.HexToByte(val, 6); + result.bytea0 = Utils.HexToByte(val, 0); + result.bytea1 = Utils.HexToByte(val, 2); + result.bytea2 = Utils.HexToByte(val, 4); + result.bytea3 = Utils.HexToByte(val, 6); - result.byteb0 = (byte)Utils.HexToByte(val, 9); - result.byteb1 = (byte)Utils.HexToByte(val, 11); + result.byteb0 = Utils.HexToByte(val, 9); + result.byteb1 = Utils.HexToByte(val, 11); - result.bytec0 = (byte)Utils.HexToByte(val, 14); - result.bytec1 = (byte)Utils.HexToByte(val, 16); + result.bytec0 = Utils.HexToByte(val, 14); + result.bytec1 = Utils.HexToByte(val, 16); } - result.d = (byte)Utils.HexToByte(val, 19); - result.e = (byte)Utils.HexToByte(val, 21); + result.d = Utils.HexToByte(val, 19); + result.e = Utils.HexToByte(val, 21); - result.f = (byte)Utils.HexToByte(val, 24); - result.g = (byte)Utils.HexToByte(val, 26); - result.h = (byte)Utils.HexToByte(val, 28); - result.i = (byte)Utils.HexToByte(val, 30); - result.j = (byte)Utils.HexToByte(val, 32); - result.k = (byte)Utils.HexToByte(val, 34); + result.f = Utils.HexToByte(val, 24); + result.g = Utils.HexToByte(val, 26); + result.h = Utils.HexToByte(val, 28); + result.i = Utils.HexToByte(val, 30); + result.j = Utils.HexToByte(val, 32); + result.k = Utils.HexToByte(val, 34); return result; } else { - while (--len > 31) - { - if (val[len] != ' ') - throw new Exception(); - } - if (BitConverter.IsLittleEndian) { result.bytea3 = Utils.HexToByte(val, 0); @@ -692,11 +848,15 @@ public unsafe static UUID Parse(string sval) /// True if the string was successfully parse, otherwise false /// UUID.TryParse("11f8aa9c-b071-4242-836b-13b7abe0d489", result) + [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static bool TryParse(string sval, out UUID result) + { + return TryParse(sval.AsSpan(), out result); + } + + public unsafe static bool TryParse(ReadOnlySpan sval, out UUID result) { result = new UUID(); - if (sval is null) - return false; int len = sval.Length; if (len < 32) @@ -720,6 +880,7 @@ public unsafe static bool TryParse(string sval, out UUID result) { if (len < 36) return false; + while (--len > 35) { if (val[len] != ' ') @@ -729,43 +890,123 @@ public unsafe static bool TryParse(string sval, out UUID result) if (val[13] != '-' || val[18] != '-' || val[23] != '-') return false; + if (Sse42.IsSupported) + { + Vector128 input = Unsafe.As>(ref Unsafe.AsRef(val)); + Vector128 upper = Ssse3.Shuffle(input, Vector128.Create(0, 4, 8, 12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff)); + Vector128 lower = Ssse3.Shuffle(input, Vector128.Create(2, 6, 10, 14, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff)); + + input = Unsafe.As>(ref Unsafe.AddByteOffset(ref Unsafe.AsRef(val), 18)); + Vector128 uppertmp = Ssse3.Shuffle(input, Vector128.Create(0xff, 0xff, 0xff, 0xff, 0, 4, 10, 14, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff)); + Vector128 lowerhalf = Ssse3.Shuffle(input, Vector128.Create(0xff, 0xff, 0xff, 0xff, 2, 6, 12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff)); + upper = Sse2.Or(upper, uppertmp); + lower = Sse2.Or(lower, lowerhalf); + + lower = Sse41.Insert(lower, Unsafe.As(ref Unsafe.AddByteOffset(ref Unsafe.AsRef(val), 34)), 7); + + input = Unsafe.As>(ref Unsafe.AddByteOffset(ref Unsafe.AsRef(val), 38)); + uppertmp = Ssse3.Shuffle(input, Vector128.Create(0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 4, 10, 14, 0xff, 0xff, 0xff, 0xff)); + lowerhalf = Ssse3.Shuffle(input, Vector128.Create(0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 2, 6, 12, 0xff, 0xff, 0xff, 0xff, 0xff)); + upper = Sse2.Or(upper, uppertmp); + lower = Sse2.Or(lower, lowerhalf); + + lower = Sse41.Insert(lower, Unsafe.As(ref Unsafe.AddByteOffset(ref Unsafe.AsRef(val), 54)), 11); + + input = Unsafe.As>(ref Unsafe.AddByteOffset(ref Unsafe.AsRef(val), 56)); + uppertmp = Ssse3.Shuffle(input, Vector128.Create(0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 4, 8, 12)); + lowerhalf = Ssse3.Shuffle(input, Vector128.Create(0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 2, 6, 10, 14)); + + upper = Sse2.Or(upper, uppertmp); + lower = Sse2.Or(lower, lowerhalf); + + Vector128 charTolower = Vector128.Create((byte)0x20); + Vector128 upperLetters = Sse2.Or(upper, charTolower); + Vector128 lowerLetters = Sse2.Or(lower, charTolower); + + Vector128 letterTohex = Vector128.Create((byte)('a' - '0' - 10)); + upperLetters = Sse2.Subtract(upperLetters, letterTohex); + lowerLetters = Sse2.Subtract(lowerLetters, letterTohex); + + Vector128 char9 = Vector128.Create((byte)'9'); + Vector128 above9upper = (Sse2.CompareGreaterThan(upper.AsSByte(), char9.AsSByte())).AsByte(); + Vector128 above9lower = (Sse2.CompareGreaterThan(lower.AsSByte(), char9.AsSByte())).AsByte(); + + Vector128 ten = Vector128.Create((byte)('0' + 10)); + Vector128 tmpcmpA = Sse2.Subtract(upperLetters, ten); + Vector128 tmpcmpB = Sse2.Subtract(lowerLetters, ten); + + Vector128 fifteen = Vector128.Create((byte)('0' + 15)); + Vector128 tmpcmpC = Sse2.Subtract(fifteen, upperLetters); + Vector128 tmpcmpD = Sse2.Subtract(fifteen, lowerLetters); + + tmpcmpA = Sse2.Or(tmpcmpC, tmpcmpA); + tmpcmpB = Sse2.Or(tmpcmpD, tmpcmpB); + + tmpcmpA = Sse2.And(tmpcmpA, above9upper); + tmpcmpB = Sse2.And(tmpcmpB, above9lower); + + tmpcmpA = Sse2.Or(tmpcmpB, tmpcmpA); + int cmp = Sse2.MoveMask(tmpcmpA); + if (cmp != 0) + return false; + + upper = Sse41.BlendVariable(upper, upperLetters, above9upper); + lower = Sse41.BlendVariable(lower, lowerLetters, above9lower); + + Vector128 charzero = Vector128.Create((byte)'0'); + upper = Sse2.Subtract(upper, charzero); + lower = Sse2.Subtract(lower, charzero); + + tmpcmpA = Sse2.Or(lower, upper); + cmp = Sse2.MoveMask(tmpcmpA); + if (cmp != 0) + return false; + + upper = Sse2.ShiftLeftLogical(upper.AsUInt16(), 4).AsByte(); + lower = Sse2.Or(lower, upper); + if (BitConverter.IsLittleEndian) + lower = Ssse3.Shuffle(lower, Vector128.Create((byte)0x03, 0x02, 0x01, 0x00, 0x05, 0x04, 0x07, 0x06, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F)); + Unsafe.As>(ref Unsafe.AsRef(in result)) = lower; + return true; + } + if (BitConverter.IsLittleEndian) { - result.bytea3 = (byte)Utils.HexToByte(val, 0); - result.bytea2 = (byte)Utils.HexToByte(val, 2); - result.bytea1 = (byte)Utils.HexToByte(val, 4); - result.bytea0 = (byte)Utils.HexToByte(val, 6); + result.bytea3 = Utils.HexToByte(val, 0); + result.bytea2 = Utils.HexToByte(val, 2); + result.bytea1 = Utils.HexToByte(val, 4); + result.bytea0 = Utils.HexToByte(val, 6); - result.byteb1 = (byte)Utils.HexToByte(val, 9); - result.byteb0 = (byte)Utils.HexToByte(val, 11); + result.byteb1 = Utils.HexToByte(val, 9); + result.byteb0 = Utils.HexToByte(val, 11); - result.bytec1 = (byte)Utils.HexToByte(val, 14); - result.bytec0 = (byte)Utils.HexToByte(val, 16); + result.bytec1 = Utils.HexToByte(val, 14); + result.bytec0 = Utils.HexToByte(val, 16); } else { - result.bytea0 = (byte)Utils.HexToByte(val, 0); - result.bytea1 = (byte)Utils.HexToByte(val, 2); - result.bytea2 = (byte)Utils.HexToByte(val, 4); - result.bytea3 = (byte)Utils.HexToByte(val, 6); + result.bytea0 = Utils.HexToByte(val, 0); + result.bytea1 = Utils.HexToByte(val, 2); + result.bytea2 = Utils.HexToByte(val, 4); + result.bytea3 = Utils.HexToByte(val, 6); - result.byteb0 = (byte)Utils.HexToByte(val, 9); - result.byteb1 = (byte)Utils.HexToByte(val, 11); + result.byteb0 = Utils.HexToByte(val, 9); + result.byteb1 = Utils.HexToByte(val, 11); - result.bytec0 = (byte)Utils.HexToByte(val, 14); - result.bytec1 = (byte)Utils.HexToByte(val, 16); + result.bytec0 = Utils.HexToByte(val, 14); + result.bytec1 = Utils.HexToByte(val, 16); } - result.d = (byte)Utils.HexToByte(val, 19); - result.e = (byte)Utils.HexToByte(val, 21); + result.d = Utils.HexToByte(val, 19); + result.e = Utils.HexToByte(val, 21); - result.f = (byte)Utils.HexToByte(val, 24); - result.g = (byte)Utils.HexToByte(val, 26); - result.h = (byte)Utils.HexToByte(val, 28); - result.i = (byte)Utils.HexToByte(val, 30); - result.j = (byte)Utils.HexToByte(val, 32); - result.k = (byte)Utils.HexToByte(val, 34); + result.f = Utils.HexToByte(val, 24); + result.g = Utils.HexToByte(val, 26); + result.h = Utils.HexToByte(val, 28); + result.i = Utils.HexToByte(val, 30); + result.j = Utils.HexToByte(val, 32); + result.k = Utils.HexToByte(val, 34); return true; } else @@ -857,7 +1098,7 @@ public unsafe static UUID Random() /// /// An integer composed of all the UUID bytes XORed together [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() + public readonly override int GetHashCode() { int h = Utils.CombineHash(intd, intc); h = Utils.CombineHash(h, intb); @@ -865,9 +1106,9 @@ public override int GetHashCode() } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public int GetHashCode(UUID u) + public readonly int GetHashCode(UUID u) { - return u.a ^ u.intb ^ u.intc ^ u.intd; + return u.GetHashCode(); } /// @@ -876,12 +1117,11 @@ public int GetHashCode(UUID u) /// An object to compare to this UUID /// True if the object is a UUID and both UUIDs are equal [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override bool Equals(object o) + public readonly override bool Equals(object o) { - if (!(o is UUID)) + if (o is not UUID uuid) return false; - UUID uuid = (UUID)o; if (ulonga != uuid.ulonga) return false; if (ulongb != uuid.ulongb) @@ -895,7 +1135,7 @@ public override bool Equals(object o) /// UUID to compare to /// True if the UUIDs are equal, otherwise false [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(UUID uuid) + public readonly bool Equals(UUID uuid) { if (ulonga != uuid.ulonga) return false; @@ -905,7 +1145,7 @@ public bool Equals(UUID uuid) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(UUID a, UUID b) + public readonly bool Equals(UUID a, UUID b) { if (a.ulonga != b.ulonga) return false; @@ -915,7 +1155,7 @@ public bool Equals(UUID a, UUID b) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsZero() + public readonly bool IsZero() { if (ulonga != 0) return false; @@ -925,7 +1165,7 @@ public bool IsZero() } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool NotEqual(UUID uuid) + public readonly bool NotEqual(in UUID uuid) { if (ulonga != uuid.ulonga) return true; @@ -935,7 +1175,7 @@ public bool NotEqual(UUID uuid) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsNotZero() + public readonly bool IsNotZero() { if (ulonga != 0) return true; @@ -952,9 +1192,9 @@ public bool IsNotZero() /// 11f8aa9c-b071-4242-836b-13b7abe0d489 [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override string ToString() + public readonly override string ToString() { - return Utils.UUIDToDashString(ref this); + return Utils.UUIDToDashString(this); } #endregion Overrides @@ -968,7 +1208,7 @@ public override string ToString() /// Second UUID for comparison /// True if the UUIDs are byte for byte equal, otherwise false [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(UUID lhs, UUID rhs) + public static bool operator ==(in UUID lhs, in UUID rhs) { if (lhs.ulonga != rhs.ulonga) return false; @@ -984,7 +1224,7 @@ public override string ToString() /// Second UUID for comparison /// True if the UUIDs are not equal, otherwise true [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(UUID lhs, UUID rhs) + public static bool operator !=(in UUID lhs, in UUID rhs) { if (lhs.ulonga != rhs.ulonga) return true; @@ -1001,10 +1241,11 @@ public override string ToString() /// A UUID that is a XOR combination of the two input UUIDs public static UUID operator ^(UUID lhs, UUID rhs) { - UUID ret = new UUID(); - ret.ulonga = lhs.ulonga ^ rhs.ulonga; - ret.ulongb = lhs.ulongb ^ rhs.ulongb; - return ret; + return new() + { + ulonga = lhs.ulonga ^ rhs.ulonga, + ulongb = lhs.ulongb ^ rhs.ulongb + }; } /// @@ -1021,7 +1262,7 @@ public static explicit operator UUID(string val) #endregion Operators /// An UUID with a value of all zeroes - public static readonly UUID Zero = new UUID(); + public static readonly UUID Zero = new(); /// A cache of UUID.Zero as a string to optimize a common path public static readonly string ZeroString = "00000000-0000-0000-0000-000000000000"; diff --git a/OpenMetaverse.Types/Utils.cs b/OpenMetaverse.Types/Utils.cs index c7b489ca..aedf190a 100644 --- a/OpenMetaverse.Types/Utils.cs +++ b/OpenMetaverse.Types/Utils.cs @@ -34,45 +34,17 @@ namespace OpenMetaverse { public static partial class Utils { - /// - /// Operating system - /// - public enum Platform - { - /// Unknown - Unknown, - /// Microsoft Windows - Windows, - /// Microsoft Windows CE - WindowsCE, - /// Linux - Linux, - /// Apple OSX - OSX - } - - /// - /// Runtime platform - /// - public enum Runtime - { - /// .NET runtime - Windows, - /// Mono runtime: http://www.mono-project.com/ - Mono - } - - public const float E = (float)Math.E; + public const float E = MathF.E; public const float LOG10E = 0.4342945f; public const float LOG2E = 1.442695f; - public const float PI = (float)Math.PI; - public const float TWO_PI = (float)(Math.PI * 2.0d); - public const float PI_OVER_TWO = (float)(Math.PI / 2.0d); - public const float PI_OVER_FOUR = (float)(Math.PI / 4.0d); + public const float PI = MathF.PI; + public const float TWO_PI = MathF.PI * 2.0f; + public const float PI_OVER_TWO = MathF.PI / 2.0f; + public const float PI_OVER_FOUR = MathF.PI / 4.0f; /// Used for converting degrees to radians - public const float DEG_TO_RAD = (float)(Math.PI / 180.0d); + public const float DEG_TO_RAD = MathF.PI / 180.0f; /// Used for converting radians to degrees - public const float RAD_TO_DEG = (float)(180.0d / Math.PI); + public const float RAD_TO_DEG = 180.0f / MathF.PI; /// Provide a single instance of the CultureInfo class to /// help parsing in situations where the grid assumes an en-us @@ -88,15 +60,15 @@ public enum Runtime /// Provide a single instance of the MD5 class to avoid making /// duplicate copies and handle thread safety private static readonly System.Security.Cryptography.MD5 MD5Builder = - new System.Security.Cryptography.MD5CryptoServiceProvider(); + System.Security.Cryptography.MD5.Create(); /// Provide a single instance of the SHA-1 class to avoid /// making duplicate copies and handle thread safety private static readonly System.Security.Cryptography.SHA1 SHA1Builder = - new System.Security.Cryptography.SHA1CryptoServiceProvider(); + System.Security.Cryptography.SHA1.Create(); private static readonly System.Security.Cryptography.SHA256 SHA256Builder = - new System.Security.Cryptography.SHA256Managed(); + System.Security.Cryptography.SHA256.Create(); /// Provide a single instance of a random number generator /// to avoid making duplicate copies and handle thread safety @@ -114,16 +86,7 @@ public enum Runtime [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Clamp(float value, float min, float max) { - // First we check to see if we're greater than the max - if (value >= max) - return max; - - // Then we check to see if we're less than the min. - if (value < min) - return min; - - // There's no check to see if min > max. - return value; + return (value < max) ? (value > min ? value : min) : max; } /// @@ -136,16 +99,7 @@ public static float Clamp(float value, float min, float max) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Clamp(double value, double min, double max) { - // First we check to see if we're greater than the max - if (value >= max) - return max; - - // Then we check to see if we're less than the min. - if (value < min) - return min; - - // There's no check to see if min > max. - return value; + return (value < max) ? (value > min ? value : min) : max; } /// @@ -158,16 +112,7 @@ public static double Clamp(double value, double min, double max) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Clamp(int value, int min, int max) { - // First we check to see if we're greater than the max - if (value >= max) - return max; - - // Then we check to see if we're less than the min. - if (value < min) - return min; - - // There's no check to see if min > max. - return value; + return (value < max) ? (value > min ? value : min) : max; } /// @@ -213,40 +158,38 @@ public static float Distance(float value1, float value2) public static float Hermite(float value1, float tangent1, float value2, float tangent2, float amount) { + if (amount <= 0f) + return value1; + if (amount >= 1f) + return value2; + // All transformed to double not to lose precission // Otherwise, for high numbers of param:amount the result is NaN instead of Infinity - double v1 = value1, v2 = value2, t1 = tangent1, t2 = tangent2, s = amount, result; - double sCubed = s * s * s; + double v1 = value1, v2 = value2, t1 = tangent1, t2 = tangent2, s = amount; double sSquared = s * s; - - if (amount == 0f) - result = value1; - else if (amount == 1f) - result = value2; - else - result = (2d * v1 - 2d * v2 + t2 + t1) * sCubed + + double sCubed = sSquared * s; + + return (float)((2d * v1 - 2d * v2 + t2 + t1) * sCubed + (3d * v2 - 3d * v1 - 2d * t1 - t2) * sSquared + - t1 * s + v1; - return (float)result; + t1 * s + v1); } public static double Hermite(double value1, double tangent1, double value2, double tangent2, double amount) { + if (amount <= 0d) + return value1; + if (amount >= 1f) + return value2; + // All transformed to double not to lose precission // Otherwise, for high numbers of param:amount the result is NaN instead of Infinity - double v1 = value1, v2 = value2, t1 = tangent1, t2 = tangent2, s = amount, result; - double sCubed = s * s * s; + double v1 = value1, v2 = value2, t1 = tangent1, t2 = tangent2, s = amount; double sSquared = s * s; + double sCubed = sSquared * s; - if (amount == 0d) - result = value1; - else if (amount == 1f) - result = value2; - else - result = (2d * v1 - 2d * v2 + t2 + t1) * sCubed + + return (2d * v1 - 2d * v2 + t2 + t1) * sCubed + (3d * v2 - 3d * v1 - 2d * t1 - t2) * sSquared + t1 * s + v1; - return result; } public static float Lerp(float value1, float value2, float amount) @@ -261,20 +204,12 @@ public static double Lerp(double value1, double value2, double amount) public static float SmoothStep(float value1, float value2, float amount) { - // It is expected that 0 < amount < 1 - // If amount < 0, return value1 - // If amount > 1, return value2 - float result = Utils.Clamp(amount, 0f, 1f); - return Utils.Hermite(value1, 0f, value2, 0f, result); + return Utils.Hermite(value1, 0f, value2, 0f, amount); } public static double SmoothStep(double value1, double value2, double amount) { - // It is expected that 0 < amount < 1 - // If amount < 0, return value1 - // If amount > 1, return value2 - double result = Utils.Clamp(amount, 0f, 1f); - return Utils.Hermite(value1, 0f, value2, 0f, result); + return Utils.Hermite(value1, 0f, value2, 0f, amount); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -414,52 +349,5 @@ public static double RandomDouble() } #endregion Math - - #region Platform - - /// - /// Get the current running platform - /// - /// Enumeration of the current platform we are running on - public static Platform GetRunningPlatform() - { - const string OSX_CHECK_FILE = "/Library/Extensions.kextcache"; - - if (Environment.OSVersion.Platform == PlatformID.WinCE) - { - return Platform.WindowsCE; - } - else - { - int plat = (int)Environment.OSVersion.Platform; - - if ((plat != 4) && (plat != 128)) - { - return Platform.Windows; - } - else - { - if (System.IO.File.Exists(OSX_CHECK_FILE)) - return Platform.OSX; - else - return Platform.Linux; - } - } - } - - /// - /// Get the current running runtime - /// - /// Enumeration of the current runtime we are running on - public static Runtime GetRunningRuntime() - { - Type t = Type.GetType("Mono.Runtime"); - if (t != null) - return Runtime.Mono; - else - return Runtime.Windows; - } - - #endregion Platform } } diff --git a/OpenMetaverse.Types/UtilsConversions.cs b/OpenMetaverse.Types/UtilsConversions.cs index 46f81f15..16068ef7 100644 --- a/OpenMetaverse.Types/UtilsConversions.cs +++ b/OpenMetaverse.Types/UtilsConversions.cs @@ -32,6 +32,9 @@ using System.Reflection; using System.IO; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics.X86; +using System.Runtime.Intrinsics; namespace OpenMetaverse { @@ -39,7 +42,19 @@ public static partial class Utils { // public static readonly bool NoAlignment = CheckNeedAlignment(); public static readonly bool CanDirectCopyLE = CheckNeedAlignment(); -// public static readonly bool CanDirectCopyBE = CheckDirectCopyBE(); + //public static readonly bool CanDirectCopyBE = CheckDirectCopyBE(); + + [StructLayout(LayoutKind.Sequential, Size = 16, Pack = 1)] + public struct Bytes16 { } + + [StructLayout(LayoutKind.Sequential, Size = 12, Pack = 1)] + public struct Bytes12 { } + + [StructLayout(LayoutKind.Sequential, Size = 8, Pack = 1)] + public struct Bytes8 { } + + [StructLayout(LayoutKind.Sequential, Size = 6, Pack = 1)] + public struct Bytes6 { } public unsafe static bool CheckNeedAlignment() { @@ -157,7 +172,7 @@ static bool CheckDirectCopyBE() string.Empty, // 54 string.Empty, // 55 "settings", // 56 - string.Empty, // 57 + "material" // 57 }; private static readonly string[] _FolderTypeNames = new string[] @@ -188,7 +203,7 @@ static bool CheckDirectCopyBE() "favorite", // 23 string.Empty, // 24 "settings", // 25 - "ensemble", // 26 + "material", // 26 "ensemble", // 27 "ensemble", // 28 "ensemble", // 29 @@ -247,7 +262,7 @@ static bool CheckDirectCopyBE() string.Empty, // 23 string.Empty, // 24 "settings", // 25 - string.Empty, // 26 + "material", // 26 }; private static readonly string[] _SaleTypeNames = new string[] @@ -322,17 +337,16 @@ static bool CheckDirectCopyBE() #endregion String Arrays - #region BytesTo [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproxEqual(float a, float b, float tolerance, float reltolerance = float.Epsilon) { - float dif = Math.Abs(a - b); + float dif = MathF.Abs(a - b); if (dif <= tolerance) return true; - a = Math.Abs(a); - b = Math.Abs(b); + a = MathF.Abs(a); + b = MathF.Abs(b); if (b > a) a = b; return dif <= a * reltolerance; @@ -341,24 +355,24 @@ public static bool ApproxEqual(float a, float b, float tolerance, float reltoler [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproxZero(float a, float tolerance) { - return Math.Abs(a) <= tolerance; + return MathF.Abs(a) <= tolerance; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproxZero(float a) { - return Math.Abs(a) <= 1e-6; + return MathF.Abs(a) <= 1e-6; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproxEqual(float a, float b) { - float dif = Math.Abs(a - b); + float dif = MathF.Abs(a - b); if (dif <= 1e-6f) return true; - a = Math.Abs(a); - b = Math.Abs(b); + a = MathF.Abs(a); + b = MathF.Abs(b); if (b > a) a = b; return dif <= a * float.Epsilon; @@ -384,13 +398,14 @@ public static unsafe short BytesToInt16(byte[] bytes) //if (bytes.Length < 2 ) return 0; if (CanDirectCopyLE) { - fixed (byte* p = bytes) - return *(short*)p; + return Unsafe.As(ref MemoryMarshal.GetArrayDataReference(bytes)); } else return (short)(bytes[0] | (bytes[1] << 8)); } + #region BytesTo + /// /// Convert the first two bytes starting at the given position in /// little endian ordering to a signed short integer @@ -405,8 +420,7 @@ public static unsafe short BytesToInt16(byte[] bytes, int pos) //if (bytes.Length < pos + 2) return 0; if (CanDirectCopyLE) { - fixed (byte* p = &bytes[pos]) - return *(short*)p; + return Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(bytes), pos)); } else return (short)(bytes[pos] | (bytes[pos + 1] << 8)); @@ -437,9 +451,8 @@ public unsafe static int BytesToInt(byte[] bytes, int pos) { if (CanDirectCopyLE) { - if (bytes.Length < pos + 4) return 0; - fixed (byte* p = &bytes[pos]) - return *(int*)p; + //if (bytes.Length < pos + 4) return 0; + return Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(bytes), pos)); } return bytes[pos] | @@ -453,7 +466,7 @@ public unsafe static int BytesToInt(byte* bytes) { if (CanDirectCopyLE) { - return *(int*)bytes; + return *(int*)bytes; } return *bytes | @@ -467,8 +480,7 @@ public unsafe static int BytesToIntSafepos(byte[] bytes, int pos) { if (CanDirectCopyLE) { - fixed (byte* p = &bytes[pos]) - return *(int*)p; + return Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(bytes), pos)); } return bytes[pos] | @@ -489,8 +501,7 @@ public unsafe static int BytesToInt(byte[] bytes) { if (CanDirectCopyLE) { - fixed (byte* p = bytes) - return *(int*)p; + return Unsafe.As(ref MemoryMarshal.GetArrayDataReference(bytes)); } else return bytes[0] | @@ -529,8 +540,7 @@ public unsafe static long BytesToInt64(byte[] bytes) { if (CanDirectCopyLE) { - fixed (byte* p = bytes) - return *(long*)p; + return Unsafe.As(ref MemoryMarshal.GetArrayDataReference(bytes)); } else return @@ -591,8 +601,7 @@ public unsafe static long BytesToInt64(byte[] bytes, int pos) if (CanDirectCopyLE) { if (bytes.Length < pos + 8) return 0; - fixed (byte* p = &bytes[pos]) - return *(long*)p; + return Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(bytes), pos)); } else return @@ -611,8 +620,7 @@ public unsafe static long BytesToInt64Safepos(byte[] bytes, int pos) { if (CanDirectCopyLE) { - fixed (byte* p = &bytes[pos]) - return *(long*)p; + return Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(bytes), pos)); } else return @@ -640,8 +648,7 @@ public static unsafe ushort BytesToUInt16(byte[] bytes, int pos) //if (bytes.Length < pos + 2) return 0; if (CanDirectCopyLE) { - fixed (byte* p = &bytes[pos]) - return *(ushort*)p; + return Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(bytes), pos)); } else return (ushort)(bytes[pos] + (bytes[pos + 1] << 8)); @@ -669,8 +676,7 @@ public static unsafe ushort BytesToUInt16(byte[] bytes) //if (bytes.Length < 2) return 0; if (CanDirectCopyLE) { - fixed (byte* p = bytes) - return *(ushort*)p; + return Unsafe.As(ref MemoryMarshal.GetArrayDataReference(bytes)); } else return (ushort)(bytes[0] + (bytes[1] << 8)); @@ -690,8 +696,7 @@ public unsafe static uint BytesToUInt(byte[] bytes, int pos) if (CanDirectCopyLE) { if (bytes.Length < pos + 4) return 0; - fixed (byte* p = &bytes[pos]) - return *(uint*)p; + return Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(bytes), pos)); } else return (uint)( @@ -706,8 +711,7 @@ public unsafe static uint BytesToUIntSafepos(byte[] bytes, int pos) { if (CanDirectCopyLE) { - fixed (byte* p = &bytes[pos]) - return *(uint*)p; + return Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(bytes), pos)); } else return (uint)( @@ -729,8 +733,7 @@ public unsafe static uint BytesToUInt(byte[] bytes) { if (CanDirectCopyLE) { - fixed (byte* p = bytes) - return *(uint*)p; + return Unsafe.As(ref MemoryMarshal.GetArrayDataReference(bytes)); } else return (uint)( @@ -765,11 +768,10 @@ public unsafe static uint BytesToUInt(byte* bytes) [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static ulong BytesToUInt64(byte[] bytes, int pos) { + if (bytes.Length < pos + 8) return 0; if (CanDirectCopyLE) { - if (bytes.Length < pos + 8) return 0; - fixed (byte* p = &bytes[pos]) - return *(ulong*)p; + return Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(bytes), pos)); } else return (ulong)( @@ -788,8 +790,7 @@ public unsafe static ulong BytesToUInt64Safepos(byte[] bytes, int pos) { if (CanDirectCopyLE) { - fixed (byte* p = &bytes[pos]) - return *(ulong*)p; + return Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(bytes), pos)); } else return (ulong)( @@ -815,8 +816,7 @@ public unsafe static ulong BytesToUInt64(byte[] bytes) { if (CanDirectCopyLE) { - fixed (byte* p = bytes) - return *(ulong*)p; + return Unsafe.As(ref MemoryMarshal.GetArrayDataReference(bytes)); } else return (ulong)( @@ -861,8 +861,7 @@ public unsafe static ulong BytesToUInt64(byte* bytes) [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static float BytesToFloat(byte[] bytes) { - int tmp = BytesToInt(bytes); - return *(float*)&tmp; + return Unsafe.As(ref MemoryMarshal.GetArrayDataReference(bytes)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -875,22 +874,19 @@ public unsafe static float BytesToFloat(byte* bytes) [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static float BytesToFloat(byte[] bytes, int pos) { - int tmp = BytesToInt(bytes, pos); - return *(float*)&tmp; + return Unsafe.As(ref bytes[pos]); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static float BytesToFloatSafepos(byte[] bytes, int pos) { - int tmp = BytesToIntSafepos(bytes, pos); - return *(float*)&tmp; + return Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(bytes), pos)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static double BytesToDouble(byte[] bytes) { - long tmp = BytesToInt64(bytes); - return *(double*)&tmp; + return Unsafe.As(ref MemoryMarshal.GetArrayDataReference(bytes)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -910,26 +906,24 @@ public unsafe static double BytesToDouble(byte* bytes) [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static double BytesToDouble(byte[] bytes, int pos) { - long tmp = BytesToInt64(bytes, pos); - return *(double*)&tmp; + return Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(bytes), pos)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static double BytesToDoubleSafepos(byte[] bytes, int pos) { - long tmp = BytesToInt64Safepos(bytes, pos); - return *(double*)&tmp; + return Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(bytes), pos)); } #endregion BytesTo - #region ToBytes + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte[] Int16ToBytes(short value) { byte[] bytes = new byte[2]; - bytes[0] = (byte)(value); - bytes[1] = (byte)((value >> 8)); + bytes[0] = (byte)value; + bytes[1] = (byte)(value >> 8); return bytes; } @@ -943,52 +937,69 @@ public static void Int16ToBytes(Stream ms, short value) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Int16ToBytes(short value, byte[] dest, int pos) { - dest[pos] = (byte)(value); - dest[pos + 1] = (byte)((value >> 8)); + Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(dest), pos)) = value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void Int16ToBytes(short value, byte* dest) { - *dest = (byte)(value); - dest[1] = (byte)((value >> 8)); + *(short*)dest = value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void Int16ToBytes(short value, byte* dest, int pos) + { + + *(short*)dest[pos] = value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte[] UInt16ToBytes(ushort value) { byte[] bytes = new byte[2]; - bytes[0] = (byte)(value); - bytes[1] = (byte)((value >> 8)); + bytes[0] = (byte)value; + bytes[1] = (byte)(value >> 8); return bytes; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void UInt16ToBytes(ushort value, byte[] dest, int pos) { - dest[pos] = (byte)(value); - dest[pos + 1] = (byte)((value >> 8)); + Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(dest), pos)) = value; + + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void UInt16ToBytes(ushort value, byte* dest, int pos) + { + *(ushort*)dest[pos] = value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void UInt16ToBytes(ushort value, byte* dest) { - *dest = (byte)(value); - dest[1] = (byte)((value >> 8)); + *(ushort*)dest = value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void UInt16ToBytesBig(ushort value, byte[] dest, int pos) { - dest[pos] = (byte)((value >> 8)); - dest[pos + 1] = (byte)(value); + dest[pos] = (byte)(value >> 8); + dest[pos + 1] = (byte)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public unsafe static void UInt16ToBytesBig(ushort value, byte* dest, int pos) + { + dest[pos] = (byte)(value >> 8); + dest[pos + 1] = (byte)value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void UInt16ToBytesBig(ushort value, byte* dest) { - *dest = (byte)((value >> 8)); - dest[1] = (byte)(value); + *dest = (byte)(value >> 8); + dest[1] = (byte)value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -1011,6 +1022,7 @@ public unsafe static byte[] IntToBytes(int value) byte[] bytes = new byte[4]; if (CanDirectCopyLE) { + //Unsafe.As(ref bytes[0]) = value; fixed (byte* p = bytes) *(int*)p = value; } @@ -1027,11 +1039,25 @@ public unsafe static byte[] IntToBytes(int value) [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static void IntToBytes(int value, byte[] dest, int pos) { + if (dest.Length < pos + 4) return; if (CanDirectCopyLE) { - if (dest.Length < pos + 4) return; - fixed (byte* p = &dest[pos]) - *(int*)p = value; + Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(dest), pos)) = value; + } + else + { + dest[pos] = (byte)(value); + dest[pos + 1] = (byte)((value >> 8)); + dest[pos + 2] = (byte)((value >> 16)); + dest[pos + 3] = (byte)((value >> 24)); + } + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public unsafe static void IntToBytes(int value, byte* dest, int pos) + { + if (CanDirectCopyLE) + { + *(int*)dest[pos] = value; } else { @@ -1063,8 +1089,7 @@ public unsafe static void IntToBytesSafepos(int value, byte[] dest, int pos) { if (CanDirectCopyLE) { - fixed (byte* p = &dest[pos]) - *(int*)p = value; + Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(dest), pos)) = value; } else { @@ -1103,6 +1128,15 @@ public static void IntToBytesBig(int value, byte[] bytes, int pos) bytes[pos + 3] = (byte)value; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public unsafe static void IntToBytesBig(int value, byte* bytes, int pos) + { + bytes[pos] = (byte)(value >> 24); + bytes[pos + 1] = (byte)(value >> 16); + bytes[pos + 2] = (byte)(value >> 8); + bytes[pos + 3] = (byte)value; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void IntToBytesBig(int value, byte* bytes) { @@ -1118,12 +1152,24 @@ public unsafe static byte[] UIntToBytes(uint value) return IntToBytes((int)value); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public unsafe static void UIntToBytes(uint value, byte* dest) + { + IntToBytes((int)value, dest); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static void UIntToBytes(uint value, byte[] dest, int pos) { IntToBytes((int)value, dest, pos); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public unsafe static void UIntToBytes(uint value, byte* dest, int pos) + { + IntToBytes((int)value, dest, pos); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static void UIntToBytesSafepos(uint value, byte[] dest, int pos) { @@ -1147,8 +1193,7 @@ public unsafe static byte[] Int64ToBytes(long value) byte[] bytes = new byte[8]; if (CanDirectCopyLE) { - fixed (byte* p = bytes) - *(long*)p = value; + Unsafe.As(ref MemoryMarshal.GetArrayDataReference(bytes)) = value; } else { @@ -1169,9 +1214,29 @@ public unsafe static void Int64ToBytes(long value, byte[] dest, int pos) { if (CanDirectCopyLE) { + //Unsafe.As(ref dest[pos]) = value; if (dest.Length < pos + 8) return; - fixed (byte* p = &dest[pos]) - *(long*)p = value; + Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(dest), pos)) = value; + } + else + { + dest[pos] = (byte)value; + dest[pos + 1] = (byte)(value >> 8); + dest[pos + 2] = (byte)(value >> 16); + dest[pos + 3] = (byte)(value >> 24); + dest[pos + 4] = (byte)(value >> 32); + dest[pos + 5] = (byte)(value >> 40); + dest[pos + 6] = (byte)(value >> 48); + dest[pos + 7] = (byte)(value >> 56); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public unsafe static void Int64ToBytes(long value, byte* dest, int pos) + { + if (CanDirectCopyLE) + { + *(long*)dest[pos] = value; } else { @@ -1211,8 +1276,7 @@ public unsafe static void Int64ToBytesSafepos(long value, byte[] dest, int pos) { if (CanDirectCopyLE) { - fixed (byte* p = &dest[pos]) - *(long*)p = value; + Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(dest), pos)) = value; } else { @@ -1240,7 +1304,6 @@ public static void Int64ToBytes(Stream ms, long value) ms.WriteByte((byte)(value >> 56)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte[] Int64ToBytesBig(long value) { @@ -1269,6 +1332,19 @@ public static void Int64ToBytesBig(long value, byte[] dest, int pos) dest[pos + 7] = (byte)value; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public unsafe static void Int64ToBytesBig(long value, byte* dest, int pos) + { + dest[pos] = (byte)(value >> 56); + dest[pos + 1] = (byte)(value >> 48); + dest[pos + 2] = (byte)(value >> 40); + dest[pos + 3] = (byte)(value >> 32); + dest[pos + 4] = (byte)(value >> 24); + dest[pos + 5] = (byte)(value >> 16); + dest[pos + 6] = (byte)(value >> 8); + dest[pos + 7] = (byte)value; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void Int64ToBytesBig(long value, byte* dest) { @@ -1300,12 +1376,24 @@ public static byte[] UInt64ToBytesBig(ulong value) return Int64ToBytesBig((long)value); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public unsafe static void UInt64ToBytes(ulong value, byte* dest) + { + Int64ToBytes((long)value, dest); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static void UInt64ToBytes(ulong value, byte[] dest, int pos) { Int64ToBytes((long)value, dest, pos); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public unsafe static void UInt64ToBytes(ulong value, byte* dest, int pos) + { + Int64ToBytes((long)value, dest, pos); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static void UInt64ToBytesSafepos(ulong value, byte[] dest, int pos) { @@ -1340,6 +1428,13 @@ public unsafe static void FloatToBytes(Stream ms, float value) [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static void FloatToBytes(float value, byte[] dest, int pos) { + Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(dest), pos)) = value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public unsafe static void FloatToBytes(float value, byte* dest, int pos) + { + //Unsafe.As(ref dest[pos]) = value; IntToBytes(*(int*)&value, dest, pos); } @@ -1352,7 +1447,7 @@ public unsafe static void FloatToBytes(float value, byte* dest) [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static void FloatToBytesSafepos(float value, byte[] dest, int pos) { - IntToBytesSafepos(*(int*)&value, dest, pos); + Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(dest), pos)) = value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -1375,6 +1470,12 @@ public unsafe static byte[] DoubleToBytesBig(double value) [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static void DoubleToBytes(double value, byte[] dest, int pos) + { + Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(dest), pos)) = value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public unsafe static void DoubleToBytes(double value, byte* dest, int pos) { Int64ToBytes(*(long*)&value, dest, pos); } @@ -1388,7 +1489,7 @@ public unsafe static void DoubleToBytes(double value, byte* dest) [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static void DoubleToBytesSafepos(double value, byte[] dest, int pos) { - Int64ToBytesSafepos(*(long*)&value, dest, pos); + Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(dest), pos)) = value; } #endregion ToBytes @@ -1423,7 +1524,7 @@ public static string BytesToString(byte[] bytes) public static string BytesToString(byte[] bytes, int index, int count) { - if (bytes.Length <= index + count) + if (bytes.Length < index + count) return string.Empty; if (bytes[index + count - 1] == 0x00) return Encoding.UTF8.GetString(bytes, index, count - 1); @@ -1715,14 +1816,15 @@ public static unsafe bool osUTF8TryGetbytes(string srcstr, ref int srcstart, byt return ret; } - public static int osUTF8GetBytesCount(string str, out int maxsource) + public static int osUTF8GetBytesCount(string sstr, out int maxsource) { maxsource = 0; char c; char lastc = (char)0; int nbytes = 0; int i = 0; - while(i < str.Length) + var str = sstr.AsSpan(); + while (i < str.Length) { c = str[i++]; @@ -1766,16 +1868,17 @@ public static int osUTF8GetBytesCount(string str, out int maxsource) return nbytes; } - public static int osUTF8GetBytesCount(string str, int maxnbytes, out int maxsourcelen) + public static int osUTF8GetBytesCount(string sstr, int maxnbytes, out int maxsourcelen) { maxsourcelen = 0; int max2 = maxnbytes - 2; int max3 = maxnbytes - 3; int max4 = maxnbytes - 4; - char c = ' '; + char c; int nbytes = 0; int i = 0; + var str = sstr.AsSpan(); while(i < str.Length && nbytes < maxnbytes) { c = str[i++]; @@ -1824,6 +1927,7 @@ public static int osUTF8GetBytesCount(string str, int maxnbytes, out int maxsour /// /// Character to test /// true if hex digit, false if not + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsHexDigit(Char c) { @@ -1846,7 +1950,7 @@ public static bool IsHexDigit(Char c) return false; } - + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int HexNibbleWithChk(Char c) { const int numA = 65; @@ -1868,7 +1972,7 @@ public static int HexNibbleWithChk(Char c) return -1; } - + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int HexNibbleWithChk(byte c) { const int numA = 65; @@ -1891,6 +1995,7 @@ public static int HexNibbleWithChk(byte c) return -1; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int HexNibble(Char c) { @@ -1917,6 +2022,7 @@ public static int HexNibble(Char c) throw new FormatException("invalid hex char"); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int HexNibble(byte c) { const byte numA = (byte)'A'; @@ -1988,7 +2094,7 @@ public unsafe static byte HexToByte(byte* data, int pos) return (byte)(HexNibble(data[pos]) << 4 | HexNibble(data[pos + 1])); } - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static byte HexToByte(char* hex, int pos) { return (byte)(HexNibble(hex[pos]) << 4 | HexNibble(hex[pos + 1])); @@ -2063,6 +2169,30 @@ public static byte FloatToByte(float val, float lower, float upper) return (byte)(255 * val); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static byte FloatZeroOneToByte(float val) + { + if (val <= 0) + return 0; + if (val >= 1.0f) + return 255; + + return (byte)(255 * val); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ushort FloatZeroOneToushort(float val) + { + if (val <= 0) + return 0; + + if (val >= 1.0f) + return 0xffff; + + return (ushort)(val * 0xffff); + } + + /// /// Convert a byte to a float value given a minimum and maximum range /// @@ -2130,6 +2260,7 @@ public static ushort FloatToUInt16(float value, float lower, float upper) return (ushort)(value * 0xffff); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ushort FloatToUInt16(float value, float range) { value += range; @@ -2143,53 +2274,39 @@ public static ushort FloatToUInt16(float value, float range) return (ushort)(value * 32767.5); } - public static void FloatToUInt16Bytes(float value, float range, byte[] dest, int pos) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ushort FloatToUnitUInt16(float value) { - value += range; - if (value <= 0) - { - dest[pos] = 0; - dest[pos + 1] = 0; - return; - } + if (value <= -1.0) + return 0; - value /= range; - if (value >= 2.0f) - { - dest[pos] = 0xff; - dest[pos + 1] = 0xff; - return; - } + if (value >= 1.0f) + return 0xffff; - ushort s = (ushort)(value * 32767.5); - dest[pos] = (byte)s; - dest[pos + 1] = (byte)(s >> 8); + return (ushort)(value * 32767.5 + 32767); } - public static byte[] FloatToUInt16Bytes(float value, float range) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void FloatToUInt16Bytes(float value, float range, byte[] dest, int pos) { - byte[] dest = new byte[2]; + UInt16ToBytes(FloatToUInt16(value, range), dest, pos); + } - value += range; - if (value <= 0) - { - dest[0] = 0; - dest[1] = 0; - return dest; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public unsafe static void FloatToUInt16Bytes(float value, float range, byte* dest, int pos) + { + UInt16ToBytes(FloatToUInt16(value, range), dest, pos); + } - value /= range; - if (value >= 2.0f) - { - dest[0] = 0xff; - dest[1] = 0xff; - return dest; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public unsafe static void FloatToUInt16Bytes(float value, float range, byte* dest) + { + UInt16ToBytes(FloatToUInt16(value, range), dest); + } - ushort s = (ushort)(value * 32767.5); - dest[0] = (byte)s; - dest[1] = (byte)(s >> 8); - return dest; + public unsafe static byte[] FloatToUInt16Bytes(float value, float range) + { + return UInt16ToBytes(FloatToUInt16(value, range)); } #endregion Packed Values @@ -2393,7 +2510,7 @@ public static byte[] CopyBytes(byte[] bytes) return null; byte[] newBytes = new byte[bytes.Length]; - Buffer.BlockCopy(bytes, 0, newBytes, 0, bytes.Length); + Array.Copy(bytes, newBytes, bytes.Length); return newBytes; } @@ -2492,9 +2609,7 @@ public static uint DateTimeToUnixTime(DateTime time) /// Second value public static void Swap(ref T lhs, ref T rhs) { - T temp = lhs; - lhs = rhs; - rhs = temp; + (rhs, lhs) = (lhs, rhs); } /// @@ -2882,8 +2997,51 @@ public static byte HighNibbleToHexByteChar(byte b) return (byte)(b > 9 ? b + 0x57 : b + ASCIIzero); } - public static unsafe void UUIDToByteDashString(ref UUID u, byte* dst) + public static unsafe void UUIDToByteDashString(UUID u, byte* dst) { + if (Sse41.IsSupported) + { + Vector128 lower = Unsafe.As>(ref Unsafe.AsRef(in u)); + if (BitConverter.IsLittleEndian) + lower = Ssse3.Shuffle(lower, Vector128.Create((byte)0x03, 0x02, 0x01, 0x00, 0x05, 0x04, 0x07, 0x06, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F)); + Vector128 upper = (Sse2.ShiftRightLogical(lower.AsInt32(), 4)).AsByte(); + + Vector128 mask0f = Vector128.Create((byte)0x0f); + lower = Sse2.And(mask0f, lower); + upper = Sse2.And(mask0f, upper); + + Vector128 pastNine = Vector128.Create((sbyte)10); + Vector128 lowerMask = Sse2.CompareLessThan(lower.AsSByte(), pastNine).AsByte(); + Vector128 upperMask = Sse2.CompareLessThan(upper.AsSByte(), pastNine).AsByte(); + + Vector128 first = Vector128.Create((byte)'0'); + Vector128 second = Vector128.Create((byte)('a' - 10)); + Vector128 addlower = Sse41.BlendVariable(second, first, lowerMask); + Vector128 addupper = Sse41.BlendVariable(second, first, upperMask); + + lower = Sse2.Add(lower, addlower); + upper = Sse2.Add(upper, addupper); + + Vector128 mask1 = Ssse3.Shuffle(lower, Vector128.Create(0xff, 0, 0xff, 1, 0xff, 2, 0xff, 3, 0xff, 0xff, 4, 0xff, 5, 0xff, 0xff, 6)); + Vector128 mask2 = Ssse3.Shuffle(upper, Vector128.Create(0, 0xff, 1, 0xff, 2, 0xff, 3, 0xff, 0xff, 4, 0xff, 5, 0xff, 0xff, 6, 0xff)); + Vector128 mask3 = Ssse3.Shuffle(lower, Vector128.Create(0xff, 7, 0xff, 0xff, 8, 0xff, 9, 0xff, 0xff, 10, 0xff, 11, 0xff, 12, 0xff, 13)); + Vector128 mask4 = Ssse3.Shuffle(upper, Vector128.Create(7, 0xff, 0xff, 8, 0xff, 9, 0xff, 0xff, 10, 0xff, 11, 0xff, 12, 0xff, 13, 0xff)); + Vector128 hypens = Vector128.Create(0, 0, (byte)'-', 0, 0, 0, 0, (byte)'-', 0, 0, 0, 0, 0, 0, 0, 0); + Vector128 hypens2 = Vector128.Create(0, 0, 0, 0, 0, 0, 0, 0, (byte)'-', 0, 0, 0, 0, (byte)'-', 0, 0); + Vector128 upperSorted = Sse2.Or(Sse2.Or(mask1, mask2), hypens2); + Vector128 lowerSorted = Sse2.Or(Sse2.Or(mask3, mask4), hypens); + + Unsafe.As>(ref Unsafe.AsRef(dst)) = upperSorted; + Unsafe.As>(ref Unsafe.AddByteOffset(ref Unsafe.AsRef(dst), 16)) = lowerSorted; + + int v1 = Sse2.Extract(upper.AsUInt16(), 7); + int v2 = Sse2.Extract(lower.AsUInt16(), 7); + Unsafe.As(ref Unsafe.AddByteOffset(ref Unsafe.AsRef(dst), 32)) = (byte)(v1 & 0xff); + Unsafe.As(ref Unsafe.AddByteOffset(ref Unsafe.AsRef(dst), 33)) = (byte)(v2 & 0xff); + Unsafe.As(ref Unsafe.AddByteOffset(ref Unsafe.AsRef(dst), 34)) = (byte)((v1 >> 8) & 0xff); + Unsafe.As(ref Unsafe.AddByteOffset(ref Unsafe.AsRef(dst), 35)) = (byte)((v2 >> 8) & 0xff); + return; + } byte b; if (BitConverter.IsLittleEndian) { @@ -2992,17 +3150,7 @@ public static unsafe osUTF8 UUIDToosUTF8(UUID v) { osUTF8 ret = new osUTF8(36); fixed (byte* d = ret.m_data) - UUIDToByteDashString(ref v, d); - ret.m_len = 36; - return ret; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe osUTF8 UUIDToosUTF8(ref UUID v) - { - osUTF8 ret = new osUTF8(36); - fixed (byte* d = ret.m_data) - UUIDToByteDashString(ref v, d); + UUIDToByteDashString(v, d); ret.m_len = 36; return ret; } @@ -3028,116 +3176,169 @@ public static char charHighNibbleToHexChar(byte b) return (char)(b > 9 ? b + 0x57 : b + ASCIIzero); } - public static string UUIDToDashString(ref UUID u) + public static string UUIDToDashString(UUID u) { - char[] dst = new char[36]; - byte b; - if (BitConverter.IsLittleEndian) - { - //a - b = u.bytea3; - dst[0] = charHighNibbleToHexChar(b); - dst[1] = charLowNibbleToHexChar(b); - b = u.bytea2; - dst[2] = charHighNibbleToHexChar(b); - dst[3] = charLowNibbleToHexChar(b); - b = u.bytea1; - dst[4] = charHighNibbleToHexChar(b); - dst[5] = charLowNibbleToHexChar(b); - b = u.bytea0; - dst[6] = charHighNibbleToHexChar(b); - dst[7] = charLowNibbleToHexChar(b); - - dst[8] = '-'; - - //b - b = u.byteb1; - dst[9] = charHighNibbleToHexChar(b); - dst[10] = charLowNibbleToHexChar(b); - b = u.byteb0; - dst[11] = charHighNibbleToHexChar(b); - dst[12] = charLowNibbleToHexChar(b); - - dst[13] = '-'; - - //c - b = u.bytec1; - dst[14] = charHighNibbleToHexChar(b); - dst[15] = charLowNibbleToHexChar(b); - b = u.bytec0; - dst[16] = charHighNibbleToHexChar(b); - dst[17] = charLowNibbleToHexChar(b); - } - else + return string.Create(36, u, (dst, u) => { - //a - b = u.bytea0; - dst[0] = charHighNibbleToHexChar(b); - dst[1] = charLowNibbleToHexChar(b); - b = u.bytea1; - dst[2] = charHighNibbleToHexChar(b); - dst[3] = charLowNibbleToHexChar(b); - b = u.bytea2; - dst[4] = charHighNibbleToHexChar(b); - dst[5] = charLowNibbleToHexChar(b); - b = u.bytea3; - dst[6] = charHighNibbleToHexChar(b); - dst[7] = charLowNibbleToHexChar(b); - - dst[8] = '-'; - - //b - b = u.byteb0; - dst[9] = charHighNibbleToHexChar(b); - dst[10] = charLowNibbleToHexChar(b); - b = u.byteb1; - dst[11] = charHighNibbleToHexChar(b); - dst[12] = charLowNibbleToHexChar(b); - - dst[13] = '-'; - - //c - b = u.bytec0; - dst[14] = charHighNibbleToHexChar(b); - dst[15] = charLowNibbleToHexChar(b); - b = u.bytec1; - dst[16] = charHighNibbleToHexChar(b); - dst[17] = charLowNibbleToHexChar(b); - } - - - dst[18] = '-'; - - b = u.d; //d - dst[19] = charHighNibbleToHexChar(b); - dst[20] = charLowNibbleToHexChar(b); - b = u.e; //e - dst[21] = charHighNibbleToHexChar(b); - dst[22] = charLowNibbleToHexChar(b); - - dst[23] = '-'; + if (Sse41.IsSupported) + { + Vector128 lower = Unsafe.As>(ref Unsafe.AsRef(in u)); + if (BitConverter.IsLittleEndian) + lower = Ssse3.Shuffle(lower, Vector128.Create((byte)0x03, 0x02, 0x01, 0x00, 0x05, 0x04, 0x07, 0x06, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F)); + Vector128 upper = (Sse2.ShiftRightLogical(lower.AsInt32(), 4)).AsByte(); + + Vector128 mask0f = Vector128.Create((byte)0x0f); + lower = Sse2.And(mask0f, lower); + upper = Sse2.And(mask0f, upper); + + Vector128 pastNine = Vector128.Create((sbyte)10); + Vector128 lowerMask = Sse2.CompareLessThan(lower.AsSByte(), pastNine).AsByte(); + Vector128 upperMask = Sse2.CompareLessThan(upper.AsSByte(), pastNine).AsByte(); + + Vector128 first = Vector128.Create((byte)'0'); + Vector128 second = Vector128.Create((byte)('a' - 10)); + Vector128 addlower = Sse41.BlendVariable(second, first, lowerMask); + Vector128 addupper = Sse41.BlendVariable(second, first, upperMask); + + lower = Sse2.Add(lower, addlower); + upper = Sse2.Add(upper, addupper); + + Vector128 mask1 = Ssse3.Shuffle(lower, Vector128.Create(0xff, 0, 0xff, 1, 0xff, 2, 0xff, 3, 0xff, 0xff, 4, 0xff, 5, 0xff, 0xff, 6)); + Vector128 mask2 = Ssse3.Shuffle(upper, Vector128.Create(0, 0xff, 1, 0xff, 2, 0xff, 3, 0xff, 0xff, 4, 0xff, 5, 0xff, 0xff, 6, 0xff)); + Vector128 mask3 = Ssse3.Shuffle(lower, Vector128.Create(0xff, 7, 0xff, 0xff, 8, 0xff, 9, 0xff, 0xff, 10, 0xff, 11, 0xff, 12, 0xff, 13)); + Vector128 mask4 = Ssse3.Shuffle(upper, Vector128.Create(7, 0xff, 0xff, 8, 0xff, 9, 0xff, 0xff, 10, 0xff, 11, 0xff, 12, 0xff, 13, 0xff)); + Vector128 hypens = Vector128.Create(0, 0, (byte)'-', 0, 0, 0, 0, (byte)'-', 0, 0, 0, 0, 0, 0, 0, 0); + Vector128 hypens2 = Vector128.Create(0, 0, 0, 0, 0, 0, 0, 0, (byte)'-', 0, 0, 0, 0, (byte)'-', 0, 0); + Vector128 upperSorted = Sse2.Or(Sse2.Or(mask1, mask2), hypens2); + Vector128 lowerSorted = Sse2.Or(Sse2.Or(mask3, mask4), hypens); + + Vector128 charsMask0 = Vector128.Create(0, 0xff, 1, 0xff, 2, 0xff, 3, 0xff, 4, 0xff, 5, 0xff, 6, 0xff, 7, 0xff); + Vector128 chars0 = Ssse3.Shuffle(upperSorted, charsMask0); + Unsafe.As>(ref MemoryMarshal.GetReference(dst)) = chars0; + + Vector128 charsMask1 = Vector128.Create(8, 0xff, 9, 0xff, 10, 0xff, 11, 0xff, 12, 0xff, 13, 0xff, 14, 0xff, 15, 0xff); + Vector128 chars1 = Ssse3.Shuffle(upperSorted, charsMask1); + Unsafe.As>(ref Unsafe.AddByteOffset(ref MemoryMarshal.GetReference(dst), 16)) = chars1; + + chars0 = Ssse3.Shuffle(lowerSorted, charsMask0); + Unsafe.As>(ref Unsafe.AddByteOffset(ref MemoryMarshal.GetReference(dst), 32)) = chars0; + + chars1 = Ssse3.Shuffle(lowerSorted, charsMask1); + Unsafe.As>(ref Unsafe.AddByteOffset(ref MemoryMarshal.GetReference(dst), 48)) = chars1; + + int v1 = Sse2.Extract(upper.AsUInt16(), 7); + int v2 = Sse2.Extract(lower.AsUInt16(), 7); + Unsafe.As(ref Unsafe.AddByteOffset(ref MemoryMarshal.GetReference(dst), 64)) = (byte)(v1 & 0xff); + Unsafe.As(ref Unsafe.AddByteOffset(ref MemoryMarshal.GetReference(dst), 66)) = (byte)(v2 & 0xff); + Unsafe.As(ref Unsafe.AddByteOffset(ref MemoryMarshal.GetReference(dst), 68)) = (byte)((v1 >> 8) & 0xff); + Unsafe.As(ref Unsafe.AddByteOffset(ref MemoryMarshal.GetReference(dst), 70)) = (byte)((v2 >> 8) & 0xff); + return; + } + byte b; + if (BitConverter.IsLittleEndian) + { + //a + b = u.bytea3; + dst[0] = charHighNibbleToHexChar(b); + dst[1] = charLowNibbleToHexChar(b); + b = u.bytea2; + dst[2] = charHighNibbleToHexChar(b); + dst[3] = charLowNibbleToHexChar(b); + b = u.bytea1; + dst[4] = charHighNibbleToHexChar(b); + dst[5] = charLowNibbleToHexChar(b); + b = u.bytea0; + dst[6] = charHighNibbleToHexChar(b); + dst[7] = charLowNibbleToHexChar(b); + + dst[8] = '-'; + + //b + b = u.byteb1; + dst[9] = charHighNibbleToHexChar(b); + dst[10] = charLowNibbleToHexChar(b); + b = u.byteb0; + dst[11] = charHighNibbleToHexChar(b); + dst[12] = charLowNibbleToHexChar(b); + + dst[13] = '-'; + + //c + b = u.bytec1; + dst[14] = charHighNibbleToHexChar(b); + dst[15] = charLowNibbleToHexChar(b); + b = u.bytec0; + dst[16] = charHighNibbleToHexChar(b); + dst[17] = charLowNibbleToHexChar(b); + } + else + { + //a + b = u.bytea0; + dst[0] = charHighNibbleToHexChar(b); + dst[1] = charLowNibbleToHexChar(b); + b = u.bytea1; + dst[2] = charHighNibbleToHexChar(b); + dst[3] = charLowNibbleToHexChar(b); + b = u.bytea2; + dst[4] = charHighNibbleToHexChar(b); + dst[5] = charLowNibbleToHexChar(b); + b = u.bytea3; + dst[6] = charHighNibbleToHexChar(b); + dst[7] = charLowNibbleToHexChar(b); + + dst[8] = '-'; + + //b + b = u.byteb0; + dst[9] = charHighNibbleToHexChar(b); + dst[10] = charLowNibbleToHexChar(b); + b = u.byteb1; + dst[11] = charHighNibbleToHexChar(b); + dst[12] = charLowNibbleToHexChar(b); + + dst[13] = '-'; + + //c + b = u.bytec0; + dst[14] = charHighNibbleToHexChar(b); + dst[15] = charLowNibbleToHexChar(b); + b = u.bytec1; + dst[16] = charHighNibbleToHexChar(b); + dst[17] = charLowNibbleToHexChar(b); + } - b = u.f; //f - dst[24] = charHighNibbleToHexChar(b); - dst[25] = charLowNibbleToHexChar(b); - b = u.g; //g - dst[26] = charHighNibbleToHexChar(b); - dst[27] = charLowNibbleToHexChar(b); - b = u.h; //h - dst[28] = charHighNibbleToHexChar(b); - dst[29] = charLowNibbleToHexChar(b); - b = u.i; //i - dst[30] = charHighNibbleToHexChar(b); - dst[31] = charLowNibbleToHexChar(b); - b = u.j; //j - dst[32] = charHighNibbleToHexChar(b); - dst[33] = charLowNibbleToHexChar(b); - b = u.k; //k - dst[34] = charHighNibbleToHexChar(b); - dst[35] = charLowNibbleToHexChar(b); - return new string(dst); + dst[18] = '-'; + + b = u.d; //d + dst[19] = charHighNibbleToHexChar(b); + dst[20] = charLowNibbleToHexChar(b); + b = u.e; //e + dst[21] = charHighNibbleToHexChar(b); + dst[22] = charLowNibbleToHexChar(b); + + dst[23] = '-'; + + b = u.f; //f + dst[24] = charHighNibbleToHexChar(b); + dst[25] = charLowNibbleToHexChar(b); + b = u.g; //g + dst[26] = charHighNibbleToHexChar(b); + dst[27] = charLowNibbleToHexChar(b); + b = u.h; //h + dst[28] = charHighNibbleToHexChar(b); + dst[29] = charLowNibbleToHexChar(b); + b = u.i; //i + dst[30] = charHighNibbleToHexChar(b); + dst[31] = charLowNibbleToHexChar(b); + b = u.j; //j + dst[32] = charHighNibbleToHexChar(b); + dst[33] = charLowNibbleToHexChar(b); + b = u.k; //k + dst[34] = charHighNibbleToHexChar(b); + dst[35] = charLowNibbleToHexChar(b); + }); } - #endregion Miscellaneous } } diff --git a/OpenMetaverse.Types/Vector2.cs b/OpenMetaverse.Types/Vector2.cs index 76f6ef4e..26f52c90 100644 --- a/OpenMetaverse.Types/Vector2.cs +++ b/OpenMetaverse.Types/Vector2.cs @@ -28,6 +28,7 @@ using System.Globalization; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Text; namespace OpenMetaverse { @@ -156,6 +157,16 @@ public bool IsZero() return true; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool IsNotZero() + { + if (X != 0) + return true; + if (Y != 0) + return true; + return false; + } + /// /// Test if this vector is composed of all finite numbers /// @@ -183,7 +194,7 @@ public float Dot(Vector3 value2) /// /// Byte array containing two four-byte floats /// Beginning position in the byte array - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void FromBytes(byte[] byteArray, int pos) { X = Utils.BytesToFloatSafepos(byteArray, pos); @@ -194,7 +205,7 @@ public void FromBytes(byte[] byteArray, int pos) /// Returns the raw bytes for this vector /// /// An eight-byte array containing X and Y - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public byte[] GetBytes() { byte[] dest = new byte[8]; @@ -209,32 +220,52 @@ public byte[] GetBytes() /// Destination byte array /// Position in the destination array to start /// writing. Must be at least 8 bytes before the end of the array - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] - public void ToBytes(byte[] dest, int pos) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public unsafe void ToBytes(byte[] dest, int pos) { - Utils.FloatToBytesSafepos(X, dest, pos); - Utils.FloatToBytesSafepos(Y, dest, pos + 4); + if (Utils.CanDirectCopyLE) + { + fixed (byte* d = &dest[0]) + *(Vector2*)(d + pos) = this; + } + else + { + Utils.FloatToBytesSafepos(X, dest, pos); + Utils.FloatToBytesSafepos(Y, dest, pos + 4); + } } - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public unsafe void ToBytes(byte* dest) + { + if (Utils.CanDirectCopyLE) + *(Vector2*)(dest) = this; + else + { + Utils.FloatToBytes(X, dest); + Utils.FloatToBytes(Y, dest + 4); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] public float Length() { - return (float)Math.Sqrt(X * X + Y * Y); + return MathF.Sqrt(X * X + Y * Y); } - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public float LengthSquared() { return X * X + Y * Y; } - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Normalize() { float factor = LengthSquared(); if (factor > 1e-6) { - factor = 1f / (float)Math.Sqrt(factor); + factor = 1f / MathF.Sqrt(factor); X *= factor; Y *= factor; } @@ -249,7 +280,7 @@ public void Normalize() #region Static Methods - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Add(Vector2 value1, Vector2 value2) { return new Vector2(value1.X + value2.X, value1.Y + value2.Y); @@ -263,7 +294,7 @@ public static Vector2 Clamp(Vector3 value1, float min, float max) Utils.Clamp(value1.Y, min, max)); } - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Clamp(Vector2 value1, Vector2 min, Vector2 max) { return new Vector2( @@ -271,13 +302,13 @@ public static Vector2 Clamp(Vector2 value1, Vector2 min, Vector2 max) Utils.Clamp(value1.Y, min.Y, max.Y)); } - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Distance(Vector2 value1, Vector2 value2) { - return (float)Math.Sqrt(DistanceSquared(value1, value2)); + return MathF.Sqrt(DistanceSquared(value1, value2)); } - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float DistanceSquared(Vector2 value1, Vector2 value2) { return @@ -285,20 +316,20 @@ public static float DistanceSquared(Vector2 value1, Vector2 value2) (value1.Y - value2.Y) * (value1.Y - value2.Y); } - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Divide(Vector2 value1, Vector2 value2) { return new Vector2(value1.X / value2.X, value1.Y / value2.Y); } - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Divide(Vector2 value1, float divider) { float factor = 1 / divider; return new Vector2(value1.X * factor, value1.Y * factor); } - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Dot(Vector2 value1, Vector2 value2) { return (value1.X * value2.X) + (value1.Y * value2.Y); @@ -311,47 +342,47 @@ public static Vector2 Lerp(Vector2 value1, Vector2 value2, float amount) Utils.Lerp(value1.Y, value2.Y, amount)); } - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Max(Vector2 value1, Vector2 value2) { return new Vector2( - Math.Max(value1.X, value2.X), - Math.Max(value1.Y, value2.Y)); + MathF.Max(value1.X, value2.X), + MathF.Max(value1.Y, value2.Y)); } - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Min(Vector2 value1, Vector2 value2) { return new Vector2( - Math.Min(value1.X, value2.X), - Math.Min(value1.Y, value2.Y)); + MathF.Min(value1.X, value2.X), + MathF.Min(value1.Y, value2.Y)); } - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Multiply(Vector2 value1, Vector2 value2) { return new Vector2(value1.X * value2.X, value1.Y * value2.Y); } - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Multiply(Vector2 value1, float scaleFactor) { return new Vector2(value1.X * scaleFactor, value1.Y * scaleFactor); } - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Negate(Vector2 value) { return new Vector2(-value.X, -value.Y); } - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Normalize(Vector2 value) { float factor = value.LengthSquared(); if (factor > 1e-6) { - factor = 1f / (float)Math.Sqrt(factor); + factor = 1f / MathF.Sqrt(factor); return new Vector2(value.X * factor, value.Y * factor); } return new Vector2(); @@ -362,29 +393,117 @@ public static Vector2 Normalize(Vector2 value) /// /// A string representation of a 2D vector, enclosed /// in arrow brackets and separated by commas - public static Vector2 Parse(string val) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe Vector2 Parse(string val) { - char[] splitChar = { ',' }; - string[] split = val.Replace("<", String.Empty).Replace(">", String.Empty).Split(splitChar); - return new Vector2( - float.Parse(split[0].Trim(), Utils.EnUsCulture), - float.Parse(split[1].Trim(), Utils.EnUsCulture)); + return Parse(val.AsSpan()); + } + + public static Vector2 Parse(ReadOnlySpan sp) + { + if (sp.Length < 3) + throw new FormatException("Invalid Vector2"); + + int start = 0; + int comma = 0; + char c; + + do + { + c = Unsafe.Add(ref MemoryMarshal.GetReference(sp), comma); + if (c == ',' || c == '<') + break; + } + while (++comma < sp.Length); + + if (c == '<') + { + start = ++comma; + while (++comma < sp.Length) + { + if (Unsafe.Add(ref MemoryMarshal.GetReference(sp), comma) == ',') + break; + } + } + if (comma > sp.Length - 1) + throw new FormatException("Invalid Vector2"); + + if (!float.TryParse(sp[start..comma], NumberStyles.Float, Utils.EnUsCulture, out float x)) + throw new FormatException("Invalid Vector2"); + + start = ++comma; + while (++comma < sp.Length) + { + if (Unsafe.Add(ref MemoryMarshal.GetReference(sp), comma) == '>') + break; + } + if (!float.TryParse(sp[start..comma], NumberStyles.Float, Utils.EnUsCulture, out float y)) + throw new FormatException("Invalid Vector2"); + + return new Vector2(x, y); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryParse(string val, out Vector2 result) { - try + return TryParse(val.AsSpan(), out result); + } + public static bool TryParse(ReadOnlySpan sp, out Vector2 result) + { + if (sp.Length < 3) { - result = Parse(val); - return true; + result = Zero; + return false; } - catch (Exception) + + int start = 0; + int comma = 0; + char c; + do { - result = new Vector2(); + c = Unsafe.Add(ref MemoryMarshal.GetReference(sp), comma); + if (c == ',' || c == '<') + break; + } + while (++comma < sp.Length); + + if (c == '<') + { + start = ++comma; + while (++comma < sp.Length) + { + if (Unsafe.Add(ref MemoryMarshal.GetReference(sp), comma) == ',') + break; + } + } + if (comma > sp.Length - 1) + { + result = Zero; return false; } - } + if (!float.TryParse(sp[start..comma], NumberStyles.Float, Utils.EnUsCulture, out float x)) + { + result = Zero; + return false; + } + + start = ++comma; + while (++comma < sp.Length) + { + c = Unsafe.Add(ref MemoryMarshal.GetReference(sp), comma); + if (c == ' ' || c == '>') + break; + } + if (!float.TryParse(sp[start..comma], NumberStyles.Float, Utils.EnUsCulture, out float y)) + { + result = Zero; + return false; + } + + result = new Vector2(x, y); + return true; + } /// /// Interpolates between two vectors using a cubic equation /// @@ -395,7 +514,7 @@ public static Vector2 SmoothStep(Vector2 value1, Vector2 value2, float amount) Utils.SmoothStep(value1.Y, value2.Y, amount)); } - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Subtract(Vector2 value1, Vector2 value2) { return new Vector2(value1.X - value2.X, value1.Y - value2.Y); @@ -466,7 +585,13 @@ public override int GetHashCode() /// A string representation of the vector public override string ToString() { - return String.Format(Utils.EnUsCulture, "<{0}, {1}>", X, Y); + StringBuilder sb = new(); + sb.Append('<'); + sb.Append(X.ToString(Utils.EnUsCulture)); + sb.Append(", "); + sb.Append(Y.ToString(Utils.EnUsCulture)); + sb.Append('>'); + return sb.ToString(); } /// @@ -479,7 +604,12 @@ public string ToRawString() CultureInfo enUs = new CultureInfo("en-us"); enUs.NumberFormat.NumberDecimalDigits = 3; - return String.Format(enUs, "{0} {1}", X, Y); + StringBuilder sb = new(); + sb.Append(X.ToString(enUs)); + sb.Append(' '); + sb.Append(Y.ToString(enUs)); + sb.Append(' '); + return sb.ToString(); } #endregion Overrides diff --git a/OpenMetaverse.Types/Vector3.cs b/OpenMetaverse.Types/Vector3.cs index d9fa9d00..162ced45 100644 --- a/OpenMetaverse.Types/Vector3.cs +++ b/OpenMetaverse.Types/Vector3.cs @@ -25,9 +25,13 @@ */ using System; +using System.Globalization; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using System.Globalization; +using System.Runtime.Intrinsics.X86; +using System.Runtime.Intrinsics; +using System.Text; +using System.Collections; namespace OpenMetaverse { @@ -38,13 +42,13 @@ namespace OpenMetaverse [StructLayout(LayoutKind.Sequential)] public struct Vector3 : IComparable, IEquatable { - /// X value + /// x value public float X; /// Y value public float Y; /// Z value public float Z; - + #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -149,19 +153,30 @@ public void Sub(Vector3 v) [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Clamp(float min, float max) { - X = Utils.Clamp(X, min, max); - Y = Utils.Clamp(Y, min, max); - Z = Utils.Clamp(Z, min, max); + if (X > max) + X = max; + else if (X < min) + X = min; + + if (Y > max) + Y = max; + else if (Y < min) + Y = min; + + if (Z > max) + Z = max; + else if (Z < min) + Z = min; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public float Length() + public readonly float Length() { - return (float)Math.Sqrt(X * X + Y * Y + Z * Z); + return MathF.Sqrt(X * X + Y * Y + Z * Z); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public float LengthSquared() + public readonly float LengthSquared() { return (X * X + Y * Y + Z * Z); } @@ -172,7 +187,7 @@ public void Normalize() float factor = X * X + Y * Y + Z * Z; if (factor > 1e-6f) { - factor = 1f / (float)Math.Sqrt(factor); + factor = 1f / MathF.Sqrt(factor); X *= factor; Y *= factor; Z *= factor; @@ -186,7 +201,7 @@ public void Normalize() } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool ApproxEquals(Vector3 vec) + public readonly bool ApproxEquals(Vector3 vec) { return Utils.ApproxEqual(X, vec.X) && Utils.ApproxEqual(Y, vec.Y) && @@ -203,7 +218,7 @@ public bool ApproxEquals(Vector3 vec) /// True if the magnitude of difference between the two vectors /// is less than the given tolerance, otherwise false [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool ApproxEquals(Vector3 vec, float tolerance) + public readonly bool ApproxEquals(Vector3 vec, float tolerance) { return Utils.ApproxEqual(X, vec.X, tolerance) && Utils.ApproxEqual(Y, vec.Y, tolerance) && @@ -212,7 +227,7 @@ public bool ApproxEquals(Vector3 vec, float tolerance) [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool ApproxZero() + public readonly bool ApproxZero() { if (!Utils.ApproxZero(X)) return false; @@ -224,7 +239,7 @@ public bool ApproxZero() } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool ApproxZero(float tolerance) + public readonly bool ApproxZero(float tolerance) { if (!Utils.ApproxZero(X, tolerance)) return false; @@ -236,7 +251,7 @@ public bool ApproxZero(float tolerance) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsZero() + public readonly bool IsZero() { if (X != 0) return false; @@ -247,26 +262,41 @@ public bool IsZero() return true; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly bool IsNotZero() + { + if (X != 0) + return true; + if (Y != 0) + return true; + if (Z != 0) + return true; + return false; + } + /// /// IComparable.CompareTo implementation /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public int CompareTo(Vector3 vector) + public readonly int CompareTo(Vector3 vector) { return LengthSquared().CompareTo(vector.LengthSquared()); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public float Dot(Vector3 value2) + public readonly float Dot(Vector3 value2) { return (X * value2.X) + (Y * value2.Y) + (Z * value2.Z); } - + public readonly float AbsDot(Vector3 value2) + { + return MathF.Abs(X * value2.X) + MathF.Abs(Y * value2.Y) + MathF.Abs(Z * value2.Z); + } /// /// Test if this vector is composed of all finite numbers /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsFinite() + public readonly bool IsFinite() { return (Utils.IsFinite(X) && Utils.IsFinite(Y) && Utils.IsFinite(Z)); } @@ -276,12 +306,16 @@ public bool IsFinite() /// /// Byte array containing a 12 byte vector /// Beginning position in the byte array + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromBytes(byte[] byteArray) + { + this = Unsafe.ReadUnaligned(ref MemoryMarshal.GetArrayDataReference(byteArray)); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void FromBytes(byte[] byteArray, int pos) { - X = Utils.BytesToFloatSafepos(byteArray, pos); - Y = Utils.BytesToFloatSafepos(byteArray, pos + 4); - Z = Utils.BytesToFloatSafepos(byteArray, pos + 8); + this = Unsafe.ReadUnaligned(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(byteArray), pos)); } /// @@ -289,12 +323,10 @@ public void FromBytes(byte[] byteArray, int pos) /// /// A 12 byte array containing X, Y, and Z [MethodImpl(MethodImplOptions.AggressiveInlining)] - public byte[] GetBytes() + public readonly byte[] GetBytes() { byte[] dest = new byte[12]; - Utils.FloatToBytesSafepos(X, dest, 0); - Utils.FloatToBytesSafepos(Y, dest, 4); - Utils.FloatToBytesSafepos(Z, dest, 8); + Unsafe.WriteUnaligned(ref MemoryMarshal.GetArrayDataReference(dest), this); return dest; } @@ -305,13 +337,274 @@ public byte[] GetBytes() /// Position in the destination array to start /// writing. Must be at least 12 bytes before the end of the array [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBytes(byte[] dest, int pos) + public readonly unsafe void ToBytes(byte[] dest, int pos) { - Utils.FloatToBytesSafepos(X, dest, pos); - Utils.FloatToBytesSafepos(Y, dest, pos + 4); - Utils.FloatToBytesSafepos(Z, dest, pos + 8); + if (Utils.CanDirectCopyLE) + { + fixed (byte* d = &dest[0]) + *(Vector3*)(d + pos) = this; + } + else + { + Utils.FloatToBytesSafepos(X, dest, pos); + Utils.FloatToBytesSafepos(Y, dest, pos + 4); + Utils.FloatToBytesSafepos(Z, dest, pos + 8); + } } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly unsafe void ToBytes(byte* dest) + { + if (Utils.CanDirectCopyLE) + *(Vector3*)dest = this; + else + { + Utils.FloatToBytes(X, dest); + Utils.FloatToBytes(Y, dest + 4); + Utils.FloatToBytes(Z, dest + 8); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly unsafe void ClampedToShortsBytes(float range, byte[] dest, int pos) + { + float a, b; + + a = MathF.Abs(X); + b = MathF.Abs(Y); + if (b > a) + a = b; + b = MathF.Abs(Z); + if (b > a) + a = b; + + ushort sx, sy, sz; + if (a > range) + { + a = range / a; + sx = Utils.FloatToUInt16(X * a, range); + sy = Utils.FloatToUInt16(Y * a, range); + sz = Utils.FloatToUInt16(Z * a, range); + } + else + { + sx = Utils.FloatToUInt16(X, range); + sy = Utils.FloatToUInt16(Y, range); + sz = Utils.FloatToUInt16(Z, range); + } + + if (Utils.CanDirectCopyLE) + { + fixed (byte* d = &dest[0]) + { + *(ushort*)(d + pos) = sx; + *(ushort*)(d + pos + 2) = sy; + *(ushort*)(d + pos + 4) = sz; + } + } + else + { + Utils.UInt16ToBytes(sx, dest, pos); + Utils.UInt16ToBytes(sy, dest, pos + 2); + Utils.UInt16ToBytes(sz, dest, pos + 4); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly unsafe void ClampedToShortsBytes(float range, byte* dest, int pos) + { + float a, b; + + a = MathF.Abs(X); + b = MathF.Abs(Y); + if (b > a) + a = b; + b = MathF.Abs(Z); + if (b > a) + a = b; + + ushort sx, sy, sz; + if (a > range) + { + a = range / a; + sx = Utils.FloatToUInt16(X * a, range); + sy = Utils.FloatToUInt16(Y * a, range); + sz = Utils.FloatToUInt16(Z * a, range); + } + else + { + sx = Utils.FloatToUInt16(X, range); + sy = Utils.FloatToUInt16(Y, range); + sz = Utils.FloatToUInt16(Z, range); + } + + if (Utils.CanDirectCopyLE) + { + *(ushort*)(dest + pos) = sx; + *(ushort*)(dest + pos + 2) = sy; + *(ushort*)(dest + pos + 4) = sz; + } + else + { + Utils.UInt16ToBytes(sx, dest, pos); + Utils.UInt16ToBytes(sy, dest, pos + 2); + Utils.UInt16ToBytes(sz, dest, pos + 4); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly unsafe void ClampedToShortsBytes(float range, byte* dest) + { + float a, b; + + a = MathF.Abs(X); + b = MathF.Abs(Y); + if (b > a) + a = b; + b = MathF.Abs(Z); + if (b > a) + a = b; + + ushort sx, sy, sc; + if (a > range) + { + a = range / a; + sx = Utils.FloatToUInt16(X * a, range); + sy = Utils.FloatToUInt16(Y * a, range); + sc = Utils.FloatToUInt16(Z * a, range); + } + else + { + sx = Utils.FloatToUInt16(X, range); + sy = Utils.FloatToUInt16(Y, range); + sc = Utils.FloatToUInt16(Z, range); + } + + if (Utils.CanDirectCopyLE) + { + *(ushort*)(dest) = sx; + *(ushort*)(dest + 2) = sy; + *(ushort*)(dest + 4) = sc; + } + else + { + Utils.UInt16ToBytes(sx, dest); + Utils.UInt16ToBytes(sy, dest + 2); + Utils.UInt16ToBytes(sc, dest + 4); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Rotate(Quaternion rot) + { + float x2 = rot.X + rot.X; + float y2 = rot.Y + rot.Y; + float z2 = rot.Z + rot.Z; + + float wx2 = rot.W * x2; + float wy2 = rot.W * y2; + float wz2 = rot.W * z2; + float xx2 = rot.X * x2; + float xy2 = rot.X * y2; + float xz2 = rot.X * z2; + float yy2 = rot.Y * y2; + float yz2 = rot.Y * z2; + float zz2 = rot.Z * z2; + + x2 = X; + y2 = Y; + z2 = Z; + + X = x2 * (1.0f - yy2 - zz2) + y2 * (xy2 - wz2) + z2 * (xz2 + wy2); + Y = x2 * (xy2 + wz2) + y2 * (1.0f - xx2 - zz2) + z2 * (yz2 - wx2); + Z = x2 * (xz2 - wy2) + y2 * (yz2 + wx2) + z2 * (1.0f - xx2 - yy2); + } + + public void InverseRotate(Quaternion rot) + { + float x2 = rot.X + rot.X; + float y2 = rot.Y + rot.Y; + float z2 = rot.Z + rot.Z; + + float wx2 = rot.W * x2; + float wy2 = rot.W * y2; + float wz2 = rot.W * z2; + + float xx2 = rot.X * x2; + float xy2 = rot.X * y2; + float xz2 = rot.X * z2; + float yy2 = rot.Y * y2; + float yz2 = rot.Y * z2; + float zz2 = rot.Z * z2; + + x2 = X; + y2 = Y; + z2 = Z; + + X = x2 * (1.0f - yy2 - zz2) + y2 * (xy2 + wz2) + z2 * (xz2 - wy2); + Y = x2 * (xy2 - wz2) + y2 * (1.0f - xx2 - zz2) + z2 * (yz2 + wx2); + Z = x2 * (xz2 + wy2) + y2 * (yz2 - wx2) + z2 * (1.0f - xx2 - yy2); + } + + //quaternion must be normalized <0,0,z,w> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RotateByQZ(Quaternion rot) + { + float z2 = rot.Z + rot.Z; + float zz2 = 1.0f - rot.Z * z2; + float wz2 = rot.W * z2; + + float ox = X; + float oy = Y; + + X = ox * zz2 - oy * wz2; + Y = ox * wz2 + oy * zz2; + } + + //quaternion must be normalized <0,0,z,w> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void InverseRotateByQZ(Quaternion rot) + { + float z2 = rot.Z + rot.Z; + float zz2 = 1.0f - rot.Z * z2; + float wz2 = rot.W * z2; + + float ox = X; + float oy = Y; + + X = ox * zz2 + oy * wz2; + Y = oy * zz2 - ox * wz2; + } + + //shortQuaternion must be normalized + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RotateByShortQZ(Vector2 shortQuaternion) + { + float z2 = shortQuaternion.X + shortQuaternion.X; + float zz2 = 1.0f - shortQuaternion.X * z2; + float wz2 = shortQuaternion.Y * z2; + + float ox = X; + float oy = Y; + + X = ox * zz2 - oy * wz2; + Y = ox * wz2 + oy * zz2; + } + + //quaternion must be normalized <0,0,z,w> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void InverseRotateByShortQZ(Vector2 shortQuaternion) + { + float z2 = shortQuaternion.X + shortQuaternion.X; + float zz2 = 1.0f - shortQuaternion.X * z2; + float wz2 = shortQuaternion.Y * z2; + + float ox = X; + float oy = Y; + + X = ox * zz2 + oy * wz2; + Y = oy * zz2 - ox * wz2; + } #endregion Public Methods #region Static Methods @@ -321,6 +614,12 @@ public static Vector3 Add(Vector3 value1, Vector3 value2) return new Vector3(value1.X + value2.X, value1.Y + value2.Y, value1.Z + value2.Z); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 Abs(Vector3 value1) + { + return new Vector3(MathF.Abs(value1.X), MathF.Abs(value1.Y), MathF.Abs(value1.Z)); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Clamp(Vector3 value1, float min, float max) { @@ -348,6 +647,7 @@ public static Vector3 Cross(Vector3 value1, Vector3 value2) value1.X * value2.Y - value2.X * value1.Y); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Distance(Vector3 value1, Vector3 value2) { return (float)Math.Sqrt(DistanceSquared(value1, value2)); @@ -382,6 +682,12 @@ public static float Dot(Vector3 value1, Vector3 value2) return (value1.X * value2.X) + (value1.Y * value2.Y) + (value1.Z * value2.Z); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float AbsDot(Vector3 value1, Vector3 value2) + { + return MathF.Abs(value1.X * value2.X) + MathF.Abs(value1.Y * value2.Y) + MathF.Abs(value1.Z * value2.Z); + } + public static Vector3 Lerp(Vector3 value1, Vector3 value2, float amount) { return new Vector3( @@ -438,7 +744,7 @@ public static Vector3 Normalize(Vector3 value) float factor = value.LengthSquared(); if (factor > 1e-6f) { - factor = 1f / (float)Math.Sqrt(factor); + factor = 1f / MathF.Sqrt(factor); return value * factor; } return new Vector3(); @@ -449,28 +755,150 @@ public static Vector3 Normalize(Vector3 value) /// /// A string representation of a 3D vector, enclosed /// in arrow brackets and separated by commas - public static Vector3 Parse(string val) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe Vector3 Parse(string val) { - char[] splitChar = { ',' }; - string[] split = val.Replace("<", String.Empty).Replace(">", String.Empty).Split(splitChar); - return new Vector3( - Single.Parse(split[0].Trim(), Utils.EnUsCulture), - Single.Parse(split[1].Trim(), Utils.EnUsCulture), - Single.Parse(split[2].Trim(), Utils.EnUsCulture)); + return Parse(val.AsSpan()); } + public static Vector3 Parse(ReadOnlySpan sp) + { + if (sp.Length < 5) + throw new FormatException("Invalid Vector3"); + + int start = 0; + int comma = 0; + char c; + + do + { + c = Unsafe.Add(ref MemoryMarshal.GetReference(sp), comma); + if (c == ',' || c == '<') + break; + } + while (++comma < sp.Length); + + if (c == '<') + { + start = ++comma; + while (++comma < sp.Length) + { + if (Unsafe.Add(ref MemoryMarshal.GetReference(sp), comma) == ',') + break; + } + } + + if (comma > sp.Length - 3) + throw new FormatException("Invalid Vector3"); + + if (!float.TryParse(sp[start..comma], NumberStyles.Float, Utils.EnUsCulture, out float x)) + throw new FormatException("Invalid Vector3"); + + start = ++comma; + while (++comma < sp.Length) + { + if (Unsafe.Add(ref MemoryMarshal.GetReference(sp), comma) == ',') + break; + } + if (comma > sp.Length - 1) + throw new FormatException("Invalid Vector3"); + + if (!float.TryParse(sp[start..comma], NumberStyles.Float, Utils.EnUsCulture, out float y)) + throw new FormatException("Invalid Vector3"); + + start = ++comma; + while (++comma < sp.Length) + { + c = Unsafe.Add(ref MemoryMarshal.GetReference(sp), comma); + if (c == ' ' || c == '>') + break; + } + + if (!float.TryParse(sp[start..comma], NumberStyles.Float, Utils.EnUsCulture, out float z)) + throw new FormatException("Invalid Vector3"); + return new Vector3(x, y, z); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryParse(string val, out Vector3 result) { - try + return TryParse(val.AsSpan(), out result); + } + + public static bool TryParse(ReadOnlySpan sp, out Vector3 result) + { + if (sp.Length < 7) { - result = Parse(val); - return true; + result = Zero; + return false; + } + + int start = 0; + int comma = 0; + char c; + do + { + c = Unsafe.Add(ref MemoryMarshal.GetReference(sp), comma); + if (c == ',' || c == '<') + break; + } + while (++comma < sp.Length); + + if (c == '<') + { + start = ++comma; + while (++comma < sp.Length) + { + if (Unsafe.Add(ref MemoryMarshal.GetReference(sp), comma) == ',') + break; + } + if (start > sp.Length - 6) + { + result = Zero; + return false; + } + } + + if (!float.TryParse(sp[start..comma], NumberStyles.Float, Utils.EnUsCulture, out float x)) + { + result = Zero; + return false; + } + + start = ++comma; + while (++comma < sp.Length) + { + if (Unsafe.Add(ref MemoryMarshal.GetReference(sp), comma) == ',') + break; + } + if (comma > sp.Length - 3) + { + result = Zero; + return false; } - catch (Exception) + + if (!float.TryParse(sp[start..comma], NumberStyles.Float, Utils.EnUsCulture, out float y)) { - result = Vector3.Zero; + result = Zero; return false; } + + start = ++comma; + while (++comma < sp.Length) + { + c = Unsafe.Add(ref MemoryMarshal.GetReference(sp), comma); + if (c == ' ' || c == '>') + break; + } + + if (!float.TryParse(sp[start..comma], NumberStyles.Float, Utils.EnUsCulture, out float z)) + { + result = Zero; + return false; + } + + result = new Vector3(x, y, z); + return true; } /// @@ -480,16 +908,16 @@ public static bool TryParse(string val, out Vector3 result) /// Normalized target vector public static Quaternion RotationBetween(Vector3 a, Vector3 b) { - const double piOverfour = 0.25 * Math.PI; - double magProduct = Math.Sqrt(a.LengthSquared() * b.LengthSquared()); - double angle; + const float piOverfour = 0.25f * MathF.PI; + float magProduct = MathF.Sqrt(a.LengthSquared() * b.LengthSquared()); + float angle; if(magProduct > 1e-6) { float dotProduct = Dot(a, b); - if(dotProduct < 1e-6) + if(dotProduct < 1e-6f) angle = piOverfour; else - angle = 0.5 * Math.Acos(dotProduct / magProduct); + angle = 0.5f * MathF.Acos(dotProduct / magProduct); } else angle = piOverfour; @@ -497,7 +925,7 @@ public static Quaternion RotationBetween(Vector3 a, Vector3 b) Vector3 axis = Cross(a, b); axis.Normalize(); - float s = (float)Math.Sin(angle); + float s = MathF.Sin(angle); return new Quaternion( axis.X * s, axis.Y * s, @@ -522,7 +950,52 @@ public static Vector3 Subtract(Vector3 value1, Vector3 value2) { return new Vector3(value1.X - value2.X, value1.Y - value2.Y, value1.Z - value2.Z); } + /* + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public unsafe static Vector3 SubtractS(Vector3 value1, Vector3 value2) + { + if (Sse2.IsSupported) + { + Vector128 ma = Sse2.LoadScalarVector128((double*)&value1.X).AsSingle(); + ma = Sse2.Shuffle(ma, Sse2.LoadScalarVector128((float*)&value1.Z), 0x44); + + Vector128 mb = Sse2.LoadScalarVector128((double*)&value2.X).AsSingle(); + mb = Sse2.Shuffle(mb, Sse2.LoadScalarVector128((float*)&value2.Z), 0x44); + + ma = Sse.Subtract(ma, mb); + Vector3 ret = new(); + Sse2.StoreScalar((double*)&ret.X, ma.AsDouble()); + Sse2.StoreScalar(&ret.Z, Sse2.Shuffle(ma.AsInt32(), 0x02).AsSingle()); + return ret; + } + else + return Subtract(value1, value2); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 AddS(Vector3 value1, Vector3 value2) + { + if (Sse2.IsSupported) + { + unsafe + { + Vector128 ma = Sse2.LoadScalarVector128((double*)&value1.X).AsSingle(); + ma = Sse2.Shuffle(ma, Sse2.LoadScalarVector128(&value1.Z), 0x44); + + Vector128 mb = Sse2.LoadScalarVector128((double*)&value2.X).AsSingle(); + mb = Sse2.Shuffle(mb, Sse2.LoadScalarVector128(&value2.Z), 0x44); + + ma = Sse.Add(ma, mb); + Vector3 ret = new(); + Sse2.StoreScalar((double*)&ret.X, ma.AsDouble()); + Sse2.StoreScalar(&ret.Z, Sse2.Shuffle(ma.AsInt32(), 0x02).AsSingle()); + return ret; + } + } + else + return Subtract(value1, value2); + } + */ public static Vector3 Transform(Vector3 position, Matrix4 matrix) { return new Vector3( @@ -541,6 +1014,12 @@ public static Vector3 TransformNormal(Vector3 position, Matrix4 matrix) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Transform(Vector3 vec, Quaternion rot) + { + return Rotate(vec, rot); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 Rotate(Vector3 vec, Quaternion rot) { float x2 = rot.X + rot.X; float y2 = rot.Y + rot.Y; @@ -566,16 +1045,147 @@ public static Vector3 Transform(Vector3 vec, Quaternion rot) x2 * (xz2 - wy2) + y2 * (yz2 + wx2) + z2 * (1.0f - xx2 - yy2)); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 InverseRotate(Vector3 vec, Quaternion rot) + { + float x2 = rot.X + rot.X; + float y2 = rot.Y + rot.Y; + float z2 = rot.Z + rot.Z; + + float wx2 = rot.W * x2; + float wy2 = rot.W * y2; + float wz2 = rot.W * z2; + float xx2 = rot.X * x2; + float xy2 = rot.X * y2; + float xz2 = rot.X * z2; + float yy2 = rot.Y * y2; + float yz2 = rot.Y * z2; + float zz2 = rot.Z * z2; + + x2 = vec.X; + y2 = vec.Y; + z2 = vec.Z; + + return new Vector3( + x2 * (1.0f - yy2 - zz2) + y2 * (xy2 + wz2) + z2 * (xz2 - wy2), + x2 * (xy2 - wz2) + y2 * (1.0f - xx2 - zz2) + z2 * (yz2 + wx2), + x2 * (xz2 + wy2) + y2 * (yz2 - wx2) + z2 * (1.0f - xx2 - yy2)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 UnitXRotated(Quaternion rot) + { + float y2 = rot.Y + rot.Y; + float z2 = rot.Z + rot.Z; + + float wy2 = rot.W * y2; + float wz2 = rot.W * z2; + float xy2 = rot.X * y2; + float xz2 = rot.X * z2; + float yy2 = rot.Y * y2; + float zz2 = rot.Z * z2; + + return new Vector3(1.0f - yy2 - zz2, xy2 + wz2, xz2 - wy2); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 UnitYRotated(Quaternion rot) + { + float x2 = rot.X + rot.X; + float y2 = rot.Y + rot.Y; + float z2 = rot.Z + rot.Z; + + float wx2 = rot.W * x2; + float wz2 = rot.W * z2; + float xx2 = rot.X * x2; + float xy2 = rot.X * y2; + float yz2 = rot.Y * z2; + float zz2 = rot.Z * z2; + + return new Vector3(xy2 - wz2, 1.0f - xx2 - zz2, yz2 + wx2); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 UnitZRotated(Quaternion rot) + { + float x2 = rot.X + rot.X; + float y2 = rot.Y + rot.Y; + float z2 = rot.Z + rot.Z; + + float wx2 = rot.W * x2; + float wy2 = rot.W * y2; + float xx2 = rot.X * x2; + float xz2 = rot.X * z2; + float yy2 = rot.Y * y2; + float yz2 = rot.Y * z2; + + return new Vector3(xz2 + wy2, yz2 - wx2, 1.0f - xx2 - yy2); + } + + //quaternion must be normalized <0,0,z,w> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 RotateByQZ(Vector3 vec, Quaternion rot) + { + float z2 = rot.Z + rot.Z; + float wz2 = rot.W * z2; + float zz2 = 1.0f - rot.Z * z2; + + return new Vector3( + vec.X * zz2 - vec.Y * wz2, + vec.X * wz2 + vec.Y * zz2, + vec.Z);; + } + + //quaternion must be normalized <0,0,z,w> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 InverseRotateByQZ(Vector3 vec, Quaternion rot) + { + float z2 = rot.Z + rot.Z; + float wz2 = rot.W * z2; + float zz2 = 1.0f - rot.Z * z2; + + return new Vector3( + vec.X * zz2 + vec.Y * wz2, + vec.Y * zz2 - vec.X * wz2, + vec.Z); + } + + //shortQuaternion must be normalized + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 RotateByShortQZ(Vector3 vec, Vector2 shortQuaternion) + { + float z2 = shortQuaternion.X + shortQuaternion.X; + float zz2 = 1.0f - shortQuaternion.X * z2; + float wz2 = shortQuaternion.Y * z2; + + return new Vector3( + vec.X * zz2 - vec.Y * wz2, + vec.X * wz2 + vec.Y * zz2, + vec.Z); ; + } + + //shortQuaternion must be normalized + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 InverseRotateByShortQZ(Vector3 vec, Vector2 shortQuaternion) + { + float z2 = shortQuaternion.X + shortQuaternion.X; + float zz2 = 1.0f - shortQuaternion.X * z2; + float wz2 = shortQuaternion.Y * z2; + + return new Vector3( + vec.X * zz2 + vec.Y * wz2, + vec.Y * zz2 - vec.X * wz2, + vec.Z); + } #endregion Static Methods #region Overrides - public override bool Equals(object obj) + public readonly override bool Equals(object obj) { - if (!(obj is Vector3)) + if (obj is not Vector3 other) return false; - Vector3 other = (Vector3)obj; if (X != other.X) return false; if (Y != other.Y) @@ -586,7 +1196,7 @@ public override bool Equals(object obj) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Vector3 other) + public readonly bool Equals(Vector3 other) { if (X != other.X) return false; @@ -598,7 +1208,7 @@ public bool Equals(Vector3 other) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool NotEqual(Vector3 other) + public readonly bool NotEqual(Vector3 other) { if (X != other.X) return true; @@ -610,7 +1220,7 @@ public bool NotEqual(Vector3 other) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() + public readonly override int GetHashCode() { int hash = X.GetHashCode(); hash = Utils.CombineHash(hash, Y.GetHashCode()); @@ -622,9 +1232,17 @@ public override int GetHashCode() /// Get a formatted string representation of the vector /// /// A string representation of the vector - public override string ToString() + public readonly override string ToString() { - return String.Format(Utils.EnUsCulture, "<{0}, {1}, {2}>", X, Y, Z); + StringBuilder sb = new(); + sb.Append('<'); + sb.Append(X.ToString(Utils.EnUsCulture)); + sb.Append(", "); + sb.Append(Y.ToString(Utils.EnUsCulture)); + sb.Append(", "); + sb.Append(Z.ToString(Utils.EnUsCulture)); + sb.Append('>'); + return sb.ToString(); } /// @@ -632,12 +1250,18 @@ public override string ToString() /// decimal digits and separated by spaces only /// /// Raw string representation of the vector - public string ToRawString() + public readonly string ToRawString() { CultureInfo enUs = new CultureInfo("en-us"); enUs.NumberFormat.NumberDecimalDigits = 3; - return String.Format(enUs, "{0} {1} {2}", X, Y, Z); + StringBuilder sb = new(); + sb.Append(X.ToString(enUs)); + sb.Append(' '); + sb.Append(Y.ToString(enUs)); + sb.Append(' '); + sb.Append(Z.ToString(enUs)); + return sb.ToString(); } #endregion Overrides @@ -768,16 +1392,16 @@ public static explicit operator Vector3(Vector3d value) #endregion Operators /// A vector with a value of 0,0,0 - public readonly static Vector3 Zero = new Vector3(); + public readonly static Vector3 Zero = new(); /// A vector with a value of 1,1,1 - public readonly static Vector3 One = new Vector3(1f); + public readonly static Vector3 One = new(1f); /// A unit vector facing forward (X axis), value 1,0,0 - public readonly static Vector3 UnitX = new Vector3(1f, 0f, 0f); + public readonly static Vector3 UnitX = new(1f, 0f, 0f); /// A unit vector facing left (Y axis), value 0,1,0 - public readonly static Vector3 UnitY = new Vector3(0f, 1f, 0f); + public readonly static Vector3 UnitY = new(0f, 1f, 0f); /// A unit vector facing up (Z axis), value 0,0,1 - public readonly static Vector3 UnitZ = new Vector3(0f, 0f, 1f); - public readonly static Vector3 MinValue = new Vector3(float.MinValue, float.MinValue, float.MinValue); - public readonly static Vector3 MaxValue = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue); + public readonly static Vector3 UnitZ = new(0f, 0f, 1f); + public readonly static Vector3 MinValue = new(float.MinValue, float.MinValue, float.MinValue); + public readonly static Vector3 MaxValue = new(float.MaxValue, float.MaxValue, float.MaxValue); } } diff --git a/OpenMetaverse.Types/Vector3d.cs b/OpenMetaverse.Types/Vector3d.cs index 50bd368e..96c63141 100644 --- a/OpenMetaverse.Types/Vector3d.cs +++ b/OpenMetaverse.Types/Vector3d.cs @@ -27,6 +27,8 @@ using System; using System.Runtime.InteropServices; using System.Globalization; +using System.Text; +using System.Runtime.CompilerServices; namespace OpenMetaverse { @@ -308,28 +310,163 @@ public static Vector3d Normalize(Vector3d value) /// /// A string representation of a 3D vector, enclosed /// in arrow brackets and separated by commas - public static Vector3d Parse(string val) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe Vector3d Parse(string val) { - char[] splitChar = { ',' }; - string[] split = val.Replace("<", String.Empty).Replace(">", String.Empty).Split(splitChar); - return new Vector3d( - Double.Parse(split[0].Trim(), Utils.EnUsCulture), - Double.Parse(split[1].Trim(), Utils.EnUsCulture), - Double.Parse(split[2].Trim(), Utils.EnUsCulture)); + return Parse(val.AsSpan()); } - public static bool TryParse(string val, out Vector3d result) + public static unsafe Vector3d Parse(ReadOnlySpan sp) { - try + if (sp.Length < 7) + throw new FormatException("Invalid Vector3"); + + int start = 0; + fixed (char* p = sp) { - result = Parse(val); - return true; + while (start < sp.Length) + { + if (p[start++] == '<') + break; + } + if (start > sp.Length - 6) + throw new FormatException("Invalid Vector3"); + + int comma1 = start + 1; + while (comma1 < sp.Length) + { + if (p[comma1] == ',') + break; + comma1++; + } + if (comma1 > sp.Length - 5) + throw new FormatException("Invalid Vector3"); + + if (!double.TryParse(sp[start..comma1], NumberStyles.Float, Utils.EnUsCulture, out double x)) + throw new FormatException("Invalid Vector3"); + + comma1++; + start = comma1; + comma1++; + while (comma1 < sp.Length) + { + if (p[comma1] == ',') + break; + comma1++; + } + if (comma1 > sp.Length - 3) + throw new FormatException("Invalid Vector3"); + if (!double.TryParse(sp[start..comma1], NumberStyles.Float, Utils.EnUsCulture, out double y)) + throw new FormatException("Invalid Vector3"); + + comma1++; + start = comma1; + comma1++; + while (comma1 < sp.Length) + { + if (p[comma1] == '>') + break; + comma1++; + } + if (comma1 >= sp.Length) + throw new FormatException("Invalid Vector3"); + + if (!double.TryParse(sp[start..comma1], NumberStyles.Float, Utils.EnUsCulture, out double z)) + throw new FormatException("Invalid Vector3"); + return new Vector3d(x, y, z); } - catch (Exception) + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public unsafe static bool TryParse(string val, out Vector3d result) + { + return TryParse(val.AsSpan(), out result); + } + + public unsafe static bool TryParse(ReadOnlySpan sp, out Vector3d result) + { + if (sp.Length < 7) { - result = Vector3d.Zero; + result = Zero; return false; } + + int start = 0; + fixed (char* p = sp) + { + while (start < sp.Length) + { + if (p[start++] == '<') + break; + } + if (start > sp.Length - 6) + { + result = Zero; + return false; + } + + int comma1 = start + 1; + while (comma1 < sp.Length) + { + if (p[comma1] == ',') + break; + comma1++; + } + if (comma1 > sp.Length - 5) + { + result = Zero; + return false; + } + + if (!double.TryParse(sp[start..comma1], NumberStyles.Float, Utils.EnUsCulture, out double x)) + { + result = Zero; + return false; + } + + comma1++; + start = comma1; + comma1++; + while (comma1 < sp.Length) + { + if (p[comma1] == ',') + break; + comma1++; + } + if (comma1 > sp.Length - 3) + { + result = Zero; + return false; + } + if (!double.TryParse(sp[start..comma1], NumberStyles.Float, Utils.EnUsCulture, out double y)) + { + result = Zero; + return false; + } + + comma1++; + start = comma1; + comma1++; + while (comma1 < sp.Length) + { + if (p[comma1] == '>') + break; + comma1++; + } + if (comma1 >= sp.Length) + { + result = Zero; + return false; + } + + if (!double.TryParse(sp[start..comma1], NumberStyles.Float, Utils.EnUsCulture, out double z)) + { + result = Zero; + return false; + } + result = new Vector3d(x, y, z); + return true; + } } /// @@ -376,7 +513,15 @@ public override int GetHashCode() /// A string representation of the vector public override string ToString() { - return String.Format(Utils.EnUsCulture, "<{0}, {1}, {2}>", X, Y, Z); + StringBuilder sb = new(); + sb.Append('<'); + sb.Append(X.ToString(Utils.EnUsCulture)); + sb.Append(", "); + sb.Append(Y.ToString(Utils.EnUsCulture)); + sb.Append(", "); + sb.Append(Z.ToString(Utils.EnUsCulture)); + sb.Append('>'); + return sb.ToString(); } /// @@ -386,10 +531,16 @@ public override string ToString() /// Raw string representation of the vector public string ToRawString() { - CultureInfo enUs = new CultureInfo("en-us"); + CultureInfo enUs = new("en-us"); enUs.NumberFormat.NumberDecimalDigits = 3; - return String.Format(enUs, "{0} {1} {2}", X, Y, Z); + StringBuilder sb = new(); + sb.Append(X.ToString(enUs)); + sb.Append(' '); + sb.Append(Y.ToString(enUs)); + sb.Append(' '); + sb.Append(Z.ToString(enUs)); + return sb.ToString(); } #endregion Overrides diff --git a/OpenMetaverse.Types/Vector4.cs b/OpenMetaverse.Types/Vector4.cs index 2aad0146..fe5a3210 100644 --- a/OpenMetaverse.Types/Vector4.cs +++ b/OpenMetaverse.Types/Vector4.cs @@ -28,6 +28,7 @@ using System.Globalization; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Text; namespace OpenMetaverse { @@ -93,10 +94,7 @@ public Vector4(byte[] byteArray, int pos) public Vector4(Vector4 value) { - X = value.X; - Y = value.Y; - Z = value.Z; - W = value.W; + this = value; } #endregion Constructors @@ -132,11 +130,19 @@ public void Sub(Vector4 v) [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Clamp(float min, float max) { - X = Utils.Clamp(X, min, max); - Y = Utils.Clamp(Y, min, max); - Z = Utils.Clamp(Z, min, max); - W = Utils.Clamp(W, min, max); + if (X < min) X = min; + else if (X > max) X = max; + + if (Y < min) Y = min; + else if (Y > max) Y = max; + + if (Z < min) Z = min; + else if (Z > max) Z = max; + + if (W < min) W = min; + else if (W > max) W = max; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Min(Vector4 v) { @@ -222,6 +228,20 @@ public bool IsZero() return false; return true; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool IsNotZero() + { + if (X != 0) + return true; + if (Y != 0) + return true; + if (Z != 0) + return true; + if (W != 0) + return true; + return false; + } /// /// IComparable.CompareTo implementation /// @@ -276,12 +296,35 @@ public byte[] GetBytes() /// Destination byte array /// Position in the destination array to start /// writing. Must be at least 16 bytes before the end of the array - public void ToBytes(byte[] dest, int pos) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public unsafe void ToBytes(byte[] dest, int pos) { - Utils.FloatToBytesSafepos(X, dest, pos); - Utils.FloatToBytesSafepos(Y, dest, pos + 4); - Utils.FloatToBytesSafepos(Z, dest, pos + 8); - Utils.FloatToBytesSafepos(W, dest, pos + 12); + if (Utils.CanDirectCopyLE) + { + fixed (byte* d = &dest[0]) + *(Vector4*)(d + pos) = this; + } + else + { + Utils.FloatToBytesSafepos(X, dest, pos); + Utils.FloatToBytesSafepos(Y, dest, pos + 4); + Utils.FloatToBytesSafepos(Z, dest, pos + 8); + Utils.FloatToBytesSafepos(W, dest, pos + 12); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public unsafe void ToBytes(byte* dest) + { + if (Utils.CanDirectCopyLE) + *(Vector4*)dest = this; + else + { + Utils.FloatToBytes(X, dest); + Utils.FloatToBytes(Y, dest + 4); + Utils.FloatToBytes(Z, dest + 8); + Utils.FloatToBytes(W, dest + 12); + } } #endregion Public Methods @@ -470,29 +513,172 @@ public static Vector4 Transform(Vector4 vector, Matrix4 matrix) (vector.X * matrix.M14) + (vector.Y * matrix.M24) + (vector.Z * matrix.M34) + (vector.W * matrix.M44)); } - public static Vector4 Parse(string val) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public unsafe static Vector4 Parse(string val) { - char[] splitChar = { ',' }; - string[] split = val.Replace("<", String.Empty).Replace(">", String.Empty).Split(splitChar); - return new Vector4( - float.Parse(split[0].Trim(), Utils.EnUsCulture), - float.Parse(split[1].Trim(), Utils.EnUsCulture), - float.Parse(split[2].Trim(), Utils.EnUsCulture), - float.Parse(split[3].Trim(), Utils.EnUsCulture)); + return Parse(val.AsSpan()); } + public static Vector4 Parse(ReadOnlySpan sp) + { + if (sp.Length < 7) + throw new FormatException("Invalid Vector4"); + + int start = 0; + int comma = 0; + char c; + + do + { + c = Unsafe.Add(ref MemoryMarshal.GetReference(sp), comma); + if (c == ',' || c == '<') + break; + } + while (++comma < sp.Length); + + if (c == '<') + { + start = ++comma; + while (++comma < sp.Length) + { + if (Unsafe.Add(ref MemoryMarshal.GetReference(sp), comma) == ',') + break; + } + } + if (comma > sp.Length - 5) + throw new FormatException("Invalid Vector4"); + + if (!float.TryParse(sp[start..comma], NumberStyles.Float, Utils.EnUsCulture, out float x)) + throw new FormatException("Invalid Vector4"); + + start = ++comma; + while (++comma < sp.Length) + { + if (Unsafe.Add(ref MemoryMarshal.GetReference(sp), comma) == ',') + break; + } + if (comma > sp.Length - 3) + throw new FormatException("Invalid Vector4"); + if (!float.TryParse(sp[start..comma], NumberStyles.Float, Utils.EnUsCulture, out float y)) + throw new FormatException("Invalid Vector4"); + + start = ++comma; + while (++comma < sp.Length) + { + if (Unsafe.Add(ref MemoryMarshal.GetReference(sp), comma) == ',') + break; + } + if (comma > sp.Length - 1) + throw new FormatException("Invalid Vector4"); + if (!float.TryParse(sp[start..comma], NumberStyles.Float, Utils.EnUsCulture, out float z)) + throw new FormatException("Invalid Vector4"); + + start = ++comma; + while (++comma < sp.Length) + { + if (Unsafe.Add(ref MemoryMarshal.GetReference(sp), comma) == '>') + break; + } + + if (!float.TryParse(sp[start..comma], NumberStyles.Float, Utils.EnUsCulture, out float w)) + throw new FormatException("Invalid Vector4"); + return new Vector4(x, y, z, w); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryParse(string val, out Vector4 result) { - try + return TryParse(val.AsSpan(), out result); + } + + public static bool TryParse(ReadOnlySpan sp, out Vector4 result) + { + if (sp.Length < 7) { - result = Parse(val); - return true; + result = Zero; + return false; + } + int start = 0; + int comma = 0; + char c; + do + { + c = Unsafe.Add(ref MemoryMarshal.GetReference(sp), comma); + if (c == ',' || c == '<') + break; + } + while (++comma < sp.Length); + + if (c == '<') + { + start = ++comma; + while (++comma < sp.Length) + { + if (Unsafe.Add(ref MemoryMarshal.GetReference(sp), comma) == ',') + break; + } + } + if (comma > sp.Length - 5) + { + result = Zero; + return false; + } + + if (!float.TryParse(sp[start..comma], NumberStyles.Float, Utils.EnUsCulture, out float x)) + { + result = Zero; + return false; + } + + start = ++comma; + while (++comma < sp.Length) + { + if (Unsafe.Add(ref MemoryMarshal.GetReference(sp), comma) == ',') + break; + } + if (comma > sp.Length - 5) + { + result = Zero; + return false; + } + if (!float.TryParse(sp[start..comma], NumberStyles.Float, Utils.EnUsCulture, out float y)) + { + result = Zero; + return false; + } + + start = ++comma; + while (++comma < sp.Length) + { + if (Unsafe.Add(ref MemoryMarshal.GetReference(sp), comma) == ',') + break; + } + if (comma > sp.Length - 1) + { + result = Zero; + return false; + } + if (!float.TryParse(sp[start..comma], NumberStyles.Float, Utils.EnUsCulture, out float z)) + { + result = Zero; + return false; + } + + start = ++comma; + while (++comma < sp.Length) + { + c = Unsafe.Add(ref MemoryMarshal.GetReference(sp), comma); + if(c == ' ' || c == '>') + break; } - catch (Exception) + if (!float.TryParse(sp[start..comma], NumberStyles.Float, Utils.EnUsCulture, out float w)) { - result = new Vector4(); + result = Zero; return false; } + + result = new Vector4(x, y, z, w); + return true; } #endregion Static Methods @@ -501,10 +687,9 @@ public static bool TryParse(string val, out Vector4 result) public override bool Equals(object obj) { - if (!(obj is Vector4)) + if (obj is not Vector4 other) return false; - Vector4 other = (Vector4)obj; if (X != other.X) return false; if (Y != other.Y) @@ -549,7 +734,17 @@ public override int GetHashCode() public override string ToString() { - return String.Format(Utils.EnUsCulture, "<{0}, {1}, {2}, {3}>", X, Y, Z, W); + StringBuilder sb = new(); + sb.Append('<'); + sb.Append(X.ToString(Utils.EnUsCulture)); + sb.Append(", "); + sb.Append(Y.ToString(Utils.EnUsCulture)); + sb.Append(", "); + sb.Append(Z.ToString(Utils.EnUsCulture)); + sb.Append(", "); + sb.Append(W.ToString(Utils.EnUsCulture)); + sb.Append('>'); + return sb.ToString(); } /// @@ -559,10 +754,18 @@ public override string ToString() /// Raw string representation of the vector public string ToRawString() { - CultureInfo enUs = new CultureInfo("en-us"); + CultureInfo enUs = new("en-us"); enUs.NumberFormat.NumberDecimalDigits = 3; - return String.Format(enUs, "{0} {1} {2} {3}", X, Y, Z, W); + StringBuilder sb = new(); + sb.Append(X.ToString(enUs)); + sb.Append(' '); + sb.Append(Y.ToString(enUs)); + sb.Append(' '); + sb.Append(Z.ToString(enUs)); + sb.Append(' '); + sb.Append(W.ToString(enUs)); + return sb.ToString(); } #endregion Overrides @@ -658,18 +861,18 @@ public string ToRawString() #endregion Operators /// A vector with a value of 0,0,0,0 - public readonly static Vector4 Zero = new Vector4(); + public readonly static Vector4 Zero = new(); /// A vector with a value of 1,1,1,1 - public readonly static Vector4 One = new Vector4(1f, 1f, 1f, 1f); + public readonly static Vector4 One = new(1f, 1f, 1f, 1f); /// A vector with a value of 1,0,0,0 - public readonly static Vector4 UnitX = new Vector4(1f, 0f, 0f, 0f); + public readonly static Vector4 UnitX = new(1f, 0f, 0f, 0f); /// A vector with a value of 0,1,0,0 - public readonly static Vector4 UnitY = new Vector4(0f, 1f, 0f, 0f); + public readonly static Vector4 UnitY = new(0f, 1f, 0f, 0f); /// A vector with a value of 0,0,1,0 - public readonly static Vector4 UnitZ = new Vector4(0f, 0f, 1f, 0f); + public readonly static Vector4 UnitZ = new(0f, 0f, 1f, 0f); /// A vector with a value of 0,0,0,1 - public readonly static Vector4 UnitW = new Vector4(0f, 0f, 0f, 1f); - public readonly static Vector4 MinValue = new Vector4(float.MinValue, float.MinValue, float.MinValue, float.MinValue); - public readonly static Vector4 MaxValue = new Vector4(float.MaxValue, float.MaxValue, float.MaxValue, float.MaxValue); + public readonly static Vector4 UnitW = new(0f, 0f, 0f, 1f); + public readonly static Vector4 MinValue = new(float.MinValue, float.MinValue, float.MinValue, float.MinValue); + public readonly static Vector4 MaxValue = new(float.MaxValue, float.MaxValue, float.MaxValue, float.MaxValue); } } diff --git a/OpenMetaverse.Utilities/OpenMetaverse.Utilities.csproj b/OpenMetaverse.Utilities/OpenMetaverse.Utilities.csproj index 43ec7dea..20893c6f 100644 --- a/OpenMetaverse.Utilities/OpenMetaverse.Utilities.csproj +++ b/OpenMetaverse.Utilities/OpenMetaverse.Utilities.csproj @@ -1,7 +1,7 @@  Local - net48 + net6.0 OpenMetaverse.Utilities OpenMetaverse.Utilities 1591,1574,0419,0618 diff --git a/OpenMetaverse.sln b/OpenMetaverse.sln index 03e57126..8157aa16 100644 --- a/OpenMetaverse.sln +++ b/OpenMetaverse.sln @@ -61,6 +61,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenMetaverse.PrimMesher", EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{49AFD80D-D399-43FC-A9EE-9F15BC6D49E7}" ProjectSection(SolutionItems) = preProject + Directory.Build.props = Directory.Build.props README.md = README.md EndProjectSection EndProject diff --git a/OpenMetaverse/BitPack.cs b/OpenMetaverse/BitPack.cs index f1dd02f3..471a73ea 100644 --- a/OpenMetaverse/BitPack.cs +++ b/OpenMetaverse/BitPack.cs @@ -69,18 +69,17 @@ public BitPack(byte[] data, int pos, int? bitp = null) { Data = data; bytePos = pos; - - if(bitp.HasValue) + if (bitp.HasValue) { bitPos = bitp.Value; - if(bitPos < 0) + if (bitPos < 0) bitPos = 0; - else if(bitPos > 7) + else if (bitPos > 7) bitPos = 7; // this is wrong anyway if (bitPos == 0) Data[pos] = 0; else - Data[pos] &= (byte)~(0xff >> bitPos); + Data[pos] &= (byte)~(0xff >> bitPos); } else { @@ -88,10 +87,30 @@ public BitPack(byte[] data, int pos, int? bitp = null) } } + public void Reset(byte[] data, int pos, int? bitp = null) + { + Data = data; + bytePos = pos; + if (bitp.HasValue) + { + bitPos = bitp.Value; + if (bitPos < 0) + bitPos = 0; + else if (bitPos > 7) + bitPos = 7; // this is wrong anyway + if (bitPos == 0) + Data[pos] = 0; + else + Data[pos] &= (byte)~(0xff >> bitPos); + } + else + bitPos = 0; + } /// /// Pack a floating point value in to the data /// /// Floating point value to pack + [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public unsafe void PackFloat(float data) { int d = (*(int*)&data); @@ -106,16 +125,10 @@ public unsafe void PackFloat(float data) /// /// Integer containing the data to pack /// Number of bits of the integer to pack + [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public void PackBits(int data, int totalCount) { - while (totalCount > 8) - { - PackBitsFromByte((byte)data); - data >>= 8; - totalCount -= 8; - } - if (totalCount > 0) - PackBitsFromByte((byte)data, totalCount); + PackBits((uint)data, totalCount); } /// @@ -123,6 +136,7 @@ public void PackBits(int data, int totalCount) /// /// Unsigned integer containing the data to pack /// Number of bits of the integer to pack + [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public void PackBits(uint data, int totalCount) { while (totalCount > 8) @@ -135,6 +149,7 @@ public void PackBits(uint data, int totalCount) PackBitsFromByte((byte)data, totalCount); } + [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public void PackBitsFromUInt(uint data) { PackBitsFromByte((byte)data); @@ -143,6 +158,24 @@ public void PackBitsFromUInt(uint data) PackBitsFromByte((byte)(data >> 24)); } + [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] + public void PackBitsFromInt(int data) + { + PackBitsFromUInt((uint)data); + } + + [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] + public void PackBitsFromUShort(ushort data) + { + PackBitsFromByte((byte)data); + PackBitsFromByte((byte)(data >> 8)); + } + + [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] + public void PackBitsFromShort(short data) + { + PackBitsFromUShort((ushort) data); + } /// /// @@ -195,9 +228,50 @@ public void PackFixed(float data, bool isSigned, int intBits, int fracBits) /// public void PackUUID(UUID data) { - byte[] bytes = data.GetBytes(); - for (int i = 0; i < 16; i++) - PackBitsFromByte(bytes[i]); + if (BitConverter.IsLittleEndian) + { + PackBitsFromByte(data.bytea3); + PackBitsFromByte(data.bytea2); + PackBitsFromByte(data.bytea1); + PackBitsFromByte(data.bytea0); + + PackBitsFromByte(data.byteb1); + PackBitsFromByte(data.byteb0); + + PackBitsFromByte(data.bytec1); + PackBitsFromByte(data.bytec0); + + PackBitsFromByte(data.d); + PackBitsFromByte(data.e); + PackBitsFromByte(data.f); + PackBitsFromByte(data.g); + PackBitsFromByte(data.h); + PackBitsFromByte(data.i); + PackBitsFromByte(data.j); + PackBitsFromByte(data.k); + } + else + { + PackBitsFromByte(data.bytea0); + PackBitsFromByte(data.bytea1); + PackBitsFromByte(data.bytea2); + PackBitsFromByte(data.bytea3); + + PackBitsFromByte(data.byteb0); + PackBitsFromByte(data.byteb1); + + PackBitsFromByte(data.bytec0); + PackBitsFromByte(data.bytec1); + + PackBitsFromByte(data.k); + PackBitsFromByte(data.j); + PackBitsFromByte(data.i); + PackBitsFromByte(data.h); + PackBitsFromByte(data.g); + PackBitsFromByte(data.f); + PackBitsFromByte(data.e); + PackBitsFromByte(data.d); + } } /// @@ -206,10 +280,10 @@ public void PackUUID(UUID data) /// public void PackColor(Color4 data) { - PackBitsFromByte(Utils.FloatToByte(data.R, 0f, 1f)); - PackBitsFromByte(Utils.FloatToByte(data.G, 0f, 1f)); - PackBitsFromByte(Utils.FloatToByte(data.B, 0f, 1f)); - PackBitsFromByte(Utils.FloatToByte(data.A, 0f, 1f)); + PackBitsFromByte(Utils.FloatZeroOneToByte(data.R)); + PackBitsFromByte(Utils.FloatZeroOneToByte(data.G)); + PackBitsFromByte(Utils.FloatZeroOneToByte(data.B)); + PackBitsFromByte(Utils.FloatZeroOneToByte(data.A)); } /// @@ -292,7 +366,6 @@ public uint UnpackUInt() tmp |= (byte)(UnpackByte() << 24); return tmp; } - public byte UnpackByte() { byte o = Data[bytePos]; @@ -344,7 +417,6 @@ public string UnpackString(int size) bytePos += size; return str; } - public UUID UnpackUUID() { if (bitPos != 0) throw new IndexOutOfRangeException(); @@ -393,7 +465,7 @@ public void PackBitsFromByte(byte inbyte, int count) if (count > 8) //should not happen count = 7; else - count = count - 1; + --count; while (count >= 0) { diff --git a/OpenMetaverse/Capabilities/CapsBase.cs b/OpenMetaverse/Capabilities/CapsBase.cs index 28b39664..8db97c2a 100644 --- a/OpenMetaverse/Capabilities/CapsBase.cs +++ b/OpenMetaverse/Capabilities/CapsBase.cs @@ -38,10 +38,28 @@ public static class CapsBase public delegate void OpenWriteEventHandler(HttpWebRequest request); public delegate void DownloadProgressEventHandler(HttpWebRequest request, HttpWebResponse response, int bytesReceived, int totalBytesToReceive); public delegate void RequestCompletedEventHandler(HttpWebRequest request, HttpWebResponse response, byte[] responseData, Exception error); + public static bool ValidateServerCertificate( + object sender, + X509Certificate certificate, + X509Chain chain, + SslPolicyErrors sslPolicyErrors) + { + //if (m_NoVerifyCertChain) + sslPolicyErrors &= ~SslPolicyErrors.RemoteCertificateChainErrors; + + //if (m_NoVerifyCertHostname) + sslPolicyErrors &= ~SslPolicyErrors.RemoteCertificateNameMismatch; + + if (sslPolicyErrors == SslPolicyErrors.None) + return true; + + return false; + } static CapsBase() { - ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true; + // Even though this will compile on Mono 2.4, it throws a runtime exception + ServicePointManager.ServerCertificateValidationCallback = ValidateServerCertificate; } private class RequestState diff --git a/OpenMetaverse/DllmapConfigHelper.cs b/OpenMetaverse/DllmapConfigHelper.cs new file mode 100644 index 00000000..6dd01f91 --- /dev/null +++ b/OpenMetaverse/DllmapConfigHelper.cs @@ -0,0 +1,387 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics.X86; +using System.Xml.Serialization; +using System.Xml; + +namespace OpenMetaverse +{ + public static class DllmapConfigHelper + { + [XmlRoot("dllmap")] + public class dllmap + { + [XmlAttribute("os")] + public string os; + [XmlAttribute("cpu")] + public string cpu; + [XmlAttribute("target")] + public string target; + [XmlAttribute("dll")] + public string dll; + } + + [XmlRoot("configuration")] + public class configuration + { + [XmlElement("dllmap")] + public List maps = new(); + } + + private static readonly Dictionary LoadedLibs = new(); + private static readonly HashSet RegisteredAssemblies = new(); + private static readonly object m_mainlock = new object(); + + public static void RegisterAssembly(Assembly assembly) + { + lock (m_mainlock) + { + if (RegisteredAssemblies.Contains(assembly)) + return; + RegisteredAssemblies.Add(assembly); + } + + string assemblyPath = Path.GetDirectoryName(assembly.Location); + string path = Path.Combine(assemblyPath, + Path.GetFileNameWithoutExtension(assembly.Location) + ".dll.config"); + configuration c = ParseConfig(path); + if (c is null) + return; + + int matchs = ProcessAssemblyConfiguration(c, out List<(string libname, string libpath)> libstoload); + if (matchs == 0) + return; + if (libstoload.Count == 0) + return; + + foreach (var (libname, libpath) in libstoload) + { + path= Path.Combine(assemblyPath, libpath); + if (NativeLibrary.TryLoad(path, out IntPtr ptr)) + LoadedLibs.Add(libname, ptr); + else + LoadedLibs.Add(libname, IntPtr.Zero); + } + NativeLibrary.SetDllImportResolver(assembly, AssemblyDllImport); + } + private static IntPtr AssemblyDllImport(string libraryName, Assembly assembly, DllImportSearchPath? dllImportSearchPath) + { + if (LoadedLibs.TryGetValue(libraryName, out IntPtr ptr)) + return ptr; + return IntPtr.Zero; + } + + public static configuration ParseConfig(string path) + { + if (string.IsNullOrWhiteSpace(path)) + return null; + + configuration c; + try + { + if (!File.Exists(path)) + return null; + using FileStream fs = new(path, FileMode.Open); + using XmlReader reader = XmlReader.Create(fs); + XmlSerializer serializer = new(typeof(configuration)); + c = (configuration)serializer.Deserialize(reader); + } + catch + { + return null; + } + if (c is null || c.maps is null || c.maps.Count == 0) + return null; + return c; + } + + public static int ProcessAssemblyConfiguration(configuration c, out List<(string libname, string libpath)> libsToLoad) + { + libsToLoad = new List<(string libname, string libpath)>(c.maps.Count); + int MatchCount = 0; + HashSet libsdone = new(); + foreach (dllmap m in c.maps) + { + if (string.IsNullOrEmpty(m.target)) + continue; + if (string.IsNullOrEmpty(m.os)) + continue; + if (string.IsNullOrEmpty(m.dll)) + continue; + if (libsdone.Contains(m.dll)) + continue; + + bool match = false; + bool negate = m.os[0] == '!'; + if (negate) + m.os = m.os[1..]; + string[] tos = m.os.Split(','); + foreach (string s in tos) + { + match = OperatingSystem.IsOSPlatform(s); + if (match) + break; + } + if (negate) + match = !match; + if (!match) + continue; + + if (string.IsNullOrEmpty(m.cpu)) + { + libsdone.Add(m.dll); + MatchCount++; + if (!LoadedLibs.ContainsKey(m.dll)) + libsToLoad.Add((m.dll, m.target)); + break; + } + + negate = m.cpu[0] == '!'; + if (negate) + m.cpu = m.cpu[1..]; + m.cpu = m.cpu.ToLower(); + string[] tcpu = m.cpu.Split(','); + match = false; + foreach (string s in tcpu) + { + switch (s) + { + case "x86": + if (RuntimeInformation.ProcessArchitecture == Architecture.X86) + match = true; + break; + case "x86avx": + if (Avx.IsSupported && RuntimeInformation.ProcessArchitecture == Architecture.X86) + match = true; + break; + case "x86-64": + if (RuntimeInformation.ProcessArchitecture == Architecture.X64) + match = true; + break; + case "x86-64avx": + if (Avx.IsSupported && RuntimeInformation.ProcessArchitecture == Architecture.X64) + match = true; + break; + case "arm": + case "aarch32": + if (RuntimeInformation.ProcessArchitecture == Architecture.Arm) + match = true; + break; + case "arm64": + case "armv8": + case "aarch64": + if (RuntimeInformation.ProcessArchitecture == Architecture.Arm64) + match = true; + break; + case "s390": + case "s390x": + if (RuntimeInformation.ProcessArchitecture == Architecture.S390x) + match = true; + break; + } + if (match) + break; + } + if(negate) + match = !match; + + if (match) + { + MatchCount++; + libsdone.Add(m.dll); + if (!LoadedLibs.ContainsKey(m.dll)) + libsToLoad.Add((m.dll, m.target)); + } + } + return MatchCount; + } + + public static void RegisterDll(Assembly assembly, string libname) + { + lock (m_mainlock) + { + if (RegisteredAssemblies.Contains(assembly)) + return; + RegisteredAssemblies.Add(assembly); + } + + if (!LoadedLibs.TryGetValue(libname, out IntPtr ptr)) + { + string assemblyPath = Path.GetDirectoryName(assembly.Location); + string path = Path.Combine(assemblyPath, libname + ".dllconfig"); + configuration c = ParseConfig(path); + if (c is null) + return; + + string libpath = ProcessDllConfiguration(c); + if (string.IsNullOrEmpty(libpath)) + { + LoadedLibs.Add(libname, IntPtr.Zero); + return; + } + + libpath = Path.Combine(assemblyPath, libpath); + if (!NativeLibrary.TryLoad(libpath, out ptr)) + { + LoadedLibs.Add(libname, IntPtr.Zero); + return; + } + + LoadedLibs.Add(libname, ptr); + } + if (ptr != IntPtr.Zero) + NativeLibrary.SetDllImportResolver(assembly, AssemblyDllImport); + } + + public static IntPtr LoadDll(string libname) + { + if (LoadedLibs.TryGetValue(libname, out IntPtr ptr)) + return ptr; + + string execpath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); + + string path = Path.Combine(execpath, libname + ".dllconfig"); + configuration c = ParseConfig(path); + if (c is null) + return IntPtr.Zero; + + string libpath = ProcessDllConfiguration(c); + if (string.IsNullOrEmpty(libpath)) + { + LoadedLibs.Add(libname, IntPtr.Zero); + return IntPtr.Zero; + } + + libpath = Path.Combine(execpath, libpath); + if (NativeLibrary.TryLoad(libpath, out ptr)) + { + LoadedLibs.Add(libname, ptr); + return ptr; + } + + LoadedLibs.Add(libname, IntPtr.Zero); + return IntPtr.Zero; + } + + public static string ProcessDllConfiguration(configuration c) + { + string newlibname = null; + foreach (dllmap m in c.maps) + { + if (string.IsNullOrEmpty(m.target)) + continue; + if (string.IsNullOrEmpty(m.os)) + continue; + + bool match = false; + bool negate = m.os[0] == '!'; + if (negate) + m.os = m.os[1..]; + string[] tos = m.os.Split(','); + foreach (string s in tos) + { + match = System.OperatingSystem.IsOSPlatform(s); + if (match) + { + match = !negate; + break; + } + } + if (!match) + continue; + + if (string.IsNullOrEmpty(m.cpu)) + { + newlibname = m.target; + break; + } + + negate = m.cpu[0] == '!'; + if (negate) + m.cpu = m.cpu[1..]; + m.cpu = m.cpu.ToLower(); + string[] tcpu = m.cpu.Split(','); + match = false; + foreach (string s in tcpu) + { + switch (s) + { + case "x86": + if (RuntimeInformation.ProcessArchitecture == Architecture.X86) + match = true; + break; + case "x86avx": + if (Avx.IsSupported && RuntimeInformation.ProcessArchitecture == Architecture.X86) + match = true; + break; + case "x86-64": + if (RuntimeInformation.ProcessArchitecture == Architecture.X64) + match = true; + break; + case "x86-64avx": + if (Avx.IsSupported && RuntimeInformation.ProcessArchitecture == Architecture.X64) + match = true; + break; + case "arm": + case "aarch32": + if (RuntimeInformation.ProcessArchitecture == Architecture.Arm) + match = true; + break; + case "arm64": + case "armv8": + case "aarch64": + if (RuntimeInformation.ProcessArchitecture == Architecture.Arm64) + match = true; + break; + case "s390": + case "s390x": + if (RuntimeInformation.ProcessArchitecture == Architecture.S390x) + match = true; + break; + } + if (match) + { + match = !negate; + break; + } + } + if (match) + { + newlibname = m.target; + break; + } + } + return newlibname; + } + } +} diff --git a/OpenMetaverse/Imaging/BakeLayer.cs b/OpenMetaverse/Imaging/BakeLayer.cs index 91326df4..bc8e6f0e 100644 --- a/OpenMetaverse/Imaging/BakeLayer.cs +++ b/OpenMetaverse/Imaging/BakeLayer.cs @@ -581,9 +581,9 @@ private void ApplyTint(ManagedImage dest, Color4 src) for (int i = 0; i < dest.Red.Length; i++) { - dest.Red[i] = (byte)((dest.Red[i] * Utils.FloatToByte(src.R, 0f, 1f)) >> 8); - dest.Green[i] = (byte)((dest.Green[i] * Utils.FloatToByte(src.G, 0f, 1f)) >> 8); - dest.Blue[i] = (byte)((dest.Blue[i] * Utils.FloatToByte(src.B, 0f, 1f)) >> 8); + dest.Red[i] = (byte)((dest.Red[i] * Utils.FloatZeroOneToByte(src.R)) >> 8); + dest.Green[i] = (byte)((dest.Green[i] * Utils.FloatZeroOneToByte(src.G)) >> 8); + dest.Blue[i] = (byte)((dest.Blue[i] * Utils.FloatZeroOneToByte(src.B)) >> 8); } } @@ -610,9 +610,9 @@ private void InitBakedLayerColor(Color4 color) /// Blue value private void InitBakedLayerColor(float r, float g, float b) { - byte rByte = Utils.FloatToByte(r, 0f, 1f); - byte gByte = Utils.FloatToByte(g, 0f, 1f); - byte bByte = Utils.FloatToByte(b, 0f, 1f); + byte rByte = Utils.FloatZeroOneToByte(r); + byte gByte = Utils.FloatZeroOneToByte(g); + byte bByte = Utils.FloatZeroOneToByte(b); byte rAlt, gAlt, bAlt; diff --git a/OpenMetaverse/Imaging/OpenJPEG.cs b/OpenMetaverse/Imaging/OpenJPEG.cs index 2d68d668..71c8c804 100644 --- a/OpenMetaverse/Imaging/OpenJPEG.cs +++ b/OpenMetaverse/Imaging/OpenJPEG.cs @@ -27,11 +27,11 @@ using System; using System.Drawing; using System.Drawing.Imaging; +using System.Reflection; using System.Runtime.InteropServices; namespace OpenMetaverse.Imaging { -#if !NO_UNSAFE /// /// A Wrapper around openjpeg to encode and decode images to and from byte arrays /// @@ -95,73 +95,45 @@ public override string ToString() start_pos, end_ph_pos, end_pos); } } - #endregion JPEG2000 Structs - #region Unmanaged Function Declarations - + static OpenJPEG() + { + DllmapConfigHelper.RegisterAssembly(typeof(OpenJPEG).Assembly); + } + #region Unmanaged Function Declarations // allocate encoded buffer based on length field [System.Security.SuppressUnmanagedCodeSecurity] - [DllImport("openjpeg-dotnet.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("openjpeg-dotnet", CallingConvention = CallingConvention.Cdecl)] private static extern bool DotNetAllocEncoded(ref MarshalledImage image); // allocate decoded buffer based on width and height fields [System.Security.SuppressUnmanagedCodeSecurity] - [DllImport("openjpeg-dotnet.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("openjpeg-dotnet", CallingConvention = CallingConvention.Cdecl)] private static extern bool DotNetAllocDecoded(ref MarshalledImage image); // free buffers [System.Security.SuppressUnmanagedCodeSecurity] - [DllImport("openjpeg-dotnet.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("openjpeg-dotnet", CallingConvention = CallingConvention.Cdecl)] private static extern bool DotNetFree(ref MarshalledImage image); // encode raw to jpeg2000 [System.Security.SuppressUnmanagedCodeSecurity] - [DllImport("openjpeg-dotnet.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("openjpeg-dotnet", CallingConvention = CallingConvention.Cdecl)] private static extern bool DotNetEncode(ref MarshalledImage image, bool lossless); // decode jpeg2000 to raw [System.Security.SuppressUnmanagedCodeSecurity] - [DllImport("openjpeg-dotnet.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("openjpeg-dotnet", CallingConvention = CallingConvention.Cdecl)] private static extern bool DotNetDecode(ref MarshalledImage image); // decode jpeg2000 to raw, get jpeg2000 file info [System.Security.SuppressUnmanagedCodeSecurity] - [DllImport("openjpeg-dotnet.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("openjpeg-dotnet", CallingConvention = CallingConvention.Cdecl)] private static extern bool DotNetDecodeWithInfo(ref MarshalledImage image); - // invoke 64 bit openjpeg calls - [System.Security.SuppressUnmanagedCodeSecurity] - [DllImport("openjpeg-dotnet-x86_64.dll", CallingConvention = CallingConvention.Cdecl)] - private static extern bool DotNetAllocEncoded64(ref MarshalledImage image); - - // allocate decoded buffer based on width and height fields - [System.Security.SuppressUnmanagedCodeSecurity] - [DllImport("openjpeg-dotnet-x86_64.dll", CallingConvention = CallingConvention.Cdecl)] - private static extern bool DotNetAllocDecoded64(ref MarshalledImage image); - - // free buffers - [System.Security.SuppressUnmanagedCodeSecurity] - [DllImport("openjpeg-dotnet-x86_64.dll", CallingConvention = CallingConvention.Cdecl)] - private static extern bool DotNetFree64(ref MarshalledImage image); - - // encode raw to jpeg2000 - [System.Security.SuppressUnmanagedCodeSecurity] - [DllImport("openjpeg-dotnet-x86_64.dll", CallingConvention = CallingConvention.Cdecl)] - private static extern bool DotNetEncode64(ref MarshalledImage image, bool lossless); - - // decode jpeg2000 to raw - [System.Security.SuppressUnmanagedCodeSecurity] - [DllImport("openjpeg-dotnet-x86_64.dll", CallingConvention = CallingConvention.Cdecl)] - private static extern bool DotNetDecode64(ref MarshalledImage image); - - // decode jpeg2000 to raw, get jpeg2000 file info - [System.Security.SuppressUnmanagedCodeSecurity] - [DllImport("openjpeg-dotnet-x86_64.dll", CallingConvention = CallingConvention.Cdecl)] - private static extern bool DotNetDecodeWithInfo64(ref MarshalledImage image); - #endregion Unmanaged Function Declarations - + #endregion /// OpenJPEG is not threadsafe, so this object is used to lock /// during calls into unmanaged code private static object OpenJPEGLock = new object(); @@ -190,9 +162,7 @@ public static byte[] Encode(ManagedImage image, bool lossless) lock (OpenJPEGLock) { - - bool allocSuccess = (IntPtr.Size == 8) ? DotNetAllocDecoded64(ref marshalled) : DotNetAllocDecoded(ref marshalled); - + bool allocSuccess = DotNetAllocDecoded(ref marshalled); if (!allocSuccess) throw new Exception("DotNetAllocDecoded failed"); @@ -209,7 +179,7 @@ public static byte[] Encode(ManagedImage image, bool lossless) if ((image.Channels & ManagedImage.ImageChannels.Bump) != 0) Marshal.Copy(image.Bump, 0, (IntPtr)(marshalled.decoded.ToInt64() + n * 4), n); // codec will allocate output buffer - bool encodeSuccess = (IntPtr.Size == 8) ? DotNetEncode64(ref marshalled, lossless) : DotNetEncode(ref marshalled, lossless); + bool encodeSuccess = DotNetEncode(ref marshalled, lossless); if (!encodeSuccess) throw new Exception("DotNetEncode failed"); @@ -218,10 +188,7 @@ public static byte[] Encode(ManagedImage image, bool lossless) Marshal.Copy(marshalled.encoded, encoded, 0, marshalled.length); // free buffers - if (IntPtr.Size == 8) - DotNetFree64(ref marshalled); - else - DotNetFree(ref marshalled); + DotNetFree(ref marshalled); } return encoded; @@ -284,18 +251,12 @@ public static bool DecodeToImage(byte[] encoded, out ManagedImage managedImage) lock (OpenJPEGLock) { - if (IntPtr.Size == 8) - DotNetAllocEncoded64(ref marshalled); - else - DotNetAllocEncoded(ref marshalled); + DotNetAllocEncoded(ref marshalled); Marshal.Copy(encoded, 0, marshalled.encoded, encoded.Length); // Codec will allocate output buffer - if (IntPtr.Size == 8) - DotNetDecode64(ref marshalled); - else - DotNetDecode(ref marshalled); + DotNetDecode(ref marshalled); int n = marshalled.width * marshalled.height; @@ -349,19 +310,13 @@ public static bool DecodeToImage(byte[] encoded, out ManagedImage managedImage) Logger.Log("Decoded image with unhandled number of components: " + marshalled.components, Helpers.LogLevel.Error); - if (IntPtr.Size == 8) - DotNetFree64(ref marshalled); - else - DotNetFree(ref marshalled); + DotNetFree(ref marshalled); managedImage = null; return false; } - if (IntPtr.Size == 8) - DotNetFree64(ref marshalled); - else - DotNetFree(ref marshalled); + DotNetFree(ref marshalled); } return true; @@ -386,15 +341,12 @@ public static bool DecodeLayerBoundaries(byte[] encoded, out J2KLayerInfo[] laye lock (OpenJPEGLock) { - if (IntPtr.Size == 8) - DotNetAllocEncoded64(ref marshalled); - else - DotNetAllocEncoded(ref marshalled); + DotNetAllocEncoded(ref marshalled); Marshal.Copy(encoded, 0, marshalled.encoded, encoded.Length); // Run the decode - bool decodeSuccess = (IntPtr.Size == 8) ? DotNetDecodeWithInfo64(ref marshalled) : DotNetDecodeWithInfo(ref marshalled); + bool decodeSuccess = DotNetDecodeWithInfo(ref marshalled); if (decodeSuccess) { components = marshalled.components; @@ -499,10 +451,7 @@ public static bool DecodeLayerBoundaries(byte[] encoded, out J2KLayerInfo[] laye } } - if (IntPtr.Size == 8) - DotNetFree64(ref marshalled); - else - DotNetFree(ref marshalled); + DotNetFree(ref marshalled); } return success; @@ -585,5 +534,4 @@ public unsafe static byte[] EncodeFromImage(Bitmap bitmap, bool lossless) return encoded; } } -#endif } diff --git a/OpenMetaverse/Imaging/TGALoader.cs b/OpenMetaverse/Imaging/TGALoader.cs index c6c39839..111e369a 100644 --- a/OpenMetaverse/Imaging/TGALoader.cs +++ b/OpenMetaverse/Imaging/TGALoader.cs @@ -30,8 +30,6 @@ namespace OpenMetaverse.Imaging { -#if !NO_UNSAFE - /// /// Capability to load TGAs to Bitmap /// @@ -635,6 +633,4 @@ public static System.Drawing.Bitmap LoadTGA(string filename) } } } - -#endif } diff --git a/OpenMetaverse/Login.cs b/OpenMetaverse/Login.cs index 43d33fb3..93de96bc 100644 --- a/OpenMetaverse/Login.cs +++ b/OpenMetaverse/Login.cs @@ -24,15 +24,19 @@ * POSSIBILITY OF SUCH DAMAGE. */ -using Nwc.XmlRpc; -using OpenMetaverse.Http; -using OpenMetaverse.Packets; -using OpenMetaverse.StructuredData; using System; using System.Collections; using System.Collections.Generic; using System.Net; +using System.Net.Security; +using System.Security.Cryptography.X509Certificates; +using OpenMetaverse.StructuredData; +using OpenMetaverse.Http; +using OpenMetaverse.Packets; using System.Threading; +using XmlRpcCore; +using System.Threading.Tasks; +using System.Net.Http; namespace OpenMetaverse { @@ -149,23 +153,25 @@ public class LoginParams /// public LoginParams() { - List options = new List(16); - options.Add("inventory-root"); - options.Add("inventory-skeleton"); - options.Add("inventory-lib-root"); - options.Add("inventory-lib-owner"); - options.Add("inventory-skel-lib"); - options.Add("initial-outfit"); - options.Add("gestures"); - options.Add("event_categories"); - options.Add("event_notifications"); - options.Add("classified_categories"); - options.Add("buddy-list"); - options.Add("ui-config"); - options.Add("tutorial_settings"); - options.Add("login-flags"); - options.Add("global-textures"); - options.Add("adult_compliant"); + var options = new List(16) + { + "inventory-root", + "inventory-skeleton", + "inventory-lib-root", + "inventory-lib-owner", + "inventory-skel-lib", + "initial-outfit", + "gestures", + "event_categories", + "event_notifications", + "classified_categories", + "buddy-list", + "ui-config", + "tutorial_settings", + "login-flags", + "global-textures", + "adult_compliant" + }; this.Options = options.ToArray(); this.MethodName = "login_to_simulator"; @@ -899,6 +905,13 @@ public event EventHandler LoginProgress #endregion #region Private Members + + public static readonly HttpClient HTTP_CLIENT = new HttpClient(new HttpClientHandler() + { + ServerCertificateCustomValidationCallback = delegate { return true; }, + AllowAutoRedirect = true + }); + private LoginParams CurrentContext = null; private AutoResetEvent LoginEvent = new AutoResetEvent(false); private LoginStatus InternalStatusCode = LoginStatus.None; @@ -1060,6 +1073,23 @@ public void AbortLogin() #endregion #region Private Methods + public static bool ValidateServerCertificate( + object sender, + X509Certificate certificate, + X509Chain chain, + SslPolicyErrors sslPolicyErrors) + { + //if (m_NoVerifyCertChain) + sslPolicyErrors &= ~SslPolicyErrors.RemoteCertificateChainErrors; + + //if (m_NoVerifyCertHostname) + sslPolicyErrors &= ~SslPolicyErrors.RemoteCertificateNameMismatch; + + if (sslPolicyErrors == SslPolicyErrors.None) + return true; + + return false; + } private void BeginLogin() { @@ -1109,7 +1139,7 @@ private void BeginLogin() #endregion - ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true; + ServicePointManager.ServerCertificateValidationCallback = ValidateServerCertificate; if (Client.Settings.USE_LLSD_LOGIN) { @@ -1176,64 +1206,69 @@ private void BeginLogin() #region XML-RPC Based Login Code // Create the Hashtable for XmlRpcCs - Hashtable loginXmlRpc = new Hashtable(); - loginXmlRpc["first"] = loginParams.FirstName; - loginXmlRpc["last"] = loginParams.LastName; - loginXmlRpc["passwd"] = loginParams.Password; - loginXmlRpc["start"] = loginParams.Start; - loginXmlRpc["channel"] = loginParams.Channel; - loginXmlRpc["version"] = loginParams.Version; - loginXmlRpc["platform"] = loginParams.Platform; - loginXmlRpc["platform_version"] = loginParams.PlatformVersion; - loginXmlRpc["mac"] = loginParams.MAC; - if (loginParams.AgreeToTos) - loginXmlRpc["agree_to_tos"] = "true"; - if (loginParams.ReadCritical) - loginXmlRpc["read_critical"] = "true"; - loginXmlRpc["id0"] = loginParams.ID0; - loginXmlRpc["last_exec_event"] = (int)loginParams.LastExecEvent; + var loginXmlRpc = new Hashtable + { + ["first"] = loginParams.FirstName, + ["last"] = loginParams.LastName, + ["passwd"] = loginParams.Password, + ["start"] = loginParams.Start, + ["channel"] = loginParams.Channel, + ["version"] = loginParams.Version, + ["platform"] = loginParams.Platform, + ["platform_version"] = loginParams.PlatformVersion, + ["mac"] = loginParams.MAC, + ["id0"] = loginParams.ID0, + ["last_exec_event"] = (int)loginParams.LastExecEvent + }; + if (loginParams.AgreeToTos) { loginXmlRpc["agree_to_tos"] = "true"; } + if (loginParams.ReadCritical) { loginXmlRpc["read_critical"] = "true"; } + //if (loginParams.MfaEnabled) + //{ + // loginXmlRpc["token"] = loginParams.Token; + // loginXmlRpc["mfa_hash"] = loginParams.MfaHash; + //} // Create the options array ArrayList options = new ArrayList(); for (int i = 0; i < loginParams.Options.Length; i++) + { options.Add(loginParams.Options[i]); - - foreach (string[] callbackOpts in CallbackOptions.Values) + } + foreach (var callbackOpts in CallbackOptions.Values) { - if (callbackOpts != null) + if (callbackOpts == null) continue; + foreach (var t in callbackOpts) { - for (int i = 0; i < callbackOpts.Length; i++) - { - if (!options.Contains(callbackOpts[i])) - options.Add(callbackOpts[i]); - } + if (!options.Contains(t)) + options.Add(t); } } loginXmlRpc["options"] = options; try { - ArrayList loginArray = new ArrayList(1); - loginArray.Add(loginXmlRpc); - XmlRpcRequest request = new XmlRpcRequest(CurrentContext.MethodName, loginArray); + var loginArray = new ArrayList(1) { loginXmlRpc }; + var request = new XmlRpcRequest(CurrentContext.MethodName, loginArray); var cc = CurrentContext; + // Start the request - Thread requestThread = new Thread( - delegate () + Task.Run(async () => + { + try { - try - { - LoginReplyXmlRpcHandler( - request.Send(cc.URI, cc.Timeout), - loginParams); - } - catch (Exception e) - { - UpdateLoginStatus(LoginStatus.Failed, "Error opening the login server connection: " + e.Message); - } - }); - requestThread.Name = "XML-RPC Login"; - requestThread.Start(); + var cts = new CancellationTokenSource(); + cts.CancelAfter(cc.Timeout); + var loginResponse = await HTTP_CLIENT.PostAsXmlRpcAsync(cc.URI, request, cts.Token); + cts.Dispose(); + + LoginReplyXmlRpcHandler(loginResponse, loginParams); + } + catch (Exception e) + { + UpdateLoginStatus(LoginStatus.Failed, + $"Error opening the login server connection: {e.Message}"); + } + }); } catch (Exception e) { diff --git a/OpenMetaverse/Messages/LindenMessages.cs b/OpenMetaverse/Messages/LindenMessages.cs index 9664478e..9f26d1f5 100644 --- a/OpenMetaverse/Messages/LindenMessages.cs +++ b/OpenMetaverse/Messages/LindenMessages.cs @@ -24,13 +24,13 @@ * POSSIBILITY OF SUCH DAMAGE. */ -using ComponentAce.Compression.Libs.zlib; using OpenMetaverse.Interfaces; using OpenMetaverse.StructuredData; using System; using System.Collections.Generic; using System.IO; using System.Net; +using ComponentAce.Compression.Libs.zlib; namespace OpenMetaverse.Messages.Linden { @@ -1813,6 +1813,76 @@ public OSDMap Serialize() } + public class LargeGenericMessage : IMessage + { + private OSDMap RawData; + public UUID AgentID; + public UUID SessionID; + public UUID TransactionID; + + public string Method; + public UUID Invoice; + + public class Parameter + { + public string value; + } + + public Parameter[] Parameters; + + public void Deserialize(OSDMap map) + { + RawData = map; + OSD osdtmp, osdtmp2; + if (map.TryGetValue("AgentData", out osdtmp)) + { + if (osdtmp is OSDArray agdArray && agdArray.Count > 0) + { + if (agdArray[0] is OSDMap agdMap) + { + if (agdMap.TryGetValue("AgentID", out osdtmp2)) + AgentID = osdtmp2.AsUUID(); + if (agdMap.TryGetValue("SessionID", out osdtmp2)) + SessionID = osdtmp2.AsUUID(); + if (agdMap.TryGetValue("TransactionID", out osdtmp2)) + TransactionID = osdtmp2.AsUUID(); + } + } + } + if (map.TryGetValue("MethodData", out osdtmp)) + { + if (osdtmp is OSDArray mdArray && mdArray.Count > 0) + { + if (mdArray[0] is OSDMap mdMap) + { + if (mdMap.TryGetValue("Method", out osdtmp2)) + Method = osdtmp2.AsString(); + if (mdMap.TryGetValue("Invoice", out osdtmp2)) + Invoice = osdtmp2.AsUUID(); + } + } + } + if (map.TryGetValue("ParamList", out osdtmp)) + { + if (osdtmp is OSDArray pArray && pArray.Count > 0) + { + Parameters = new Parameter[pArray.Count]; + for(int i = 0; i < Parameters.Length; i++) + { + Parameters[i] = new Parameter(){value = pArray[i].ToString() }; + } + } + } + + Method ??="MissingMethod"; + } + + public OSDMap Serialize() + { + return RawData; + } + } + /// Base class for Asset uploads/results via Capabilities public abstract class AssetUploaderBlock { diff --git a/OpenMetaverse/Messages/MessageEventDecoder.cs b/OpenMetaverse/Messages/MessageEventDecoder.cs index 063b899c..cb9321ab 100644 --- a/OpenMetaverse/Messages/MessageEventDecoder.cs +++ b/OpenMetaverse/Messages/MessageEventDecoder.cs @@ -101,6 +101,7 @@ public static IMessage DecodeEvent(string eventName, OSDMap map) case "BulkUpdateInventory": message = new BulkUpdateInventoryMessage(); break; case "RenderMaterials": message = new RenderMaterialsMessage(); break; case "GetObjectCost": message = GetObjectCostMessage.GetMessageHandler(map); break; + case "LargeGenericMessage": message = new LargeGenericMessage(); break; // Capabilities TODO: // DispatchRegionInfo diff --git a/OpenMetaverse/OpenMetaverse.csproj b/OpenMetaverse/OpenMetaverse.csproj index ce8212b5..755cb050 100644 --- a/OpenMetaverse/OpenMetaverse.csproj +++ b/OpenMetaverse/OpenMetaverse.csproj @@ -1,33 +1,29 @@  Local - net48;netstandard2.0;netstandard2.1 + net6.0 OpenMetaverse 1591,1574,0419,0618 True true + Utopia Skye LLC, OpenMetaverse Developers + OMV OpenMetaverse OpenSim OpenSim-NGC OpenMetaverseFoundation VirtualWorld VirtualReality 3D SecondLife - + + + ..\bin\SmartThreadPool.dll False - - ..\bin\XMLRPC.dll - False - - - ..\bin\zlib.net.dll - False - - \ No newline at end of file + diff --git a/OpenMetaverse/PacketDecoder.cs b/OpenMetaverse/PacketDecoder.cs index 87f4ec89..0ad11faa 100644 --- a/OpenMetaverse/PacketDecoder.cs +++ b/OpenMetaverse/PacketDecoder.cs @@ -1,1926 +1,1949 @@ -/* - * Copyright (c) 2006-2016, openmetaverse.co - * All rights reserved. - * - * - Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - Neither the name of the openmetaverse.co nor the names - * of its contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.Reflection; -using System.Text; - -namespace OpenMetaverse.Packets -{ - - public static class PacketDecoder - { - /// - /// A custom decoder callback - /// - /// The key of the object - /// the data to decode - /// A string represending the fieldData - public delegate string CustomPacketDecoder(string fieldName, object fieldData); - - private static Dictionary> Callbacks = new Dictionary>(); - - - static PacketDecoder() - { - AddCallback("Color", DecodeColorField); - AddCallback("TextColor", DecodeColorField); - AddCallback("Timestamp", DecodeTimeStamp); - AddCallback("EstateCovenantReply.Data.CovenantTimestamp", DecodeTimeStamp); - AddCallback("CreationDate", DecodeTimeStamp); - AddCallback("BinaryBucket", DecodeBinaryBucket); - AddCallback("ParcelData.Data", DecodeBinaryToHexString); - AddCallback("LayerData.Data", DecodeBinaryToHexString); - AddCallback("ImageData.Data", DecodeImageData); - AddCallback("TransferData.Data", DecodeBinaryToHexString); - AddCallback("ObjectData.TextureEntry", DecodeTextureEntry); - AddCallback("ImprovedInstantMessage.MessageBlock.Dialog", DecodeDialog); - - // Inventory/Permissions - AddCallback("BaseMask", DecodePermissionMask); - AddCallback("OwnerMask", DecodePermissionMask); - AddCallback("EveryoneMask", DecodePermissionMask); - AddCallback("NextOwnerMask", DecodePermissionMask); - AddCallback("GroupMask", DecodePermissionMask); - - // FetchInventoryDescendents - AddCallback("InventoryData.SortOrder", DecodeInventorySort); - - AddCallback("WearableType", DecodeWearableType); - // - AddCallback("InventoryData.Type", DecodeInventoryType); - AddCallback("InvType", DecodeInventoryInvType); - AddCallback("InventoryData.Flags", DecodeInventoryFlags); - // BulkUpdateInventory - AddCallback("ItemData.Type", DecodeInventoryType); - AddCallback("ItemData.Flags", DecodeInventoryFlags); - - AddCallback("SaleType", DecodeObjectSaleType); - - AddCallback("ScriptControlChange.Data.Controls", DecodeScriptControls); - - AddCallback("RegionFlags", DecodeRegionFlags); - AddCallback("SimAccess", DecodeSimAccess); - AddCallback("ControlFlags", DecodeControlFlags); - - // AgentUpdate - AddCallback("AgentUpdate.AgentData.State", DecodeAgentState); - AddCallback("AgentUpdate.AgentData.Flags", DecodeAgentFlags); - - // ViewerEffect TypeData - AddCallback("ViewerEffect.Effect.TypeData", DecodeViewerEffectTypeData); - AddCallback("ViewerEffect.Effect.Type", DecodeViewerEffectType); - - // Prim/ObjectUpdate decoders - AddCallback("ObjectUpdate.ObjectData.PCode", DecodeObjectPCode); - AddCallback("ObjectUpdate.ObjectData.Material", DecodeObjectMaterial); - AddCallback("ObjectUpdate.ObjectData.ClickAction", DecodeObjectClickAction); - AddCallback("ObjectData.UpdateFlags", DecodeObjectUpdateFlags); - - AddCallback("ObjectUpdate.ObjectData.ObjectData", DecodeObjectData); - AddCallback("TextureAnim", DecodeObjectTextureAnim); - AddCallback("ObjectUpdate.ObjectData.NameValue", DecodeNameValue); - AddCallback("ObjectUpdate.ObjectData.Data", DecodeObjectData); - - AddCallback("ObjectUpdate.ObjectData.PSBlock", DecodeObjectParticleSystem); - AddCallback("ParticleSys", DecodeObjectParticleSystem); - AddCallback("ObjectUpdate.ObjectData.ExtraParams", DecodeObjectExtraParams); - - AddCallback("ImprovedTerseObjectUpdate.ObjectData.Data", DecodeTerseUpdate); - AddCallback("ImprovedTerseObjectUpdate.ObjectData.TextureEntry", DecodeTerseTextureEntry); - - AddCallback("ObjectUpdateCompressed.ObjectData.Data", DecodeObjectCompressedData); - - // ImprovedTerseObjectUpdate & ObjectUpdate AttachmentPoint & ObjectUpdateCompressed - AddCallback("ObjectData.State", DecodeObjectState); - //AddCallback("ObjectUpdateCompressed.ObjectData.State", DecodeObjectState); - //AddCallback("ImprovedTerseObjectUpdate.ObjectData.State", DecodeObjectState); - - - // ChatFromSimulator - AddCallback("ChatData.SourceType", DecodeChatSourceType); - AddCallback("ChatData.ChatType", DecodeChatChatType); - AddCallback("ChatData.Audible", DecodeChatAudible); - AddCallback("AttachedSound.DataBlock.Flags", DecodeAttachedSoundFlags); - - AddCallback("RequestImage.Type", DecodeImageType); - - AddCallback("EstateOwnerMessage.ParamList.Parameter", DecodeEstateParameter); - - AddCallback("Codec", DecodeImageCodec); - AddCallback("Info.TeleportFlags", DecodeTeleportFlags); - - // map - AddCallback("MapBlockRequest.AgentData.Flags", DecodeMapRequestFlags); - AddCallback("MapItemRequest.AgentData.Flags", DecodeMapRequestFlags); - AddCallback("MapBlockReply.Data.Access", DecodeMapAccess); - AddCallback("FolderData.Type", DecodeFolderType); - AddCallback("RequestData.ItemType", DecodeGridItemType); - - // TransferRequest/TransferInfo - AddCallback("TransferInfo.Params", DecodeTransferParams); - AddCallback("TransferInfo.ChannelType", DecodeTransferChannelType); - AddCallback("TransferInfo.SourceType", DecodeTransferSourceType); - AddCallback("TransferInfo.TargetType", DecodeTransferTargetType); - AddCallback("TransferData.ChannelType", DecodeTransferChannelType); - // SendXferPacket - AddCallback("DataPacket.Data", DecodeBinaryToHexString); - // Directory Manager - AddCallback("DirClassifiedQuery.QueryData.QueryFlags", DecodeDirClassifiedQueryFlags); - AddCallback("QueryData.QueryFlags", DecodeDirQueryFlags); - AddCallback("Category", DecodeCategory); - AddCallback("QueryData.SearchType", SearchTypeFlags); - - AddCallback("ClassifiedFlags", DecodeDirClassifiedFlags); - AddCallback("EventFlags", DecodeEventFlags); - - AddCallback("ParcelAccessListRequest.Data.Flags", DecodeParcelACL); - AddCallback("ParcelAccessListReply.Data.Flags", DecodeParcelACL); - //AddCallback("ParcelAccessListReply.List.Flags", DecodeParcelACLReply); - - // AgentAnimation - AddCallback("AnimID", DecodeAnimToConst); - - AddCallback("LayerData.LayerID.Type", DecodeLayerDataType); - - AddCallback("GroupPowers", DecodeGroupPowers); - } - - /// - /// Add a custom decoder callback - /// - /// The key of the field to decode - /// The custom decode handler - public static void AddCallback(string key, CustomPacketDecoder customPacketHandler) - { - if (Callbacks.ContainsKey(key)) - { - lock (Callbacks) - Callbacks[key].Add(customPacketHandler); - } - else - { - lock (Callbacks) - Callbacks.Add(key, new List() { customPacketHandler }); - } - } - - /// - /// Remove a custom decoder callback - /// - /// The key of the field to decode - /// The custom decode handler - public static void RemoveCustomHandler(string key, CustomPacketDecoder customPacketHandler) - { - if (Callbacks.ContainsKey(key)) - lock (Callbacks) - { - if (Callbacks[key].Contains(customPacketHandler)) - Callbacks[key].Remove(customPacketHandler); - } - } - - #region Custom Decoders - - private static string DecodeTerseUpdate(string fieldName, object fieldData) - { - byte[] block = (byte[])fieldData; - int i = 4; - - StringBuilder result = new StringBuilder(); - - // LocalID - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "LocalID", - Utils.BytesToUInt(block, 0), - "Uint32"); - - - - // State - byte point = block[i++]; - result.AppendFormat("{0,30}: {1,-3} {2,-36} [{3}]" + Environment.NewLine, - "State", - point, - "(" + (AttachmentPoint)point + ")", - "AttachmentPoint"); - - // Avatar boolean - bool isAvatar = (block[i++] != 0); - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "IsAvatar", - isAvatar, - "Boolean"); - - // Collision normal for avatar - if (isAvatar) - { - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "CollisionPlane", - new Vector4(block, i), - "Vector4"); - - i += 16; - } - - // Position - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "Position", - new Vector3(block, i), - "Vector3"); - i += 12; - - // Velocity - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "Velocity", - new Vector3( - Utils.BytesUInt16ToFloat(block, i, -128.0f, 128.0f), - Utils.BytesUInt16ToFloat(block, i + 2, -128.0f, 128.0f), - Utils.BytesUInt16ToFloat(block, i + 4, -128.0f, 128.0f)), - "Vector3"); - i += 6; - - // Acceleration - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "Acceleration", - new Vector3( - Utils.BytesUInt16ToFloat(block, i, -64.0f, 64.0f), - Utils.BytesUInt16ToFloat(block, i + 2, -64.0f, 64.0f), - Utils.BytesUInt16ToFloat(block, i + 4, -64.0f, 64.0f)), - "Vector3"); - - i += 6; - // Rotation (theta) - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "Rotation", - new Quaternion( - Utils.BytesUInt16ToFloat(block, i, -1.0f, 1.0f), - Utils.BytesUInt16ToFloat(block, i + 2, -1.0f, 1.0f), - Utils.BytesUInt16ToFloat(block, i + 4, -1.0f, 1.0f), - Utils.BytesUInt16ToFloat(block, i + 6, -1.0f, 1.0f)), - "Quaternion"); - i += 8; - // Angular velocity (omega) - result.AppendFormat("{0,30}: {1,-40} [{2}]", - "AngularVelocity", - new Vector3( - Utils.BytesUInt16ToFloat(block, i, -64.0f, 64.0f), - Utils.BytesUInt16ToFloat(block, i + 2, -64.0f, 64.0f), - Utils.BytesUInt16ToFloat(block, i + 4, -64.0f, 64.0f)), - "Vector3"); - //pos += 6; - // TODO: What is in these 6 bytes? - return result.ToString(); - } - - private static string DecodeObjectCompressedData(string fieldName, object fieldData) - { - StringBuilder result = new StringBuilder(); - byte[] block = (byte[])fieldData; - int i = 0; - - // UUID - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "ID", - new UUID(block, 0), - "UUID"); - i += 16; - - // Local ID - uint LocalID = (uint)(block[i++] + (block[i++] << 8) + - (block[i++] << 16) + (block[i++] << 24)); - - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "LocalID", - LocalID, - "Uint32"); - // PCode - PCode pcode = (PCode)block[i++]; - - result.AppendFormat("{0,30}: {1,-3} {2,-36} [{3}]" + Environment.NewLine, - "PCode", - (int)pcode, - "(" + pcode + ")", - "PCode"); - - // State - AttachmentPoint point = (AttachmentPoint)block[i++]; - result.AppendFormat("{0,30}: {1,-3} {2,-36} [{3}]" + Environment.NewLine, - "State", - (byte)point, - "(" + point + ")", - "AttachmentPoint"); - - //CRC - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "CRC", - Utils.BytesToUInt(block, i), - "UInt"); - i += 4; - - // Material - result.AppendFormat("{0,30}: {1,-3} {2,-36} [{3}]" + Environment.NewLine, - "Material", - block[i], - "(" + (Material)block[i++] + ")", - "Material"); - - // Click action - result.AppendFormat("{0,30}: {1,-3} {2,-36} [{3}]" + Environment.NewLine, - "ClickAction", - block[i], - "(" + (ClickAction)block[i++] + ")", - "ClickAction"); - - // Scale - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "Scale", - new Vector3(block, i), - "Vector3"); - i += 12; - - // Position - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "Position", - new Vector3(block, i), - "Vector3"); - i += 12; - - // Rotation - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "Rotation", - new Vector3(block, i), - "Vector3"); - - i += 12; - // Compressed flags - - CompressedFlags flags = (CompressedFlags)Utils.BytesToUInt(block, i); - result.AppendFormat("{0,30}: {1,-10} {2,-29} [{3}]" + Environment.NewLine, - "CompressedFlags", - Utils.BytesToUInt(block, i), - "(" + (CompressedFlags)Utils.BytesToUInt(block, i) + ")", - "UInt"); - i += 4; - - // Owners ID - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "OwnerID", - new UUID(block, i), - "UUID"); - i += 16; - - // Angular velocity - if ((flags & CompressedFlags.HasAngularVelocity) != 0) - { - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "AngularVelocity", - new Vector3(block, i), - "Vector3"); - i += 12; - } - - // Parent ID - if ((flags & CompressedFlags.HasParent) != 0) - { - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "ParentID", - (uint)(block[i++] + (block[i++] << 8) + - (block[i++] << 16) + (block[i++] << 24)), - "UInt"); - } - - // Tree data - if ((flags & CompressedFlags.Tree) != 0) - { - result.AppendFormat("{0,30}: {1,-2} {2,-37} [{3}]" + Environment.NewLine, - "TreeSpecies", - block[i++], - "(" + (Tree)block[i] + ")", - "Tree"); - } - - // Scratch pad - else if ((flags & CompressedFlags.ScratchPad) != 0) - { - int size = block[i++]; - byte[] scratch = new byte[size]; - Buffer.BlockCopy(block, i, scratch, 0, size); - result.AppendFormat("{0,30}: {1,-40} [ScratchPad[]]" + Environment.NewLine, - "ScratchPad", - Utils.BytesToHexString(scratch, String.Format("{0,30}", "Data"))); - i += size; - } - - // Floating text - if ((flags & CompressedFlags.HasText) != 0) - { - string text = String.Empty; - while (block[i] != 0) - { - text += (char)block[i]; - i++; - } - i++; - - // Floating text - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "Text", - text, - "string"); - - // Text color - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "TextColor", - new Color4(block, i, false), - "Color4"); - i += 4; - } - - // Media URL - if ((flags & CompressedFlags.MediaURL) != 0) - { - string text = String.Empty; - while (block[i] != 0) - { - text += (char)block[i]; - i++; - } - i++; - - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "MediaURL", - text, - "string"); - } - - // Particle system - if ((flags & CompressedFlags.HasParticles) != 0) - { - Primitive.ParticleSystem p = new Primitive.ParticleSystem(block, i); - result.AppendLine(DecodeObjectParticleSystem("ParticleSystem", p)); - i += 86; - } - - // Extra parameters TODO: - Primitive prim = new Primitive(); - int extrapLen = prim.SetExtraParamsFromBytes(block, i); - i += extrapLen; - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "ExtraParams[]", - extrapLen, - "byte[]"); - - //Sound data - if ((flags & CompressedFlags.HasSound) != 0) - { - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "SoundID", - new UUID(block, i), - "UUID"); - i += 16; - - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "SoundGain", - Utils.BytesToFloat(block, i), - "Float"); - i += 4; - - result.AppendFormat("{0,30}: {1,-2} {2,-37} [{3}]" + Environment.NewLine, - "SoundFlags", - block[i++], - "(" + (SoundFlags)block[i] + ")", - "SoundFlags"); - - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "SoundRadius", - Utils.BytesToFloat(block, i), - "Float"); - i += 4; - } - - // Name values - if ((flags & CompressedFlags.HasNameValues) != 0) - { - string text = String.Empty; - while (block[i] != 0) - { - text += (char)block[i]; - i++; - } - i++; - - // Parse the name values - if (text.Length > 0) - { - string[] lines = text.Split('\n'); - NameValue[] nameValues = new NameValue[lines.Length]; - - for (int j = 0; j < lines.Length; j++) - { - if (!String.IsNullOrEmpty(lines[j])) - { - NameValue nv = new NameValue(lines[j]); - nameValues[j] = nv; - } - } - result.AppendLine(DecodeNameValue("NameValues", nameValues)); - } - } - - result.AppendFormat("{0,30}: {1,-2} {2,-37} [{3}]" + Environment.NewLine, - "PathCurve", - block[i], - "(" + (PathCurve)block[i++] + ")", - "PathCurve"); - - ushort pathBegin = Utils.BytesToUInt16(block, i); - i += 2; - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "PathBegin", - Primitive.UnpackBeginCut(pathBegin), - "float"); - - ushort pathEnd = Utils.BytesToUInt16(block, i); - i += 2; - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "PathEnd", - Primitive.UnpackEndCut(pathEnd), - "float"); - - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "PathScaleX", - Primitive.UnpackPathScale(block[i++]), - "float"); - - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "PathScaleY", - Primitive.UnpackPathScale(block[i++]), - "float"); - - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "PathShearX", - Primitive.UnpackPathShear((sbyte)block[i++]), - "float"); - - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "PathShearY", - Primitive.UnpackPathShear((sbyte)block[i++]), - "float"); - - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "PathTwist", - Primitive.UnpackPathTwist((sbyte)block[i++]), - "float"); - - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "PathTwistBegin", - Primitive.UnpackPathTwist((sbyte)block[i++]), - "float"); - - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "PathRadiusOffset", - Primitive.UnpackPathTwist((sbyte)block[i++]), - "float"); - - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "PathTaperX", - Primitive.UnpackPathTaper((sbyte)block[i++]), - "float"); - - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "PathTaperY", - Primitive.UnpackPathTaper((sbyte)block[i++]), - "float"); - - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "PathRevolutions", - Primitive.UnpackPathRevolutions(block[i++]), - "float"); - - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "PathSkew", - Primitive.UnpackPathTwist((sbyte)block[i++]), - "float"); - - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "ProfileCurve", - block[i++], - "float"); - - ushort profileBegin = Utils.BytesToUInt16(block, i); - i += 2; - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "ProfileBegin", - Primitive.UnpackBeginCut(profileBegin), - "float"); - - ushort profileEnd = Utils.BytesToUInt16(block, i); - i += 2; - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "ProfileEnd", - Primitive.UnpackEndCut(profileEnd), - "float"); - - ushort profileHollow = Utils.BytesToUInt16(block, i); - i += 2; - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "ProfileHollow", - Primitive.UnpackProfileHollow(profileHollow), - "float"); - - int textureEntryLength = (int)Utils.BytesToUInt(block, i); - i += 4; - //prim.Textures = new Primitive.TextureEntry(block, i, textureEntryLength); - String s = DecodeTextureEntry("TextureEntry", new Primitive.TextureEntry(block, i, textureEntryLength)); - result.AppendLine(s); - i += textureEntryLength; - - // Texture animation - if ((flags & CompressedFlags.TextureAnimation) != 0) - { - i += 4; - string a = DecodeObjectTextureAnim("TextureAnimation", new Primitive.TextureAnimation(block, i)); - result.AppendLine(a); - } - - if ((flags & CompressedFlags.HasParticlesNew) != 0) - { - Primitive.ParticleSystem p = new Primitive.ParticleSystem(block, i); - result.AppendLine(DecodeObjectParticleSystem("ParticleSystemNEW", p)); - i += 94; - if ((p.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.DataGlow) != 0) - i += 2; - if ((p.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.DataBlend) != 0) - i += 2; - } - - return result.ToString(); - } - - private static string DecodeObjectData(string fieldName, object fieldData) - { - byte[] data = (byte[])fieldData; - if (data.Length == 1) - { - return String.Format("{0,30}: {1,2} {2,-38} [{3}]", - fieldName + " (Tree Species)", - fieldData, - //"(" + (Tree)(byte)fieldData + ")", - "(" + (Tree)data[0] + ")", - fieldData.GetType().Name); - } - else if (data.Length == 76) - { - /* TODO: these are likely useful packed fields, - * need to unpack them */ - Vector4 col = Vector4.Zero; - Vector3 offset = Vector3.Zero; - Vector3 vel = Vector3.Zero; - Vector3 acc = Vector3.Zero; - Quaternion q = Quaternion.Identity; - Vector3 angvel = Vector3.Zero; - - col.FromBytes(data, 0); - offset.FromBytes(data, 16); - vel.FromBytes(data, 28); - acc.FromBytes(data, 40); - q.FromBytes(data, 52, true); - angvel.FromBytes(data, 64); - - StringBuilder result = new StringBuilder(); - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "ColisionPlane", - col, - "Vector4"); - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "Offset", - offset, - "Vector3"); - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "Velocity", - vel, - "Vector3"); - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "Acceleration", - acc, - "Vector3"); - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "rotation", - q, - "Quaternion"); - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "Omega", - angvel, - "Vector3"); - return result.ToString(); - } - else if (data.Length == 60) - { - /* TODO: these are likely useful packed fields, - * need to unpack them */ - Vector3 offset = Vector3.Zero; - Vector3 vel = Vector3.Zero; - Vector3 acc = Vector3.Zero; - Quaternion q = Quaternion.Identity; - Vector3 angvel = Vector3.Zero; - - offset.FromBytes(data, 0); - vel.FromBytes(data, 12); - acc.FromBytes(data, 24); - q.FromBytes(data, 36, true); - angvel.FromBytes(data, 48); - - StringBuilder result = new StringBuilder(); - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "Offset", - offset, - "Vector3"); - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "Velocity", - vel, - "Vector3"); - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "Acceleration", - acc, - "Vector3"); - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "rotation", - q, - "Quaternion"); - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - "Omega", - angvel, - "Vector3"); - return result.ToString(); - } - else - { - return Utils.BytesToHexString((byte[])fieldData, String.Format("{0,30}", fieldName)); - } - } - - private static string DecodeObjectTextureAnim(string fieldName, object fieldData) - { - StringBuilder result = new StringBuilder(); - Primitive.TextureAnimation TextureAnim; - if (fieldData is Primitive.TextureAnimation) - TextureAnim = (Primitive.TextureAnimation)fieldData; - else - TextureAnim = new Primitive.TextureAnimation((byte[])fieldData, 0); - - result.AppendFormat("{0,30}", " " + Environment.NewLine); - GenericTypeDecoder(TextureAnim, ref result); - result.AppendFormat("{0,30}", ""); - - return result.ToString(); - } - - private static string DecodeEstateParameter(string fieldName, object fieldData) - { - byte[] bytes = (byte[])fieldData; - - if (bytes.Length == 17) - { - return String.Format("{0,30}: {1,-40} [UUID]", fieldName, new UUID((byte[])fieldData, 0)); - } - else - { - return String.Format("{0,30}: {1,-40} [Byte[]]", fieldName, Utils.BytesToString((byte[])fieldData)); - } - } - - private static string DecodeNameValue(string fieldName, object fieldData) - { - NameValue[] nameValues = null; - if (fieldData is NameValue[]) - nameValues = fieldData as NameValue[]; - else - { - string nameValue = Utils.BytesToString((byte[])fieldData); - if (nameValue.Length > 0) - { - string[] lines = nameValue.Split('\n'); - nameValues = new NameValue[lines.Length]; - - for (int i = 0; i < lines.Length; i++) - { - if (!String.IsNullOrEmpty(lines[i])) - { - NameValue nv = new NameValue(lines[i]); - nameValues[i] = nv; - } - } - } - } - StringBuilder result = new StringBuilder(); - result.AppendFormat("{0,30}", " " + Environment.NewLine); - if (nameValues != null) - { - for (int i = 0; i < nameValues.Length; i++) - { - result.AppendFormat( - "{0,30}: Name={1} Value={2} Class={3} Type={4} Sendto={5}" + Environment.NewLine, "NameValue", - nameValues[i].Name, nameValues[i].Value, nameValues[i].Class, nameValues[i].Type, nameValues[i].Sendto); - } - } - result.AppendFormat("{0,30}", ""); - return result.ToString(); - } - - private static string DecodeObjectExtraParams(string fieldName, object fieldData) - { - - byte[] data = (byte[])fieldData; - - int i = 0; - //int totalLength = 1; - - Primitive.FlexibleData Flexible = null; - Primitive.LightData Light = null; - Primitive.SculptData Sculpt = null; - Primitive.SculptData Mesh = null; - uint meshFlags = 0; - bool hasmeshFlags = false; - - byte extraParamCount = data[i++]; - - for (int k = 0; k < extraParamCount; k++) - { - ExtraParamType type = (ExtraParamType)Utils.BytesToUInt16(data, i); - i += 2; - - uint paramLength = Utils.BytesToUInt(data, i); - i += 4; - - if (type == ExtraParamType.Flexible) - Flexible = new Primitive.FlexibleData(data, i); - else if (type == ExtraParamType.Light) - Light = new Primitive.LightData(data, i); - else if (type == ExtraParamType.Sculpt) - Sculpt = new Primitive.SculptData(data, i); - else if (type == ExtraParamType.Mesh) - Mesh = new Primitive.SculptData(data, i); - else if ((byte)type == 0x70) - { - hasmeshFlags = true; - meshFlags = Utils.BytesToUInt(data, i); - } - i += (int)paramLength; - //totalLength += (int)paramLength + 6; - } - - StringBuilder result = new StringBuilder(); - result.AppendFormat("{0,30}", "" + Environment.NewLine); - if (Flexible != null) - { - result.AppendFormat("{0,30}", "" + Environment.NewLine); - GenericTypeDecoder(Flexible, ref result); - result.AppendFormat("{0,30}", "" + Environment.NewLine); - } - - if (Sculpt != null) - { - result.AppendFormat("{0,30}", "" + Environment.NewLine); - GenericTypeDecoder(Sculpt, ref result); - result.AppendFormat("{0,30}", "" + Environment.NewLine); - } - - if (Mesh != null) - { - result.AppendFormat("{0,30}", "" + Environment.NewLine); - GenericTypeDecoder(Mesh, ref result); - result.AppendFormat("{0,30}", "" + Environment.NewLine); - } - - if (Light != null) - { - result.AppendFormat("{0,30}", "" + Environment.NewLine); - GenericTypeDecoder(Light, ref result); - result.AppendFormat("{0,30}", "" + Environment.NewLine); - } - - if (hasmeshFlags) - { - result.AppendFormat("{0,30}", "" + Environment.NewLine); - result.AppendFormat("{0,30}", meshFlags.ToString() + Environment.NewLine); - result.AppendFormat("{0,30}", "" + Environment.NewLine); - } - - result.AppendFormat("{0,30}", ""); - return result.ToString(); - } - - private static string DecodeObjectParticleSystem(string fieldName, object fieldData) - { - StringBuilder result = new StringBuilder(); - Primitive.ParticleSystem ParticleSys; - if (fieldData is Primitive.ParticleSystem) - ParticleSys = (Primitive.ParticleSystem)fieldData; - else - ParticleSys = new Primitive.ParticleSystem((byte[])fieldData, 0); - - result.AppendFormat("{0,30}", "" + Environment.NewLine); - GenericTypeDecoder(ParticleSys, ref result); - result.AppendFormat("{0,30}", ""); - - return result.ToString(); - } - - private static void GenericTypeDecoder(object obj, ref StringBuilder result) - { - FieldInfo[] fields = obj.GetType().GetFields(); - - foreach (FieldInfo field in fields) - { - String special; - if (SpecialDecoder("a" + "." + "b" + "." + field.Name, - field.GetValue(obj), out special)) - { - result.AppendLine(special); - } - else - { - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - field.Name, - field.GetValue(obj), - field.FieldType.Name); - } - } - } - - private static string DecodeObjectPCode(string fieldName, object fieldData) - { - return String.Format("{0,30}: {1,-3} {2,-36} [PCode]", - fieldName, - fieldData, - "(" + (PCode)(byte)fieldData + ")"); - } - - private static string DecodeImageType(string fieldName, object fieldData) - { - return String.Format("{0,30}: {1,-3} {2,-36} [ImageType]", - fieldName, - fieldData, - "(" + (ImageType)(byte)fieldData + ")"); - } - - private static string DecodeImageCodec(string fieldName, object fieldData) - { - return String.Format("{0,30}: {1,-3} {2,-36} [ImageCodec]", - fieldName, - fieldData, - "(" + (ImageCodec)(byte)fieldData + ")"); - } - - private static string DecodeObjectMaterial(string fieldName, object fieldData) - { - return String.Format("{0,30}: {1,-3} {2,-36} [Material]", - fieldName, - fieldData, - "(" + (Material)(byte)fieldData + ")"); - } - - private static string DecodeObjectClickAction(string fieldName, object fieldData) - { - return String.Format("{0,30}: {1,-3} {2,-36} [ClickAction]", - fieldName, - fieldData, - "(" + (ClickAction)(byte)fieldData + ")"); - } - - private static string DecodeEventFlags(string fieldName, object fieldData) - { - return String.Format("{0,30}: {1,-3} {2,-36} [EventFlags]", - fieldName, - fieldData, - "(" + (DirectoryManager.EventFlags)(uint)fieldData + ")"); - } - - private static string DecodeDirQueryFlags(string fieldName, object fieldData) - { - return String.Format("{0,30}: {1,-10} {2,-29} [DirectoryManager.DirFindFlags]", - fieldName, - fieldData, - "(" + (DirectoryManager.DirFindFlags)(uint)fieldData + ")"); - } - - private static string DecodeDirClassifiedQueryFlags(string fieldName, object fieldData) - { - return String.Format("{0,30}: {1,-10} {2,-29} [ClassifiedQueryFlags]", - fieldName, - fieldData, - "(" + (DirectoryManager.ClassifiedQueryFlags)(uint)fieldData + ")"); - } - - private static string DecodeDirClassifiedFlags(string fieldName, object fieldData) - { - return String.Format("{0,30}: {1,-10} {2,-29} [ClassifiedFlags]", - fieldName, - fieldData, - "(" + (DirectoryManager.ClassifiedFlags)(byte)fieldData + ")"); - } - - private static string DecodeGroupPowers(string fieldName, object fieldData) - { - return String.Format("{0,30}: {1,-20} {2,-19} [GroupPowers]", - fieldName, - fieldData, - "(" + (GroupPowers)(ulong)fieldData + ")"); - } - - private static string DecodeParcelACL(string fieldName, object fieldData) - { - return String.Format("{0,30}: {1,-10} {2,-29} [AccessList]", - fieldName, - fieldData, - "(" + (AccessList)(uint)fieldData + ")"); - } - - private static string SearchTypeFlags(string fieldName, object fieldData) - { - return String.Format("{0,30}: {1,-10} {2,-29} [DirectoryManager.SearchTypeFlags]", - fieldName, - fieldData, - "(" + (DirectoryManager.SearchTypeFlags)(uint)fieldData + ")"); - } - - private static string DecodeCategory(string fieldName, object fieldData) - { - return String.Format("{0,30}: {1,-3} {2,-36} [ParcelCategory]", - fieldName, - fieldData, - "(" + fieldData + ")"); - } - - private static string DecodeObjectUpdateFlags(string fieldName, object fieldData) - { - return String.Format("{0,30}: {1,-10} {2,-29} [PrimFlags]", - fieldName, - fieldData, - "(" + (PrimFlags)(uint)fieldData + ")"); - } - - private static string DecodeTeleportFlags(string fieldName, object fieldData) - { - return String.Format("{0,30}: {1,-10} {2,-29} [TeleportFlags]", - fieldName, - fieldData, - "(" + (TeleportFlags)(uint)fieldData + ")"); - } - - private static string DecodeScriptControls(string fieldName, object fieldData) - { - return String.Format("{0,30}: {1,-10} {2,-29} [AgentManager.ControlFlags]", - fieldName, - (uint)fieldData, - "(" + (AgentManager.ControlFlags)(uint)fieldData + ")"); - } - - private static string DecodeColorField(string fieldName, object fieldData) - { - return String.Format("{0,30}: {1,-40} [Color4]", - fieldName, - fieldData.GetType().Name.Equals("Color4") ? (Color4)fieldData : new Color4((byte[])fieldData, 0, false)); - } - - private static string DecodeTimeStamp(string fieldName, object fieldData) - { - if (fieldData is Int32 && (int)fieldData > 0) - return String.Format("{0,30}: {1,-10} {2,-29} [{3}]", - fieldName, - fieldData, - "(" + Utils.UnixTimeToDateTime((int)fieldData) + ")", - fieldData.GetType().Name); - else if (fieldData is uint && (uint)fieldData > 0) - return String.Format("{0,30}: {1,-10} {2,-29} [{3}]", - fieldName, - fieldData, - "(" + Utils.UnixTimeToDateTime((uint)fieldData) + ")", - fieldData.GetType().Name); - else - return String.Format("{0,30}: {1,-40} [{2}]", - fieldName, - fieldData, - fieldData.GetType().Name); - } - - private static string DecodeBinaryBucket(string fieldName, object fieldData) - { - byte[] bytes = (byte[])fieldData; - string bucket = String.Empty; - if (bytes.Length == 1) - { - bucket = String.Format("{0}", bytes[0]); - } - else if (bytes.Length == 17) - { - bucket = String.Format("{0,-36} {1} ({2})", - new UUID(bytes, 1), - bytes[0], - (AssetType)(sbyte)bytes[0]); - } - else if (bytes.Length == 16) // the folder ID for the asset to be stored into if we accept an inventory offer - { - bucket = new UUID(bytes, 0).ToString(); - } - else - { - bucket = Utils.BytesToString(bytes); // we'll try a string lastly - } - - return String.Format("{0,30}: {1,-40} [Byte[{2}]]", fieldName, bucket, bytes.Length); - } - - private static string DecodeBinaryToHexString(string fieldName, object fieldData) - { - return String.Format("{0,30}", - Utils.BytesToHexString((byte[])fieldData, - String.Format("{0,30}", fieldName))); - } - - private static string DecodeWearableType(string fieldName, object fieldData) - { - return String.Format("{0,30}: {1,-2} {2,-37} [WearableType]", - fieldName, - (byte)fieldData, - "(" + (WearableType)fieldData + ")"); - } - - private static string DecodeInventoryType(string fieldName, object fieldData) - { - return String.Format("{0,30}: {1,-2} {2,-37} [AssetType]", - fieldName, - (sbyte)fieldData, - "(" + (AssetType)(sbyte)fieldData + ")"); - } - - private static string DecodeInventorySort(string fieldName, object fieldData) - { - return String.Format("{0,30}: {1,-2} {2,-37} [InventorySortOrder]", - fieldName, - fieldData, - "(" + (InventorySortOrder)(int)fieldData + ")"); - } - - private static string DecodeInventoryInvType(string fieldName, object fieldData) - { - return String.Format("{0,30}: {1,-2} {2,-37} [InventoryType]", - fieldName, - (sbyte)fieldData, - "(" + (InventoryType)fieldData + ")"); - } - - private static string DecodeFolderType(string fieldName, object fieldData) - { - return String.Format("{0,30}: {1,-2} {2,-37} [Folderype]", - fieldName, - (sbyte)fieldData, - "(" + (FolderType)fieldData + ")"); - } - - private static string DecodeInventoryFlags(string fieldName, object fieldData) - { - return String.Format("{0,30}: {1,-2} {2,-37} [InventoryItemFlags]", - fieldName, - (uint)fieldData, - "(" + (InventoryItemFlags)(uint)fieldData + ")"); - } - - private static string DecodeObjectSaleType(string fieldName, object fieldData) - { - return String.Format("{0,30}: {1,-2} {2,-37} [SaleType]", - fieldName, - (byte)fieldData, - "(" + (SaleType)fieldData + ")"); - } - - private static string DecodeRegionFlags(string fieldName, object fieldData) - { - return String.Format("{0,30}: {1,-2} {2,-37} [RegionFlags]", - fieldName, - fieldData, - "(" + (RegionFlags)(uint)fieldData + ")"); - } - - private static string DecodeTransferParams(string fieldName, object fieldData) - { - byte[] paramData = (byte[])fieldData; - StringBuilder result = new StringBuilder(); - result.AppendLine(" "); - if (paramData.Length == 20) - { - result.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine, - "AssetID", - new UUID(paramData, 0)); - - result.AppendFormat("{0,30}: {1,-2} {2,-37} [AssetType]" + Environment.NewLine, - "AssetType", - (sbyte)paramData[16], - "(" + (AssetType)(sbyte)paramData[16] + ")"); - - } - else if (paramData.Length == 100) - { - //UUID agentID = new UUID(info.TransferInfo.Params, 0); - result.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine, - "AgentID", - new UUID(paramData, 0)); - - //UUID sessionID = new UUID(info.TransferInfo.Params, 16); - result.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine, - "SessionID", - new UUID(paramData, 16)); - //UUID ownerID = new UUID(info.TransferInfo.Params, 32); - result.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine, - "OwnerID", - new UUID(paramData, 32)); - //UUID taskID = new UUID(info.TransferInfo.Params, 48); - result.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine, - "TaskID", - new UUID(paramData, 48)); - //UUID itemID = new UUID(info.TransferInfo.Params, 64); - result.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine, - "ItemID", - new UUID(paramData, 64)); - - result.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine, - "AssetID", - new UUID(paramData, 80)); - - result.AppendFormat("{0,30}: {1,-2} {2,-37} [AssetType]" + Environment.NewLine, - "AssetType", - (sbyte)paramData[96], - "(" + (AssetType)(sbyte)paramData[96] + ")"); - } - else - { - Console.WriteLine("Oh Poop!"); - } - - result.Append(""); - - return result.ToString(); - } - - private static string DecodeTransferChannelType(string fieldName, object fieldData) - { - return String.Format("{0,30}: {1,-2} {2,-37} [ChannelType]", - fieldName, - fieldData, - "(" + (ChannelType)(int)fieldData + ")"); - } - - private static string DecodeTransferSourceType(string fieldName, object fieldData) - { - return String.Format("{0,30}: {1,-2} {2,-37} [SourceType]", - fieldName, - fieldData, - "(" + (SourceType)(int)fieldData + ")"); - } - - private static string DecodeTransferTargetType(string fieldName, object fieldData) - { - return String.Format("{0,30}: {1,-2} {2,-37} [TargetType]", - fieldName, - fieldData, - "(" + (TargetType)(int)fieldData + ")"); - } - - private static string DecodeMapRequestFlags(string fieldName, object fieldData) - { - return String.Format("{0,30}: {1,-2} {2,-37} [GridLayerType]", - fieldName, - fieldData, - "(" + (GridLayerType)(uint)fieldData + ")"); - } - - private static string DecodeGridItemType(string fieldName, object fieldData) - { - return String.Format("{0,30}: {1,-2} {2,-37} [GridItemType]", - fieldName, - fieldData, - "(" + (GridItemType)(uint)fieldData + ")"); - - } - - private static string DecodeLayerDataType(string fieldName, object fieldData) - { - return String.Format("{0,30}: {1,-2} {2,-37} [LayerType]", - fieldName, - fieldData, - "(" + (TerrainPatch.LayerType)(byte)fieldData + ")"); - } - - private static string DecodeMapAccess(string fieldName, object fieldData) - { - return String.Format("{0,30}: {1,-2} {2,-37} [SimAccess]", - fieldName, - fieldData, - "(" + (SimAccess)(byte)fieldData + ")"); - } - - private static string DecodeSimAccess(string fieldName, object fieldData) - { - return String.Format("{0,30}: {1,-2} {2,-37} [SimAccess]", - fieldName, - (byte)fieldData, - "(" + (SimAccess)fieldData + ")"); - } - - private static string DecodeAttachedSoundFlags(string fieldName, object fieldData) - { - return String.Format("{0,30}: {1,-2} {2,-37} [SoundFlags]", - fieldName, - (byte)fieldData, - "(" + (SoundFlags)fieldData + ")"); - } - - - private static string DecodeChatSourceType(string fieldName, object fieldData) - { - return String.Format("{0,30}: {1,-2} {2,-37} [SourceType]", - fieldName, - fieldData, - "(" + (SourceType)(byte)fieldData + ")"); - } - - private static string DecodeChatChatType(string fieldName, object fieldData) - { - return String.Format("{0,30}: {1,-2} {2,-37} [ChatType]", - fieldName, - (byte)fieldData, - "(" + (ChatType)fieldData + ")"); - } - - private static string DecodeChatAudible(string fieldName, object fieldData) - { - return String.Format("{0,30}: {1,-2} {2,-37} [ChatAudibleLevel]", - fieldName, - (byte)fieldData, - "(" + (ChatAudibleLevel)(byte)fieldData + ")"); - } - - private static string DecodeImageData(string fieldName, object fieldData) - { - return String.Format("{0,10}", - Utils.BytesToHexString((byte[])fieldData, - String.Format("{0,30}", fieldName))); - } - - private static string DecodeTerseTextureEntry(string fieldName, object fieldData) - { - byte[] block = (byte[])fieldData; - - Primitive.TextureEntry te = new Primitive.TextureEntry(block, 4, block.Length - 4); - - StringBuilder result = new StringBuilder(); - - result.AppendFormat("{0,30}", " " + Environment.NewLine); - if (te.DefaultTexture != null) - { - result.AppendFormat("{0,30}", " " + Environment.NewLine); - GenericFieldsDecoder(te.DefaultTexture, ref result); - GenericPropertiesDecoder(te.DefaultTexture, ref result); - result.AppendFormat("{0,30}", " " + Environment.NewLine); - } - result.AppendFormat("{0,30}", " " + Environment.NewLine); - for (int i = 0; i < te.FaceTextures.Length; i++) - { - if (te.FaceTextures[i] != null) - { - result.AppendFormat("{0,30}[{1}]" + Environment.NewLine, "FaceTexture", i); - GenericFieldsDecoder(te.FaceTextures[i], ref result); - GenericPropertiesDecoder(te.FaceTextures[i], ref result); - } - } - result.AppendFormat("{0,30}", " " + Environment.NewLine); - result.AppendFormat("{0,30}", ""); - - return result.ToString(); - } - - private static string DecodeTextureEntry(string fieldName, object fieldData) - { - Primitive.TextureEntry te; - if (fieldData is Primitive.TextureEntry) - te = (Primitive.TextureEntry)fieldData; - else - { - byte[] tebytes = (byte[])fieldData; - te = new Primitive.TextureEntry(tebytes, 0, tebytes.Length); - } - - StringBuilder result = new StringBuilder(); - - result.AppendFormat("{0,30}", " " + Environment.NewLine); - if (te.DefaultTexture != null) - { - result.AppendFormat("{0,30}", " " + Environment.NewLine); - GenericFieldsDecoder(te.DefaultTexture, ref result); - GenericPropertiesDecoder(te.DefaultTexture, ref result); - result.AppendFormat("{0,30}", " " + Environment.NewLine); - } - result.AppendFormat("{0,30}", " " + Environment.NewLine); - for (int i = 0; i < te.FaceTextures.Length; i++) - { - if (te.FaceTextures[i] != null) - { - result.AppendFormat("{0,30}[{1}]" + Environment.NewLine, "FaceTexture", i); - GenericFieldsDecoder(te.FaceTextures[i], ref result); - GenericPropertiesDecoder(te.FaceTextures[i], ref result); - } - } - result.AppendFormat("{0,30}", " " + Environment.NewLine); - result.AppendFormat("{0,30}", ""); - - return result.ToString(); - } - - private static void GenericFieldsDecoder(object obj, ref StringBuilder result) - { - Type parcelType = obj.GetType(); - FieldInfo[] fields = parcelType.GetFields(); - foreach (FieldInfo field in fields) - { - String special; - if (SpecialDecoder("a" + "." + "b" + "." + field.Name, - field.GetValue(obj), out special)) - { - result.AppendLine(special); - } - else - { - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - field.Name, - field.GetValue(obj), - field.FieldType.Name); - } - } - } - - private static void GenericPropertiesDecoder(object obj, ref StringBuilder result) - { - Type parcelType = obj.GetType(); - PropertyInfo[] propertyInfos = parcelType.GetProperties(); - foreach (PropertyInfo property in propertyInfos) - { - String special; - if (SpecialDecoder("a" + "." + "b" + "." + property.Name, - property.GetValue(obj, null), out special)) - { - result.AppendLine(special); - } - else - { - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - property.Name, - property.GetValue(obj, null), - property.PropertyType.Name); - } - } - } - - private static string DecodeDialog(string fieldName, object fieldData) - { - return String.Format("{0,30}: {1,-2} {2,-37} [{3}]", - fieldName, - (byte)fieldData, - "(" + (InstantMessageDialog)fieldData + ")", - fieldData.GetType().Name); - } - - private static string DecodeControlFlags(string fieldName, object fieldData) - { - return String.Format("{0,30}: {1,-10} {2,-29} [{3}]", - fieldName, - fieldData, - "(" + (AgentManager.ControlFlags)(uint)fieldData + ")", - fieldData.GetType().Name); - } - - private static string DecodePermissionMask(string fieldName, object fieldData) - { - return String.Format("{0,30}: {1,-10} {2,-29} [{3}]", - fieldName, - (uint)fieldData, - "(" + (PermissionMask)fieldData + ")", - fieldData.GetType().Name); - } - - private static string DecodeViewerEffectTypeData(string fieldName, object fieldData) - { - byte[] data = (byte[])fieldData; - StringBuilder sb = new StringBuilder(); - if (data.Length == 56 || data.Length == 57) - { - UUID sourceAvatar = new UUID(data, 0); - UUID targetObject = new UUID(data, 16); - Vector3d targetPos = new Vector3d(data, 32); - sb.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine, fieldName, "Source AvatarID=" + sourceAvatar); - sb.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine, fieldName, "Target ObjectID=" + targetObject); - - - float lx, ly; - Helpers.GlobalPosToRegionHandle((float)targetPos.X, (float)targetPos.Y, out lx, out ly); - - sb.AppendFormat("{0,30}: {1,-40} [Vector3d]", fieldName, targetPos); - - if (data.Length == 57) - { - sb.AppendLine(); - sb.AppendFormat("{0,30}: {1,-17} {2,-22} [Byte]", fieldName, "Point At Type=" + data[56], - "(" + (PointAtType)data[56] + ")"); - } - - return sb.ToString(); - } - else - { - return String.Format("{0,30}: (No Decoder) Length={1}" + Environment.NewLine, fieldName, data.Length) + Utils.BytesToHexString(data, String.Format("{0,30}", "")); - } - } - - private static string DecodeAgentState(string fieldName, object fieldData) - { - return String.Format("{0,30}: {1,-2} {2,-37} [AgentState]", - fieldName, - fieldData, - "(" + (AgentState)(byte)fieldData + ")"); - } - - private static string DecodeAgentFlags(string fieldName, object fieldData) - { - return String.Format("{0,30}: {1,-2} {2,-37} [AgentFlags]", - fieldName, - fieldData, - "(" + (AgentFlags)(byte)fieldData + ")"); - } - - private static string DecodeObjectState(string fieldName, object fieldData) - { - return String.Format("{0,30}: {1,-2} {2,-37} [AttachmentPoint]", - fieldName, - fieldData, - "(" + (AttachmentPoint)(byte)fieldData + ")"); - } - - private static string DecodeViewerEffectType(string fieldName, object fieldData) - { - return String.Format("{0,30}: {1,-2} {2,-37} [{3}]", - fieldName, - fieldData, - "(" + (EffectType)(byte)fieldData + ")", - fieldData.GetType().Name); - } - - private static string DecodeAnimToConst(string fieldName, object fieldData) - { - string animConst = "UUID"; - Dictionary animsDict = Animations.ToDictionary(); - if (animsDict.ContainsKey((UUID)fieldData)) - animConst = animsDict[(UUID)fieldData]; - return String.Format("{0,30}: {1,-40} [{2}]", - fieldName, - fieldData, - animConst); - } - #endregion - - /// - /// Creates a formatted string containing the values of a Packet - /// - /// The Packet - /// A formatted string of values of the nested items in the Packet object - public static string PacketToString(Packet packet) - { - StringBuilder result = new StringBuilder(); - - result.AppendFormat("Packet Type: {0}" + Environment.NewLine, packet.Type); - result.AppendLine("[Packet Header]"); - // payload - result.AppendFormat("Sequence: {0}" + Environment.NewLine, packet.Header.Sequence); - result.AppendFormat(" Options: {0}" + Environment.NewLine, InterpretOptions(packet.Header)); - result.AppendLine(); - - result.AppendLine("[Packet Payload]"); - - FieldInfo[] fields = packet.GetType().GetFields(); - - for (int i = 0; i < fields.Length; i++) - { - // we're not interested in any of these here - if (fields[i].Name == "Type" || fields[i].Name == "Header" || fields[i].Name == "HasVariableBlocks") - continue; - - if (fields[i].FieldType.IsArray) - { - result.AppendFormat("{0,30} []" + Environment.NewLine, "-- " + fields[i].Name + " --"); - RecursePacketArray(fields[i], packet, ref result); - } - else - { - result.AppendFormat("{0,30}" + Environment.NewLine, "-- " + fields[i].Name + " --"); - RecursePacketField(fields[i], packet, ref result); - } - } - return result.ToString(); - } - - public static string InterpretOptions(Header header) - { - return "[" - + (header.AppendedAcks ? "Ack" : " ") - + " " - + (header.Resent ? "Res" : " ") - + " " - + (header.Reliable ? "Rel" : " ") - + " " - + (header.Zerocoded ? "Zer" : " ") - + "]" - ; - } - - private static void RecursePacketArray(FieldInfo fieldInfo, object packet, ref StringBuilder result) - { - var packetDataObject = fieldInfo.GetValue(packet); - int k = -1; - foreach (object nestedArrayRecord in packetDataObject as Array) - { - FieldInfo[] fields = nestedArrayRecord.GetType().GetFields(); - ++k; - for (int i = 0; i < fields.Length; i++) - { - String special; - if (SpecialDecoder(packet.GetType().Name + "." + fieldInfo.Name + "." + fields[i].Name, - fields[i].GetValue(nestedArrayRecord), out special)) - { - result.AppendLine(special); - } - else if (fields[i].FieldType.IsArray) // default for an array (probably a byte[]) - { - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - fields[i].Name + "[" + k.ToString() + "]", - Utils.BytesToString((byte[])fields[i].GetValue(nestedArrayRecord)), - /*fields[i].GetValue(nestedArrayRecord).GetType().Name*/ "String"); - } - else // default for a field - { - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - fields[i].Name + "[" + k.ToString() + "]", - fields[i].GetValue(nestedArrayRecord), - fields[i].GetValue(nestedArrayRecord).GetType().Name); - } - } - - // Handle Properties - foreach (PropertyInfo propertyInfo in nestedArrayRecord.GetType().GetProperties()) - { - if (propertyInfo.Name.Equals("Length")) - continue; - - string special; - if (SpecialDecoder(packet.GetType().Name + "." + fieldInfo.Name + "." + propertyInfo.Name, - propertyInfo.GetValue(nestedArrayRecord, null), - out special)) - { - result.AppendLine(special); - } - else - { - var p = propertyInfo.GetValue(nestedArrayRecord, null); - /* Leave the c for now at the end, it signifies something useful that still needs to be done i.e. a decoder written */ - result.AppendFormat("{0, 30}: {1,-40} [{2}]c" + Environment.NewLine, - propertyInfo.Name, - Utils.BytesToString((byte[])propertyInfo.GetValue(nestedArrayRecord, null)), - propertyInfo.PropertyType.Name); - } - } - result.AppendFormat("{0,32}" + Environment.NewLine, "***"); - } - } - - private static void RecursePacketField(FieldInfo fieldInfo, object packet, ref StringBuilder result) - { - object packetDataObject = fieldInfo.GetValue(packet); - - // handle Fields - foreach (FieldInfo packetValueField in fieldInfo.GetValue(packet).GetType().GetFields()) - { - string special; - if (SpecialDecoder(packet.GetType().Name + "." + fieldInfo.Name + "." + packetValueField.Name, - packetValueField.GetValue(packetDataObject), - out special)) - { - result.AppendLine(special); - } - else if (packetValueField.FieldType.IsArray) - { - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - packetValueField.Name, - Utils.BytesToString((byte[])packetValueField.GetValue(packetDataObject)), - /*packetValueField.FieldType.Name*/ "String"); - } - else - { - result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, - packetValueField.Name, packetValueField.GetValue(packetDataObject), packetValueField.FieldType.Name); - - } - } - - // Handle Properties - foreach (PropertyInfo propertyInfo in packetDataObject.GetType().GetProperties()) - { - if (propertyInfo.Name.Equals("Length")) - continue; - - string special; - if (SpecialDecoder(packet.GetType().Name + "." + fieldInfo.Name + "." + propertyInfo.Name, - propertyInfo.GetValue(packetDataObject, null), - out special)) - { - result.AppendLine(special); - } - else if (propertyInfo.GetValue(packetDataObject, null).GetType() == typeof(byte[])) - { - result.AppendFormat("{0, 30}: {1,-40} [{2}]" + Environment.NewLine, - propertyInfo.Name, - Utils.BytesToString((byte[])propertyInfo.GetValue(packetDataObject, null)), - propertyInfo.PropertyType.Name); - } - else - { - result.AppendFormat("{0, 30}: {1,-40} [{2}]" + Environment.NewLine, - propertyInfo.Name, - propertyInfo.GetValue(packetDataObject, null), - propertyInfo.PropertyType.Name); - } - } - } - - private static bool SpecialDecoder(string decoderKey, object fieldData, out string result) - { - result = string.Empty; - string[] keys = decoderKey.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries); - string[] keyList = { decoderKey, decoderKey.Replace("Packet", ""), keys[1] + "." + keys[2], keys[2] }; - foreach (string key in keyList) - { - - bool ok = true; - if (fieldData is byte[]) - { - byte[] fd = (byte[])fieldData; - ok = fd.Length > 0; - if (!ok) - { - // bypass the decoder since we were passed an empty byte array - result = String.Format("{0,30}:", keys[2]); - return true; - } - } - - if (ok && Callbacks.ContainsKey(key)) // fieldname e.g: Plane - { - foreach (CustomPacketDecoder decoder in Callbacks[key]) - result = decoder(keys[2], fieldData); - return true; - } - } - return false; - } - - /// - /// Decode an IMessage object into a beautifully formatted string - /// - /// The IMessage object - /// Recursion level (used for indenting) - /// A formatted string containing the names and values of the source object - public static string MessageToString(object message, int recurseLevel) - { - if (message == null) - return String.Empty; - - StringBuilder result = new StringBuilder(); - // common/custom types - if (recurseLevel <= 0) - { - result.AppendFormat("Message Type: {0}" + Environment.NewLine, message.GetType().Name); - } - else - { - string pad = " +--".PadLeft(recurseLevel + 3); - result.AppendFormat("{0} {1}" + Environment.NewLine, pad, message.GetType().Name); - } - - recurseLevel++; - - foreach (FieldInfo messageField in message.GetType().GetFields()) - { - // an abstract message class - if (messageField.FieldType.IsAbstract) - { - result.AppendLine(MessageToString(messageField.GetValue(message), recurseLevel)); - } - // a byte array - else if (messageField.GetValue(message) != null && messageField.GetValue(message).GetType() == typeof(Byte[])) - { - result.AppendFormat("{0, 30}:" + Environment.NewLine, messageField.Name); - - result.AppendFormat("{0}" + Environment.NewLine, - Utils.BytesToHexString((byte[])messageField.GetValue(message), - String.Format("{0,30}", ""))); - } - - // an array of class objects - else if (messageField.FieldType.IsArray) - { - var messageObjectData = messageField.GetValue(message); - result.AppendFormat("-- {0} --" + Environment.NewLine, messageField.FieldType.Name); - foreach (object nestedArrayObject in messageObjectData as Array) - { - if (nestedArrayObject == null) - { - result.AppendFormat("{0,30}" + Environment.NewLine, "-- null --"); - continue; - } - else - { - result.AppendFormat("{0,30}" + Environment.NewLine, "-- " + nestedArrayObject.GetType().Name + " --"); - } - foreach (FieldInfo nestedField in nestedArrayObject.GetType().GetFields()) - { - if (nestedField.FieldType.IsEnum) - { - result.AppendFormat("{0,30}: {1,-10} {2,-29} [{3}]" + Environment.NewLine, - nestedField.Name, - Enum.Format(nestedField.GetValue(nestedArrayObject).GetType(), - nestedField.GetValue(nestedArrayObject), "D"), - "(" + nestedField.GetValue(nestedArrayObject) + ")", - nestedField.GetValue(nestedArrayObject).GetType().Name); - } - else if (nestedField.FieldType.IsInterface) - { - result.AppendLine(MessageToString(nestedField.GetValue(nestedArrayObject), recurseLevel)); - } - else - { - result.AppendFormat("{0, 30}: {1,-40} [{2}]" + Environment.NewLine, - nestedField.Name, - nestedField.GetValue(nestedArrayObject), - nestedField.FieldType.Name); - } - } - } - } - else - { - if (messageField.FieldType.IsEnum) - { - result.AppendFormat("{0,30}: {1,-2} {2,-37} [{3}]" + Environment.NewLine, - messageField.Name, - Enum.Format(messageField.GetValue(message).GetType(), - messageField.GetValue(message), "D"), - "(" + messageField.GetValue(message) + ")", - messageField.FieldType.Name); - } - else if (messageField.FieldType.IsInterface) - { - result.AppendLine(MessageToString(messageField.GetValue(message), recurseLevel)); - } - else - { - result.AppendFormat("{0, 30}: {1,-40} [{2}]" + Environment.NewLine, - messageField.Name, messageField.GetValue(message), messageField.FieldType.Name); - } - } - } - - return result.ToString(); - } - } -} +/* + * Copyright (c) 2006-2016, openmetaverse.co + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.co nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Text; + +namespace OpenMetaverse.Packets +{ + + public static class PacketDecoder + { + /// + /// A custom decoder callback + /// + /// The key of the object + /// the data to decode + /// A string represending the fieldData + public delegate string CustomPacketDecoder(string fieldName, object fieldData); + + private static Dictionary> Callbacks = new Dictionary>(); + + + static PacketDecoder() + { + AddCallback("Color", DecodeColorField); + AddCallback("TextColor", DecodeColorField); + AddCallback("Timestamp", DecodeTimeStamp); + AddCallback("EstateCovenantReply.Data.CovenantTimestamp", DecodeTimeStamp); + AddCallback("CreationDate", DecodeTimeStamp); + AddCallback("BinaryBucket", DecodeBinaryBucket); + AddCallback("ParcelData.Data", DecodeBinaryToHexString); + AddCallback("LayerData.Data", DecodeBinaryToHexString); + AddCallback("ImageData.Data", DecodeImageData); + AddCallback("TransferData.Data", DecodeBinaryToHexString); + AddCallback("ObjectData.TextureEntry", DecodeTextureEntry); + AddCallback("ImprovedInstantMessage.MessageBlock.Dialog", DecodeDialog); + + // Inventory/Permissions + AddCallback("BaseMask", DecodePermissionMask); + AddCallback("OwnerMask", DecodePermissionMask); + AddCallback("EveryoneMask", DecodePermissionMask); + AddCallback("NextOwnerMask", DecodePermissionMask); + AddCallback("GroupMask", DecodePermissionMask); + + // FetchInventoryDescendents + AddCallback("InventoryData.SortOrder", DecodeInventorySort); + + AddCallback("WearableType", DecodeWearableType); + // + AddCallback("InventoryData.Type", DecodeInventoryType); + AddCallback("InvType", DecodeInventoryInvType); + AddCallback("InventoryData.Flags", DecodeInventoryFlags); + // BulkUpdateInventory + AddCallback("ItemData.Type", DecodeInventoryType); + AddCallback("ItemData.Flags", DecodeInventoryFlags); + + AddCallback("SaleType", DecodeObjectSaleType); + + AddCallback("ScriptControlChange.Data.Controls", DecodeScriptControls); + + AddCallback("RegionFlags", DecodeRegionFlags); + AddCallback("SimAccess", DecodeSimAccess); + AddCallback("ControlFlags", DecodeControlFlags); + + // AgentUpdate + AddCallback("AgentUpdate.AgentData.State", DecodeAgentState); + AddCallback("AgentUpdate.AgentData.Flags", DecodeAgentFlags); + + // ViewerEffect TypeData + AddCallback("ViewerEffect.Effect.TypeData", DecodeViewerEffectTypeData); + AddCallback("ViewerEffect.Effect.Type", DecodeViewerEffectType); + + // Prim/ObjectUpdate decoders + AddCallback("ObjectUpdate.ObjectData.PCode", DecodeObjectPCode); + AddCallback("ObjectUpdate.ObjectData.Material", DecodeObjectMaterial); + AddCallback("ObjectUpdate.ObjectData.ClickAction", DecodeObjectClickAction); + AddCallback("ObjectData.UpdateFlags", DecodeObjectUpdateFlags); + + AddCallback("ObjectUpdate.ObjectData.ObjectData", DecodeObjectData); + AddCallback("TextureAnim", DecodeObjectTextureAnim); + AddCallback("ObjectUpdate.ObjectData.NameValue", DecodeNameValue); + AddCallback("ObjectUpdate.ObjectData.Data", DecodeObjectData); + + AddCallback("ObjectUpdate.ObjectData.PSBlock", DecodeObjectParticleSystem); + AddCallback("ParticleSys", DecodeObjectParticleSystem); + AddCallback("ObjectUpdate.ObjectData.ExtraParams", DecodeObjectExtraParams); + + AddCallback("ImprovedTerseObjectUpdate.ObjectData.Data", DecodeTerseUpdate); + AddCallback("ImprovedTerseObjectUpdate.ObjectData.TextureEntry", DecodeTerseTextureEntry); + + AddCallback("ObjectUpdateCompressed.ObjectData.Data", DecodeObjectCompressedData); + + // ImprovedTerseObjectUpdate & ObjectUpdate AttachmentPoint & ObjectUpdateCompressed + AddCallback("ObjectData.State", DecodeObjectState); + //AddCallback("ObjectUpdateCompressed.ObjectData.State", DecodeObjectState); + //AddCallback("ImprovedTerseObjectUpdate.ObjectData.State", DecodeObjectState); + + + // ChatFromSimulator + AddCallback("ChatData.SourceType", DecodeChatSourceType); + AddCallback("ChatData.ChatType", DecodeChatChatType); + AddCallback("ChatData.Audible", DecodeChatAudible); + AddCallback("AttachedSound.DataBlock.Flags", DecodeAttachedSoundFlags); + + AddCallback("RequestImage.Type", DecodeImageType); + + AddCallback("EstateOwnerMessage.ParamList.Parameter", DecodeEstateParameter); + + AddCallback("Codec", DecodeImageCodec); + AddCallback("Info.TeleportFlags", DecodeTeleportFlags); + + // map + AddCallback("MapBlockRequest.AgentData.Flags", DecodeMapRequestFlags); + AddCallback("MapItemRequest.AgentData.Flags", DecodeMapRequestFlags); + AddCallback("MapBlockReply.Data.Access", DecodeMapAccess); + AddCallback("FolderData.Type", DecodeFolderType); + AddCallback("RequestData.ItemType", DecodeGridItemType); + + // TransferRequest/TransferInfo + AddCallback("TransferInfo.Params", DecodeTransferParams); + AddCallback("TransferInfo.ChannelType", DecodeTransferChannelType); + AddCallback("TransferInfo.SourceType", DecodeTransferSourceType); + AddCallback("TransferInfo.TargetType", DecodeTransferTargetType); + AddCallback("TransferData.ChannelType", DecodeTransferChannelType); + // SendXferPacket + AddCallback("DataPacket.Data", DecodeBinaryToHexString); + // Directory Manager + AddCallback("DirClassifiedQuery.QueryData.QueryFlags", DecodeDirClassifiedQueryFlags); + AddCallback("QueryData.QueryFlags", DecodeDirQueryFlags); + AddCallback("Category", DecodeCategory); + AddCallback("QueryData.SearchType", SearchTypeFlags); + + AddCallback("ClassifiedFlags", DecodeDirClassifiedFlags); + AddCallback("EventFlags", DecodeEventFlags); + + AddCallback("ParcelAccessListRequest.Data.Flags", DecodeParcelACL); + AddCallback("ParcelAccessListReply.Data.Flags", DecodeParcelACL); + //AddCallback("ParcelAccessListReply.List.Flags", DecodeParcelACLReply); + + // AgentAnimation + AddCallback("AnimID", DecodeAnimToConst); + + AddCallback("LayerData.LayerID.Type", DecodeLayerDataType); + + AddCallback("GroupPowers", DecodeGroupPowers); + } + + /// + /// Add a custom decoder callback + /// + /// The key of the field to decode + /// The custom decode handler + public static void AddCallback(string key, CustomPacketDecoder customPacketHandler) + { + if (Callbacks.ContainsKey(key)) + { + lock (Callbacks) + Callbacks[key].Add(customPacketHandler); + } + else + { + lock (Callbacks) + Callbacks.Add(key, new List() { customPacketHandler }); + } + } + + /// + /// Remove a custom decoder callback + /// + /// The key of the field to decode + /// The custom decode handler + public static void RemoveCustomHandler(string key, CustomPacketDecoder customPacketHandler) + { + if (Callbacks.ContainsKey(key)) + lock (Callbacks) + { + if (Callbacks[key].Contains(customPacketHandler)) + Callbacks[key].Remove(customPacketHandler); + } + } + + #region Custom Decoders + + private static string DecodeTerseUpdate(string fieldName, object fieldData) + { + byte[] block = (byte[])fieldData; + int i = 4; + + StringBuilder result = new StringBuilder(); + + // LocalID + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "LocalID", + Utils.BytesToUInt(block, 0), + "Uint32"); + + + + // State + byte point = block[i++]; + result.AppendFormat("{0,30}: {1,-3} {2,-36} [{3}]" + Environment.NewLine, + "State", + point, + "(" + (AttachmentPoint)point + ")", + "AttachmentPoint"); + + // Avatar boolean + bool isAvatar = (block[i++] != 0); + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "IsAvatar", + isAvatar, + "Boolean"); + + // Collision normal for avatar + if (isAvatar) + { + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "CollisionPlane", + new Vector4(block, i), + "Vector4"); + + i += 16; + } + + // Position + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "Position", + new Vector3(block, i), + "Vector3"); + i += 12; + + // Velocity + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "Velocity", + new Vector3( + Utils.BytesUInt16ToFloat(block, i, -128.0f, 128.0f), + Utils.BytesUInt16ToFloat(block, i + 2, -128.0f, 128.0f), + Utils.BytesUInt16ToFloat(block, i + 4, -128.0f, 128.0f)), + "Vector3"); + i += 6; + + // Acceleration + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "Acceleration", + new Vector3( + Utils.BytesUInt16ToFloat(block, i, -64.0f, 64.0f), + Utils.BytesUInt16ToFloat(block, i + 2, -64.0f, 64.0f), + Utils.BytesUInt16ToFloat(block, i + 4, -64.0f, 64.0f)), + "Vector3"); + + i += 6; + // Rotation (theta) + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "Rotation", + new Quaternion( + Utils.BytesUInt16ToFloat(block, i, -1.0f, 1.0f), + Utils.BytesUInt16ToFloat(block, i + 2, -1.0f, 1.0f), + Utils.BytesUInt16ToFloat(block, i + 4, -1.0f, 1.0f), + Utils.BytesUInt16ToFloat(block, i + 6, -1.0f, 1.0f)), + "Quaternion"); + i += 8; + // Angular velocity (omega) + result.AppendFormat("{0,30}: {1,-40} [{2}]", + "AngularVelocity", + new Vector3( + Utils.BytesUInt16ToFloat(block, i, -64.0f, 64.0f), + Utils.BytesUInt16ToFloat(block, i + 2, -64.0f, 64.0f), + Utils.BytesUInt16ToFloat(block, i + 4, -64.0f, 64.0f)), + "Vector3"); + //pos += 6; + // TODO: What is in these 6 bytes? + return result.ToString(); + } + + private static string DecodeObjectCompressedData(string fieldName, object fieldData) + { + StringBuilder result = new StringBuilder(); + byte[] block = (byte[])fieldData; + int i = 0; + + // UUID + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "ID", + new UUID(block, 0), + "UUID"); + i += 16; + + // Local ID + uint LocalID = (uint)(block[i++] + (block[i++] << 8) + + (block[i++] << 16) + (block[i++] << 24)); + + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "LocalID", + LocalID, + "Uint32"); + // PCode + PCode pcode = (PCode)block[i++]; + + result.AppendFormat("{0,30}: {1,-3} {2,-36} [{3}]" + Environment.NewLine, + "PCode", + (int)pcode, + "(" + pcode + ")", + "PCode"); + + // State + AttachmentPoint point = (AttachmentPoint)block[i++]; + result.AppendFormat("{0,30}: {1,-3} {2,-36} [{3}]" + Environment.NewLine, + "State", + (byte)point, + "(" + point + ")", + "AttachmentPoint"); + + //CRC + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "CRC", + Utils.BytesToUInt(block, i), + "UInt"); + i += 4; + + // Material + result.AppendFormat("{0,30}: {1,-3} {2,-36} [{3}]" + Environment.NewLine, + "Material", + block[i], + "(" + (Material)block[i++] + ")", + "Material"); + + // Click action + result.AppendFormat("{0,30}: {1,-3} {2,-36} [{3}]" + Environment.NewLine, + "ClickAction", + block[i], + "(" + (ClickAction)block[i++] + ")", + "ClickAction"); + + // Scale + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "Scale", + new Vector3(block, i), + "Vector3"); + i += 12; + + // Position + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "Position", + new Vector3(block, i), + "Vector3"); + i += 12; + + // Rotation + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "Rotation", + new Vector3(block, i), + "Vector3"); + + i += 12; + // Compressed flags + + CompressedFlags flags = (CompressedFlags)Utils.BytesToUInt(block, i); + result.AppendFormat("{0,30}: {1,-10} {2,-29} [{3}]" + Environment.NewLine, + "CompressedFlags", + Utils.BytesToUInt(block, i), + "(" + (CompressedFlags)Utils.BytesToUInt(block, i) + ")", + "UInt"); + i += 4; + + // Owners ID + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "OwnerID", + new UUID(block, i), + "UUID"); + i += 16; + + // Angular velocity + if ((flags & CompressedFlags.HasAngularVelocity) != 0) + { + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "AngularVelocity", + new Vector3(block, i), + "Vector3"); + i += 12; + } + + // Parent ID + if ((flags & CompressedFlags.HasParent) != 0) + { + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "ParentID", + (uint)(block[i++] + (block[i++] << 8) + + (block[i++] << 16) + (block[i++] << 24)), + "UInt"); + } + + // Tree data + if ((flags & CompressedFlags.Tree) != 0) + { + result.AppendFormat("{0,30}: {1,-2} {2,-37} [{3}]" + Environment.NewLine, + "TreeSpecies", + block[i++], + "(" + (Tree)block[i] + ")", + "Tree"); + } + + // Scratch pad + else if ((flags & CompressedFlags.ScratchPad) != 0) + { + int size = block[i++]; + byte[] scratch = new byte[size]; + Buffer.BlockCopy(block, i, scratch, 0, size); + result.AppendFormat("{0,30}: {1,-40} [ScratchPad[]]" + Environment.NewLine, + "ScratchPad", + Utils.BytesToHexString(scratch, String.Format("{0,30}", "Data"))); + i += size; + } + + // Floating text + if ((flags & CompressedFlags.HasText) != 0) + { + string text = String.Empty; + while (block[i] != 0) + { + text += (char)block[i]; + i++; + } + i++; + + // Floating text + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "Text", + text, + "string"); + + // Text color + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "TextColor", + new Color4(block, i, false), + "Color4"); + i += 4; + } + + // Media URL + if ((flags & CompressedFlags.MediaURL) != 0) + { + string text = String.Empty; + while (block[i] != 0) + { + text += (char)block[i]; + i++; + } + i++; + + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "MediaURL", + text, + "string"); + } + + // Particle system + if ((flags & CompressedFlags.HasParticles) != 0) + { + Primitive.ParticleSystem p = new Primitive.ParticleSystem(block, i); + result.AppendLine(DecodeObjectParticleSystem("ParticleSystem", p)); + i += 86; + } + + // Extra parameters TODO: + Primitive prim = new Primitive(); + int extrapLen = prim.SetExtraParamsFromBytes(block, i); + i += extrapLen; + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "ExtraParams[]", + extrapLen, + "byte[]"); + + //Sound data + if ((flags & CompressedFlags.HasSound) != 0) + { + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "SoundID", + new UUID(block, i), + "UUID"); + i += 16; + + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "SoundGain", + Utils.BytesToFloat(block, i), + "Float"); + i += 4; + + result.AppendFormat("{0,30}: {1,-2} {2,-37} [{3}]" + Environment.NewLine, + "SoundFlags", + block[i++], + "(" + (SoundFlags)block[i] + ")", + "SoundFlags"); + + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "SoundRadius", + Utils.BytesToFloat(block, i), + "Float"); + i += 4; + } + + // Name values + if ((flags & CompressedFlags.HasNameValues) != 0) + { + string text = String.Empty; + while (block[i] != 0) + { + text += (char)block[i]; + i++; + } + i++; + + // Parse the name values + if (text.Length > 0) + { + string[] lines = text.Split('\n'); + NameValue[] nameValues = new NameValue[lines.Length]; + + for (int j = 0; j < lines.Length; j++) + { + if (!String.IsNullOrEmpty(lines[j])) + { + NameValue nv = new NameValue(lines[j]); + nameValues[j] = nv; + } + } + result.AppendLine(DecodeNameValue("NameValues", nameValues)); + } + } + + result.AppendFormat("{0,30}: {1,-2} {2,-37} [{3}]" + Environment.NewLine, + "PathCurve", + block[i], + "(" + (PathCurve)block[i++] + ")", + "PathCurve"); + + ushort pathBegin = Utils.BytesToUInt16(block, i); + i += 2; + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "PathBegin", + Primitive.UnpackBeginCut(pathBegin), + "float"); + + ushort pathEnd = Utils.BytesToUInt16(block, i); + i += 2; + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "PathEnd", + Primitive.UnpackEndCut(pathEnd), + "float"); + + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "PathScaleX", + Primitive.UnpackPathScale(block[i++]), + "float"); + + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "PathScaleY", + Primitive.UnpackPathScale(block[i++]), + "float"); + + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "PathShearX", + Primitive.UnpackPathShear((sbyte)block[i++]), + "float"); + + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "PathShearY", + Primitive.UnpackPathShear((sbyte)block[i++]), + "float"); + + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "PathTwist", + Primitive.UnpackPathTwist((sbyte)block[i++]), + "float"); + + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "PathTwistBegin", + Primitive.UnpackPathTwist((sbyte)block[i++]), + "float"); + + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "PathRadiusOffset", + Primitive.UnpackPathTwist((sbyte)block[i++]), + "float"); + + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "PathTaperX", + Primitive.UnpackPathTaper((sbyte)block[i++]), + "float"); + + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "PathTaperY", + Primitive.UnpackPathTaper((sbyte)block[i++]), + "float"); + + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "PathRevolutions", + Primitive.UnpackPathRevolutions(block[i++]), + "float"); + + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "PathSkew", + Primitive.UnpackPathTwist((sbyte)block[i++]), + "float"); + + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "ProfileCurve", + block[i++], + "float"); + + ushort profileBegin = Utils.BytesToUInt16(block, i); + i += 2; + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "ProfileBegin", + Primitive.UnpackBeginCut(profileBegin), + "float"); + + ushort profileEnd = Utils.BytesToUInt16(block, i); + i += 2; + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "ProfileEnd", + Primitive.UnpackEndCut(profileEnd), + "float"); + + ushort profileHollow = Utils.BytesToUInt16(block, i); + i += 2; + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "ProfileHollow", + Primitive.UnpackProfileHollow(profileHollow), + "float"); + + int textureEntryLength = (int)Utils.BytesToUInt(block, i); + i += 4; + //prim.Textures = new Primitive.TextureEntry(block, i, textureEntryLength); + String s = DecodeTextureEntry("TextureEntry", new Primitive.TextureEntry(block, i, textureEntryLength)); + result.AppendLine(s); + i += textureEntryLength; + + // Texture animation + if ((flags & CompressedFlags.TextureAnimation) != 0) + { + i += 4; + string a = DecodeObjectTextureAnim("TextureAnimation", new Primitive.TextureAnimation(block, i)); + result.AppendLine(a); + } + + if ((flags & CompressedFlags.HasParticlesNew) != 0) + { + Primitive.ParticleSystem p = new Primitive.ParticleSystem(block, i); + result.AppendLine(DecodeObjectParticleSystem("ParticleSystemNEW", p)); + i += 94; + if ((p.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.DataGlow) != 0) + i += 2; + if ((p.PartDataFlags & Primitive.ParticleSystem.ParticleDataFlags.DataBlend) != 0) + i += 2; + } + + return result.ToString(); + } + + private static string DecodeObjectData(string fieldName, object fieldData) + { + byte[] data = (byte[])fieldData; + if (data.Length == 1) + { + return String.Format("{0,30}: {1,2} {2,-38} [{3}]", + fieldName + " (Tree Species)", + fieldData, + //"(" + (Tree)(byte)fieldData + ")", + "(" + (Tree)data[0] + ")", + fieldData.GetType().Name); + } + else if (data.Length == 76) + { + /* TODO: these are likely useful packed fields, + * need to unpack them */ + Vector4 col = Vector4.Zero; + Vector3 offset = Vector3.Zero; + Vector3 vel = Vector3.Zero; + Vector3 acc = Vector3.Zero; + Quaternion q = Quaternion.Identity; + Vector3 angvel = Vector3.Zero; + + col.FromBytes(data, 0); + offset.FromBytes(data, 16); + vel.FromBytes(data, 28); + acc.FromBytes(data, 40); + q.FromBytes(data, 52, true); + angvel.FromBytes(data, 64); + + StringBuilder result = new StringBuilder(); + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "ColisionPlane", + col, + "Vector4"); + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "Offset", + offset, + "Vector3"); + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "Velocity", + vel, + "Vector3"); + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "Acceleration", + acc, + "Vector3"); + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "rotation", + q, + "Quaternion"); + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "Omega", + angvel, + "Vector3"); + return result.ToString(); + } + else if (data.Length == 60) + { + /* TODO: these are likely useful packed fields, + * need to unpack them */ + Vector3 offset = Vector3.Zero; + Vector3 vel = Vector3.Zero; + Vector3 acc = Vector3.Zero; + Quaternion q = Quaternion.Identity; + Vector3 angvel = Vector3.Zero; + + offset.FromBytes(data, 0); + vel.FromBytes(data, 12); + acc.FromBytes(data, 24); + q.FromBytes(data, 36, true); + angvel.FromBytes(data, 48); + + StringBuilder result = new StringBuilder(); + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "Offset", + offset, + "Vector3"); + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "Velocity", + vel, + "Vector3"); + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "Acceleration", + acc, + "Vector3"); + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "rotation", + q, + "Quaternion"); + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "Omega", + angvel, + "Vector3"); + return result.ToString(); + } + else + { + return Utils.BytesToHexString((byte[])fieldData, String.Format("{0,30}", fieldName)); + } + } + + private static string DecodeObjectTextureAnim(string fieldName, object fieldData) + { + StringBuilder result = new StringBuilder(); + Primitive.TextureAnimation TextureAnim; + if (fieldData is Primitive.TextureAnimation) + TextureAnim = (Primitive.TextureAnimation)fieldData; + else + TextureAnim = new Primitive.TextureAnimation((byte[])fieldData, 0); + + result.AppendFormat("{0,30}", " " + Environment.NewLine); + GenericTypeDecoder(TextureAnim, ref result); + result.AppendFormat("{0,30}", ""); + + return result.ToString(); + } + + private static string DecodeEstateParameter(string fieldName, object fieldData) + { + byte[] bytes = (byte[])fieldData; + + if (bytes.Length == 17) + { + return String.Format("{0,30}: {1,-40} [UUID]", fieldName, new UUID((byte[])fieldData, 0)); + } + else + { + return String.Format("{0,30}: {1,-40} [Byte[]]", fieldName, Utils.BytesToString((byte[])fieldData)); + } + } + + private static string DecodeNameValue(string fieldName, object fieldData) + { + NameValue[] nameValues = null; + if (fieldData is NameValue[]) + nameValues = fieldData as NameValue[]; + else + { + string nameValue = Utils.BytesToString((byte[])fieldData); + if (nameValue.Length > 0) + { + string[] lines = nameValue.Split('\n'); + nameValues = new NameValue[lines.Length]; + + for (int i = 0; i < lines.Length; i++) + { + if (!String.IsNullOrEmpty(lines[i])) + { + NameValue nv = new NameValue(lines[i]); + nameValues[i] = nv; + } + } + } + } + StringBuilder result = new StringBuilder(); + result.AppendFormat("{0,30}", " " + Environment.NewLine); + if (nameValues != null) + { + for (int i = 0; i < nameValues.Length; i++) + { + result.AppendFormat( + "{0,30}: Name={1} Value={2} Class={3} Type={4} Sendto={5}" + Environment.NewLine, "NameValue", + nameValues[i].Name, nameValues[i].Value, nameValues[i].Class, nameValues[i].Type, nameValues[i].Sendto); + } + } + result.AppendFormat("{0,30}", ""); + return result.ToString(); + } + + private static string DecodeObjectExtraParams(string fieldName, object fieldData) + { + + byte[] data = (byte[])fieldData; + + int i = 0; + //int totalLength = 1; + + Primitive.FlexibleData Flexible = null; + Primitive.LightData Light = null; + Primitive.SculptData Sculpt = null; + Primitive.SculptData Mesh = null; + Primitive.ReflectionProbe rprobe = null; + Primitive.RenderMaterials RenderMaterials = null; + uint meshFlags = 0; + bool hasmeshFlags = false; + + byte extraParamCount = data[i++]; + + for (int k = 0; k < extraParamCount; k++) + { + ExtraParamType type = (ExtraParamType)Utils.BytesToUInt16(data, i); + i += 2; + + int paramLength = (int)Utils.BytesToUInt(data, i); + i += 4; + + if (type == ExtraParamType.Flexible) + Flexible = new Primitive.FlexibleData(data, i); + else if (type == ExtraParamType.Light) + Light = new Primitive.LightData(data, i); + else if (type == ExtraParamType.Sculpt) + Sculpt = new Primitive.SculptData(data, i); + else if (type == ExtraParamType.Mesh) + Mesh = new Primitive.SculptData(data, i); + else if (type == ExtraParamType.MeshFlag) + { + hasmeshFlags = true; + meshFlags = Utils.BytesToUInt(data, i); + } + else if (type == ExtraParamType.RenderMaterial) + { + RenderMaterials = new Primitive.RenderMaterials(data, i, paramLength); + } + else if (type == ExtraParamType.ReflectionProbe) + { + rprobe = new Primitive.ReflectionProbe(data, i); + } + + i += paramLength; + //totalLength += (int)paramLength + 6; + } + + StringBuilder result = new StringBuilder(); + result.AppendFormat("{0,30}", "" + Environment.NewLine); + if (Flexible != null) + { + result.AppendFormat("{0,30}", "" + Environment.NewLine); + GenericTypeDecoder(Flexible, ref result); + result.AppendFormat("{0,30}", "" + Environment.NewLine); + } + + if (Sculpt != null) + { + result.AppendFormat("{0,30}", "" + Environment.NewLine); + GenericTypeDecoder(Sculpt, ref result); + result.AppendFormat("{0,30}", "" + Environment.NewLine); + } + + if (Mesh != null) + { + result.AppendFormat("{0,30}", "" + Environment.NewLine); + GenericTypeDecoder(Mesh, ref result); + result.AppendFormat("{0,30}", "" + Environment.NewLine); + } + + if (Light != null) + { + result.AppendFormat("{0,30}", "" + Environment.NewLine); + GenericTypeDecoder(Light, ref result); + result.AppendFormat("{0,30}", "" + Environment.NewLine); + } + + if (hasmeshFlags) + { + result.AppendFormat("{0,30}", "" + Environment.NewLine); + result.AppendFormat("{0,30}", meshFlags.ToString() + Environment.NewLine); + result.AppendFormat("{0,30}", "" + Environment.NewLine); + } + if (rprobe != null) + { + result.AppendFormat("{0,30}", "" + Environment.NewLine); + GenericTypeDecoder(rprobe, ref result); + result.AppendFormat("{0,30}", "" + Environment.NewLine); + } + if (RenderMaterials != null) + { + result.AppendFormat("{0,30}", "" + Environment.NewLine); + GenericTypeDecoder(RenderMaterials, ref result); + result.AppendFormat("{0,30}", "" + Environment.NewLine); + } + + result.AppendFormat("{0,30}", ""); + return result.ToString(); + } + + private static string DecodeObjectParticleSystem(string fieldName, object fieldData) + { + StringBuilder result = new StringBuilder(); + Primitive.ParticleSystem ParticleSys; + if (fieldData is Primitive.ParticleSystem) + ParticleSys = (Primitive.ParticleSystem)fieldData; + else + ParticleSys = new Primitive.ParticleSystem((byte[])fieldData, 0); + + result.AppendFormat("{0,30}", "" + Environment.NewLine); + GenericTypeDecoder(ParticleSys, ref result); + result.AppendFormat("{0,30}", ""); + + return result.ToString(); + } + + private static void GenericTypeDecoder(object obj, ref StringBuilder result) + { + FieldInfo[] fields = obj.GetType().GetFields(); + + foreach (FieldInfo field in fields) + { + String special; + if (SpecialDecoder("a" + "." + "b" + "." + field.Name, + field.GetValue(obj), out special)) + { + result.AppendLine(special); + } + else + { + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + field.Name, + field.GetValue(obj), + field.FieldType.Name); + } + } + } + + private static string DecodeObjectPCode(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-3} {2,-36} [PCode]", + fieldName, + fieldData, + "(" + (PCode)(byte)fieldData + ")"); + } + + private static string DecodeImageType(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-3} {2,-36} [ImageType]", + fieldName, + fieldData, + "(" + (ImageType)(byte)fieldData + ")"); + } + + private static string DecodeImageCodec(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-3} {2,-36} [ImageCodec]", + fieldName, + fieldData, + "(" + (ImageCodec)(byte)fieldData + ")"); + } + + private static string DecodeObjectMaterial(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-3} {2,-36} [Material]", + fieldName, + fieldData, + "(" + (Material)(byte)fieldData + ")"); + } + + private static string DecodeObjectClickAction(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-3} {2,-36} [ClickAction]", + fieldName, + fieldData, + "(" + (ClickAction)(byte)fieldData + ")"); + } + + private static string DecodeEventFlags(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-3} {2,-36} [EventFlags]", + fieldName, + fieldData, + "(" + (DirectoryManager.EventFlags)(uint)fieldData + ")"); + } + + private static string DecodeDirQueryFlags(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-10} {2,-29} [DirectoryManager.DirFindFlags]", + fieldName, + fieldData, + "(" + (DirectoryManager.DirFindFlags)(uint)fieldData + ")"); + } + + private static string DecodeDirClassifiedQueryFlags(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-10} {2,-29} [ClassifiedQueryFlags]", + fieldName, + fieldData, + "(" + (DirectoryManager.ClassifiedQueryFlags)(uint)fieldData + ")"); + } + + private static string DecodeDirClassifiedFlags(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-10} {2,-29} [ClassifiedFlags]", + fieldName, + fieldData, + "(" + (DirectoryManager.ClassifiedFlags)(byte)fieldData + ")"); + } + + private static string DecodeGroupPowers(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-20} {2,-19} [GroupPowers]", + fieldName, + fieldData, + "(" + (GroupPowers)(ulong)fieldData + ")"); + } + + private static string DecodeParcelACL(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-10} {2,-29} [AccessList]", + fieldName, + fieldData, + "(" + (AccessList)(uint)fieldData + ")"); + } + + private static string SearchTypeFlags(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-10} {2,-29} [DirectoryManager.SearchTypeFlags]", + fieldName, + fieldData, + "(" + (DirectoryManager.SearchTypeFlags)(uint)fieldData + ")"); + } + + private static string DecodeCategory(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-3} {2,-36} [ParcelCategory]", + fieldName, + fieldData, + "(" + fieldData + ")"); + } + + private static string DecodeObjectUpdateFlags(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-10} {2,-29} [PrimFlags]", + fieldName, + fieldData, + "(" + (PrimFlags)(uint)fieldData + ")"); + } + + private static string DecodeTeleportFlags(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-10} {2,-29} [TeleportFlags]", + fieldName, + fieldData, + "(" + (TeleportFlags)(uint)fieldData + ")"); + } + + private static string DecodeScriptControls(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-10} {2,-29} [AgentManager.ControlFlags]", + fieldName, + (uint)fieldData, + "(" + (AgentManager.ControlFlags)(uint)fieldData + ")"); + } + + private static string DecodeColorField(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-40} [Color4]", + fieldName, + fieldData.GetType().Name.Equals("Color4") ? (Color4)fieldData : new Color4((byte[])fieldData, 0, false)); + } + + private static string DecodeTimeStamp(string fieldName, object fieldData) + { + if (fieldData is Int32 && (int)fieldData > 0) + return String.Format("{0,30}: {1,-10} {2,-29} [{3}]", + fieldName, + fieldData, + "(" + Utils.UnixTimeToDateTime((int)fieldData) + ")", + fieldData.GetType().Name); + else if (fieldData is uint && (uint)fieldData > 0) + return String.Format("{0,30}: {1,-10} {2,-29} [{3}]", + fieldName, + fieldData, + "(" + Utils.UnixTimeToDateTime((uint)fieldData) + ")", + fieldData.GetType().Name); + else + return String.Format("{0,30}: {1,-40} [{2}]", + fieldName, + fieldData, + fieldData.GetType().Name); + } + + private static string DecodeBinaryBucket(string fieldName, object fieldData) + { + byte[] bytes = (byte[])fieldData; + string bucket = String.Empty; + if (bytes.Length == 1) + { + bucket = String.Format("{0}", bytes[0]); + } + else if (bytes.Length == 17) + { + bucket = String.Format("{0,-36} {1} ({2})", + new UUID(bytes, 1), + bytes[0], + (AssetType)(sbyte)bytes[0]); + } + else if (bytes.Length == 16) // the folder ID for the asset to be stored into if we accept an inventory offer + { + bucket = new UUID(bytes, 0).ToString(); + } + else + { + bucket = Utils.BytesToString(bytes); // we'll try a string lastly + } + + return String.Format("{0,30}: {1,-40} [Byte[{2}]]", fieldName, bucket, bytes.Length); + } + + private static string DecodeBinaryToHexString(string fieldName, object fieldData) + { + return String.Format("{0,30}", + Utils.BytesToHexString((byte[])fieldData, + String.Format("{0,30}", fieldName))); + } + + private static string DecodeWearableType(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [WearableType]", + fieldName, + (byte)fieldData, + "(" + (WearableType)fieldData + ")"); + } + + private static string DecodeInventoryType(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [AssetType]", + fieldName, + (sbyte)fieldData, + "(" + (AssetType)(sbyte)fieldData + ")"); + } + + private static string DecodeInventorySort(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [InventorySortOrder]", + fieldName, + fieldData, + "(" + (InventorySortOrder)(int)fieldData + ")"); + } + + private static string DecodeInventoryInvType(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [InventoryType]", + fieldName, + (sbyte)fieldData, + "(" + (InventoryType)fieldData + ")"); + } + + private static string DecodeFolderType(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [Folderype]", + fieldName, + (sbyte)fieldData, + "(" + (FolderType)fieldData + ")"); + } + + private static string DecodeInventoryFlags(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [InventoryItemFlags]", + fieldName, + (uint)fieldData, + "(" + (InventoryItemFlags)(uint)fieldData + ")"); + } + + private static string DecodeObjectSaleType(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [SaleType]", + fieldName, + (byte)fieldData, + "(" + (SaleType)fieldData + ")"); + } + + private static string DecodeRegionFlags(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [RegionFlags]", + fieldName, + fieldData, + "(" + (RegionFlags)(uint)fieldData + ")"); + } + + private static string DecodeTransferParams(string fieldName, object fieldData) + { + byte[] paramData = (byte[])fieldData; + StringBuilder result = new StringBuilder(); + result.AppendLine(" "); + if (paramData.Length == 20) + { + result.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine, + "AssetID", + new UUID(paramData, 0)); + + result.AppendFormat("{0,30}: {1,-2} {2,-37} [AssetType]" + Environment.NewLine, + "AssetType", + (sbyte)paramData[16], + "(" + (AssetType)(sbyte)paramData[16] + ")"); + + } + else if (paramData.Length == 100) + { + //UUID agentID = new UUID(info.TransferInfo.Params, 0); + result.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine, + "AgentID", + new UUID(paramData, 0)); + + //UUID sessionID = new UUID(info.TransferInfo.Params, 16); + result.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine, + "SessionID", + new UUID(paramData, 16)); + //UUID ownerID = new UUID(info.TransferInfo.Params, 32); + result.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine, + "OwnerID", + new UUID(paramData, 32)); + //UUID taskID = new UUID(info.TransferInfo.Params, 48); + result.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine, + "TaskID", + new UUID(paramData, 48)); + //UUID itemID = new UUID(info.TransferInfo.Params, 64); + result.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine, + "ItemID", + new UUID(paramData, 64)); + + result.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine, + "AssetID", + new UUID(paramData, 80)); + + result.AppendFormat("{0,30}: {1,-2} {2,-37} [AssetType]" + Environment.NewLine, + "AssetType", + (sbyte)paramData[96], + "(" + (AssetType)(sbyte)paramData[96] + ")"); + } + else + { + Console.WriteLine("Oh Poop!"); + } + + result.Append(""); + + return result.ToString(); + } + + private static string DecodeTransferChannelType(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [ChannelType]", + fieldName, + fieldData, + "(" + (ChannelType)(int)fieldData + ")"); + } + + private static string DecodeTransferSourceType(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [SourceType]", + fieldName, + fieldData, + "(" + (SourceType)(int)fieldData + ")"); + } + + private static string DecodeTransferTargetType(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [TargetType]", + fieldName, + fieldData, + "(" + (TargetType)(int)fieldData + ")"); + } + + private static string DecodeMapRequestFlags(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [GridLayerType]", + fieldName, + fieldData, + "(" + (GridLayerType)(uint)fieldData + ")"); + } + + private static string DecodeGridItemType(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [GridItemType]", + fieldName, + fieldData, + "(" + (GridItemType)(uint)fieldData + ")"); + + } + + private static string DecodeLayerDataType(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [LayerType]", + fieldName, + fieldData, + "(" + (TerrainPatch.LayerType)(byte)fieldData + ")"); + } + + private static string DecodeMapAccess(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [SimAccess]", + fieldName, + fieldData, + "(" + (SimAccess)(byte)fieldData + ")"); + } + + private static string DecodeSimAccess(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [SimAccess]", + fieldName, + (byte)fieldData, + "(" + (SimAccess)fieldData + ")"); + } + + private static string DecodeAttachedSoundFlags(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [SoundFlags]", + fieldName, + (byte)fieldData, + "(" + (SoundFlags)fieldData + ")"); + } + + + private static string DecodeChatSourceType(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [SourceType]", + fieldName, + fieldData, + "(" + (SourceType)(byte)fieldData + ")"); + } + + private static string DecodeChatChatType(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [ChatType]", + fieldName, + (byte)fieldData, + "(" + (ChatType)fieldData + ")"); + } + + private static string DecodeChatAudible(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [ChatAudibleLevel]", + fieldName, + (byte)fieldData, + "(" + (ChatAudibleLevel)(byte)fieldData + ")"); + } + + private static string DecodeImageData(string fieldName, object fieldData) + { + return String.Format("{0,10}", + Utils.BytesToHexString((byte[])fieldData, + String.Format("{0,30}", fieldName))); + } + + private static string DecodeTerseTextureEntry(string fieldName, object fieldData) + { + byte[] block = (byte[])fieldData; + + Primitive.TextureEntry te = new Primitive.TextureEntry(block, 4, block.Length - 4); + + StringBuilder result = new StringBuilder(); + + result.AppendFormat("{0,30}", " " + Environment.NewLine); + if (te.DefaultTexture != null) + { + result.AppendFormat("{0,30}", " " + Environment.NewLine); + GenericFieldsDecoder(te.DefaultTexture, ref result); + GenericPropertiesDecoder(te.DefaultTexture, ref result); + result.AppendFormat("{0,30}", " " + Environment.NewLine); + } + result.AppendFormat("{0,30}", " " + Environment.NewLine); + for (int i = 0; i < te.FaceTextures.Length; i++) + { + if (te.FaceTextures[i] != null) + { + result.AppendFormat("{0,30}[{1}]" + Environment.NewLine, "FaceTexture", i); + GenericFieldsDecoder(te.FaceTextures[i], ref result); + GenericPropertiesDecoder(te.FaceTextures[i], ref result); + } + } + result.AppendFormat("{0,30}", " " + Environment.NewLine); + result.AppendFormat("{0,30}", ""); + + return result.ToString(); + } + + private static string DecodeTextureEntry(string fieldName, object fieldData) + { + Primitive.TextureEntry te; + if (fieldData is Primitive.TextureEntry) + te = (Primitive.TextureEntry)fieldData; + else + { + byte[] tebytes = (byte[])fieldData; + te = new Primitive.TextureEntry(tebytes, 0, tebytes.Length); + } + + StringBuilder result = new StringBuilder(); + + result.AppendFormat("{0,30}", " " + Environment.NewLine); + if (te.DefaultTexture != null) + { + result.AppendFormat("{0,30}", " " + Environment.NewLine); + GenericFieldsDecoder(te.DefaultTexture, ref result); + GenericPropertiesDecoder(te.DefaultTexture, ref result); + result.AppendFormat("{0,30}", " " + Environment.NewLine); + } + result.AppendFormat("{0,30}", " " + Environment.NewLine); + for (int i = 0; i < te.FaceTextures.Length; i++) + { + if (te.FaceTextures[i] != null) + { + result.AppendFormat("{0,30}[{1}]" + Environment.NewLine, "FaceTexture", i); + GenericFieldsDecoder(te.FaceTextures[i], ref result); + GenericPropertiesDecoder(te.FaceTextures[i], ref result); + } + } + result.AppendFormat("{0,30}", " " + Environment.NewLine); + result.AppendFormat("{0,30}", ""); + + return result.ToString(); + } + + private static void GenericFieldsDecoder(object obj, ref StringBuilder result) + { + Type parcelType = obj.GetType(); + FieldInfo[] fields = parcelType.GetFields(); + foreach (FieldInfo field in fields) + { + String special; + if (SpecialDecoder("a" + "." + "b" + "." + field.Name, + field.GetValue(obj), out special)) + { + result.AppendLine(special); + } + else + { + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + field.Name, + field.GetValue(obj), + field.FieldType.Name); + } + } + } + + private static void GenericPropertiesDecoder(object obj, ref StringBuilder result) + { + Type parcelType = obj.GetType(); + PropertyInfo[] propertyInfos = parcelType.GetProperties(); + foreach (PropertyInfo property in propertyInfos) + { + String special; + if (SpecialDecoder("a" + "." + "b" + "." + property.Name, + property.GetValue(obj, null), out special)) + { + result.AppendLine(special); + } + else + { + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + property.Name, + property.GetValue(obj, null), + property.PropertyType.Name); + } + } + } + + private static string DecodeDialog(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [{3}]", + fieldName, + (byte)fieldData, + "(" + (InstantMessageDialog)fieldData + ")", + fieldData.GetType().Name); + } + + private static string DecodeControlFlags(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-10} {2,-29} [{3}]", + fieldName, + fieldData, + "(" + (AgentManager.ControlFlags)(uint)fieldData + ")", + fieldData.GetType().Name); + } + + private static string DecodePermissionMask(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-10} {2,-29} [{3}]", + fieldName, + (uint)fieldData, + "(" + (PermissionMask)fieldData + ")", + fieldData.GetType().Name); + } + + private static string DecodeViewerEffectTypeData(string fieldName, object fieldData) + { + byte[] data = (byte[])fieldData; + StringBuilder sb = new StringBuilder(); + if (data.Length == 56 || data.Length == 57) + { + UUID sourceAvatar = new UUID(data, 0); + UUID targetObject = new UUID(data, 16); + Vector3d targetPos = new Vector3d(data, 32); + sb.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine, fieldName, "Source AvatarID=" + sourceAvatar); + sb.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine, fieldName, "Target ObjectID=" + targetObject); + + + float lx, ly; + Helpers.GlobalPosToRegionHandle((float)targetPos.X, (float)targetPos.Y, out lx, out ly); + + sb.AppendFormat("{0,30}: {1,-40} [Vector3d]", fieldName, targetPos); + + if (data.Length == 57) + { + sb.AppendLine(); + sb.AppendFormat("{0,30}: {1,-17} {2,-22} [Byte]", fieldName, "Point At Type=" + data[56], + "(" + (PointAtType)data[56] + ")"); + } + + return sb.ToString(); + } + else + { + return String.Format("{0,30}: (No Decoder) Length={1}" + Environment.NewLine, fieldName, data.Length) + Utils.BytesToHexString(data, String.Format("{0,30}", "")); + } + } + + private static string DecodeAgentState(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [AgentState]", + fieldName, + fieldData, + "(" + (AgentState)(byte)fieldData + ")"); + } + + private static string DecodeAgentFlags(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [AgentFlags]", + fieldName, + fieldData, + "(" + (AgentFlags)(byte)fieldData + ")"); + } + + private static string DecodeObjectState(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [AttachmentPoint]", + fieldName, + fieldData, + "(" + (AttachmentPoint)(byte)fieldData + ")"); + } + + private static string DecodeViewerEffectType(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [{3}]", + fieldName, + fieldData, + "(" + (EffectType)(byte)fieldData + ")", + fieldData.GetType().Name); + } + + private static string DecodeAnimToConst(string fieldName, object fieldData) + { + string animConst = "UUID"; + Dictionary animsDict = Animations.ToDictionary(); + if (animsDict.ContainsKey((UUID)fieldData)) + animConst = animsDict[(UUID)fieldData]; + return String.Format("{0,30}: {1,-40} [{2}]", + fieldName, + fieldData, + animConst); + } + #endregion + + /// + /// Creates a formatted string containing the values of a Packet + /// + /// The Packet + /// A formatted string of values of the nested items in the Packet object + public static string PacketToString(Packet packet) + { + StringBuilder result = new StringBuilder(); + + result.AppendFormat("Packet Type: {0}" + Environment.NewLine, packet.Type); + result.AppendLine("[Packet Header]"); + // payload + result.AppendFormat("Sequence: {0}" + Environment.NewLine, packet.Header.Sequence); + result.AppendFormat(" Options: {0}" + Environment.NewLine, InterpretOptions(packet.Header)); + result.AppendLine(); + + result.AppendLine("[Packet Payload]"); + + FieldInfo[] fields = packet.GetType().GetFields(); + + for (int i = 0; i < fields.Length; i++) + { + // we're not interested in any of these here + if (fields[i].Name == "Type" || fields[i].Name == "Header" || fields[i].Name == "HasVariableBlocks") + continue; + + if (fields[i].FieldType.IsArray) + { + result.AppendFormat("{0,30} []" + Environment.NewLine, "-- " + fields[i].Name + " --"); + RecursePacketArray(fields[i], packet, ref result); + } + else + { + result.AppendFormat("{0,30}" + Environment.NewLine, "-- " + fields[i].Name + " --"); + RecursePacketField(fields[i], packet, ref result); + } + } + return result.ToString(); + } + + public static string InterpretOptions(Header header) + { + return "[" + + (header.AppendedAcks ? "Ack" : " ") + + " " + + (header.Resent ? "Res" : " ") + + " " + + (header.Reliable ? "Rel" : " ") + + " " + + (header.Zerocoded ? "Zer" : " ") + + "]" + ; + } + + private static void RecursePacketArray(FieldInfo fieldInfo, object packet, ref StringBuilder result) + { + var packetDataObject = fieldInfo.GetValue(packet); + int k = -1; + foreach (object nestedArrayRecord in packetDataObject as Array) + { + FieldInfo[] fields = nestedArrayRecord.GetType().GetFields(); + ++k; + for (int i = 0; i < fields.Length; i++) + { + String special; + if (SpecialDecoder(packet.GetType().Name + "." + fieldInfo.Name + "." + fields[i].Name, + fields[i].GetValue(nestedArrayRecord), out special)) + { + result.AppendLine(special); + } + else if (fields[i].FieldType.IsArray) // default for an array (probably a byte[]) + { + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + fields[i].Name + "[" + k.ToString() + "]", + Utils.BytesToString((byte[])fields[i].GetValue(nestedArrayRecord)), + /*fields[i].GetValue(nestedArrayRecord).GetType().Name*/ "String"); + } + else // default for a field + { + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + fields[i].Name + "[" + k.ToString() + "]", + fields[i].GetValue(nestedArrayRecord), + fields[i].GetValue(nestedArrayRecord).GetType().Name); + } + } + + // Handle Properties + foreach (PropertyInfo propertyInfo in nestedArrayRecord.GetType().GetProperties()) + { + if (propertyInfo.Name.Equals("Length")) + continue; + + string special; + if (SpecialDecoder(packet.GetType().Name + "." + fieldInfo.Name + "." + propertyInfo.Name, + propertyInfo.GetValue(nestedArrayRecord, null), + out special)) + { + result.AppendLine(special); + } + else + { + var p = propertyInfo.GetValue(nestedArrayRecord, null); + /* Leave the c for now at the end, it signifies something useful that still needs to be done i.e. a decoder written */ + result.AppendFormat("{0, 30}: {1,-40} [{2}]c" + Environment.NewLine, + propertyInfo.Name, + Utils.BytesToString((byte[])propertyInfo.GetValue(nestedArrayRecord, null)), + propertyInfo.PropertyType.Name); + } + } + result.AppendFormat("{0,32}" + Environment.NewLine, "***"); + } + } + + private static void RecursePacketField(FieldInfo fieldInfo, object packet, ref StringBuilder result) + { + object packetDataObject = fieldInfo.GetValue(packet); + + // handle Fields + foreach (FieldInfo packetValueField in fieldInfo.GetValue(packet).GetType().GetFields()) + { + string special; + if (SpecialDecoder(packet.GetType().Name + "." + fieldInfo.Name + "." + packetValueField.Name, + packetValueField.GetValue(packetDataObject), + out special)) + { + result.AppendLine(special); + } + else if (packetValueField.FieldType.IsArray) + { + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + packetValueField.Name, + Utils.BytesToString((byte[])packetValueField.GetValue(packetDataObject)), + /*packetValueField.FieldType.Name*/ "String"); + } + else + { + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + packetValueField.Name, packetValueField.GetValue(packetDataObject), packetValueField.FieldType.Name); + + } + } + + // Handle Properties + foreach (PropertyInfo propertyInfo in packetDataObject.GetType().GetProperties()) + { + if (propertyInfo.Name.Equals("Length")) + continue; + + string special; + if (SpecialDecoder(packet.GetType().Name + "." + fieldInfo.Name + "." + propertyInfo.Name, + propertyInfo.GetValue(packetDataObject, null), + out special)) + { + result.AppendLine(special); + } + else if (propertyInfo.GetValue(packetDataObject, null).GetType() == typeof(byte[])) + { + result.AppendFormat("{0, 30}: {1,-40} [{2}]" + Environment.NewLine, + propertyInfo.Name, + Utils.BytesToString((byte[])propertyInfo.GetValue(packetDataObject, null)), + propertyInfo.PropertyType.Name); + } + else + { + result.AppendFormat("{0, 30}: {1,-40} [{2}]" + Environment.NewLine, + propertyInfo.Name, + propertyInfo.GetValue(packetDataObject, null), + propertyInfo.PropertyType.Name); + } + } + } + + private static bool SpecialDecoder(string decoderKey, object fieldData, out string result) + { + result = string.Empty; + string[] keys = decoderKey.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries); + string[] keyList = { decoderKey, decoderKey.Replace("Packet", ""), keys[1] + "." + keys[2], keys[2] }; + foreach (string key in keyList) + { + + bool ok = true; + if (fieldData is byte[]) + { + byte[] fd = (byte[])fieldData; + ok = fd.Length > 0; + if (!ok) + { + // bypass the decoder since we were passed an empty byte array + result = String.Format("{0,30}:", keys[2]); + return true; + } + } + + if (ok && Callbacks.ContainsKey(key)) // fieldname e.g: Plane + { + foreach (CustomPacketDecoder decoder in Callbacks[key]) + result = decoder(keys[2], fieldData); + return true; + } + } + return false; + } + + /// + /// Decode an IMessage object into a beautifully formatted string + /// + /// The IMessage object + /// Recursion level (used for indenting) + /// A formatted string containing the names and values of the source object + public static string MessageToString(object message, int recurseLevel) + { + if (message == null) + return String.Empty; + + StringBuilder result = new StringBuilder(); + // common/custom types + if (recurseLevel <= 0) + { + result.AppendFormat("Message Type: {0}" + Environment.NewLine, message.GetType().Name); + } + else + { + string pad = " +--".PadLeft(recurseLevel + 3); + result.AppendFormat("{0} {1}" + Environment.NewLine, pad, message.GetType().Name); + } + + recurseLevel++; + + foreach (FieldInfo messageField in message.GetType().GetFields()) + { + // an abstract message class + if (messageField.FieldType.IsAbstract) + { + result.AppendLine(MessageToString(messageField.GetValue(message), recurseLevel)); + } + // a byte array + else if (messageField.GetValue(message) != null && messageField.GetValue(message).GetType() == typeof(Byte[])) + { + result.AppendFormat("{0, 30}:" + Environment.NewLine, messageField.Name); + + result.AppendFormat("{0}" + Environment.NewLine, + Utils.BytesToHexString((byte[])messageField.GetValue(message), + String.Format("{0,30}", ""))); + } + + // an array of class objects + else if (messageField.FieldType.IsArray) + { + var messageObjectData = messageField.GetValue(message); + result.AppendFormat("-- {0} --" + Environment.NewLine, messageField.FieldType.Name); + foreach (object nestedArrayObject in messageObjectData as Array) + { + if (nestedArrayObject == null) + { + result.AppendFormat("{0,30}" + Environment.NewLine, "-- null --"); + continue; + } + else + { + result.AppendFormat("{0,30}" + Environment.NewLine, "-- " + nestedArrayObject.GetType().Name + " --"); + } + foreach (FieldInfo nestedField in nestedArrayObject.GetType().GetFields()) + { + if (nestedField.FieldType.IsEnum) + { + result.AppendFormat("{0,30}: {1,-10} {2,-29} [{3}]" + Environment.NewLine, + nestedField.Name, + Enum.Format(nestedField.GetValue(nestedArrayObject).GetType(), + nestedField.GetValue(nestedArrayObject), "D"), + "(" + nestedField.GetValue(nestedArrayObject) + ")", + nestedField.GetValue(nestedArrayObject).GetType().Name); + } + else if (nestedField.FieldType.IsInterface) + { + result.AppendLine(MessageToString(nestedField.GetValue(nestedArrayObject), recurseLevel)); + } + else + { + result.AppendFormat("{0, 30}: {1,-40} [{2}]" + Environment.NewLine, + nestedField.Name, + nestedField.GetValue(nestedArrayObject), + nestedField.FieldType.Name); + } + } + } + } + else + { + if (messageField.FieldType.IsEnum) + { + result.AppendFormat("{0,30}: {1,-2} {2,-37} [{3}]" + Environment.NewLine, + messageField.Name, + Enum.Format(messageField.GetValue(message).GetType(), + messageField.GetValue(message), "D"), + "(" + messageField.GetValue(message) + ")", + messageField.FieldType.Name); + } + else if (messageField.FieldType.IsInterface) + { + result.AppendLine(MessageToString(messageField.GetValue(message), recurseLevel)); + } + else + { + result.AppendFormat("{0, 30}: {1,-40} [{2}]" + Environment.NewLine, + messageField.Name, messageField.GetValue(message), messageField.FieldType.Name); + } + } + } + + return result.ToString(); + } + } +} diff --git a/OpenMetaverse/Primitives/Primitive.cs b/OpenMetaverse/Primitives/Primitive.cs index cbccd7ec..b9430a6f 100644 --- a/OpenMetaverse/Primitives/Primitive.cs +++ b/OpenMetaverse/Primitives/Primitive.cs @@ -24,8 +24,9 @@ * POSSIBILITY OF SUCH DAMAGE. */ -using OpenMetaverse.StructuredData; using System; +using System.Collections.Generic; +using OpenMetaverse.StructuredData; namespace OpenMetaverse { @@ -33,11 +34,17 @@ public partial class Primitive : IEquatable { // Used for packing and unpacking parameters protected const float CUT_QUANTA = 0.00002f; + protected const float CUT_QUANTAINV = 1.0f / CUT_QUANTA; protected const float SCALE_QUANTA = 0.01f; + protected const float SCALE_QUANTAINV = 1-0f/ SCALE_QUANTA; protected const float SHEAR_QUANTA = 0.01f; + protected const float SHEAR_QUANTAINV = 1.0f / SHEAR_QUANTA; protected const float TAPER_QUANTA = 0.01f; + protected const float TAPER_QUANTAINV = 1.0f / TAPER_QUANTA; protected const float REV_QUANTA = 0.015f; + protected const float REV_QUANTAINV = 1.0f / REV_QUANTA; protected const float HOLLOW_QUANTA = 0.00002f; + protected const float HOLLOW_QUANTAINV = 1.0f / HOLLOW_QUANTA; #region Subclasses @@ -129,7 +136,7 @@ public Vector2 PathBeginScale { get { - Vector2 begin = new Vector2(1f, 1f); + Vector2 begin = new(1f, 1f); if (PathScaleX > 1f) begin.X = 2f - PathScaleX; if (PathScaleY > 1f) @@ -143,7 +150,7 @@ public Vector2 PathEndScale { get { - Vector2 end = new Vector2(1f, 1f); + Vector2 end = new(1f, 1f); if (PathScaleX < 1f) end.X = PathScaleX; if (PathScaleY < 1f) @@ -267,14 +274,15 @@ public byte[] GetBytes() /// public OSD GetOSD() { - OSDMap map = new OSDMap(); - - map["simulate_lod"] = OSD.FromInteger(Softness); - map["gravity"] = OSD.FromReal(Gravity); - map["air_friction"] = OSD.FromReal(Drag); - map["wind_sensitivity"] = OSD.FromReal(Wind); - map["tension"] = OSD.FromReal(Tension); - map["user_force"] = OSD.FromVector3(Force); + OSDMap map = new() + { + ["simulate_lod"] = OSD.FromInteger(Softness), + ["gravity"] = OSD.FromReal(Gravity), + ["air_friction"] = OSD.FromReal(Drag), + ["wind_sensitivity"] = OSD.FromReal(Wind), + ["tension"] = OSD.FromReal(Tension), + ["user_force"] = OSD.FromVector3(Force) + }; return map; } @@ -382,13 +390,14 @@ public byte[] GetBytes() public OSD GetOSD() { - OSDMap map = new OSDMap(); - - map["color"] = OSD.FromColor4(Color); - map["intensity"] = OSD.FromReal(Intensity); - map["radius"] = OSD.FromReal(Radius); - map["cutoff"] = OSD.FromReal(Cutoff); - map["falloff"] = OSD.FromReal(Falloff); + OSDMap map = new() + { + ["color"] = OSD.FromColor4(Color), + ["intensity"] = OSD.FromReal(Intensity), + ["radius"] = OSD.FromReal(Radius), + ["cutoff"] = OSD.FromReal(Cutoff), + ["falloff"] = OSD.FromReal(Falloff) + }; return map; } @@ -485,10 +494,11 @@ public byte[] GetBytes() public OSD GetOSD() { - OSDMap map = new OSDMap(); - - map["texture"] = OSD.FromUUID(LightTexture); - map["params"] = OSD.FromVector3(Params); + OSDMap map = new() + { + ["texture"] = OSD.FromUUID(LightTexture), + ["params"] = OSD.FromVector3(Params) + }; return map; } @@ -519,7 +529,7 @@ public override int GetHashCode() /// public override string ToString() { - return String.Format("LightTexture: {0} Params; {1]", LightTexture, Params); + return String.Format("LightTexture: {0} Params; {1}", LightTexture, Params); } } @@ -551,7 +561,7 @@ public bool Invert public bool Mirror { get { return ((type & (byte)SculptType.Mirror) != 0); } - } + } /// /// Default constructor @@ -591,10 +601,11 @@ public byte[] GetBytes() public OSD GetOSD() { - OSDMap map = new OSDMap(); - - map["texture"] = OSD.FromUUID(SculptTexture); - map["type"] = OSD.FromInteger(type); + OSDMap map = new() + { + ["texture"] = OSD.FromUUID(SculptTexture), + ["type"] = OSD.FromInteger(type) + }; return map; } @@ -620,6 +631,236 @@ public override int GetHashCode() } } + /// + /// Information on the ReflectionProbe properties of a primitive + /// + public class ReflectionProbe + { + /// + /// Default constructor + /// + public ReflectionProbe() + { + } + + public float Ambiance = 0; + public float ClipDistance = 0; + public byte Flags = 0; + /// + /// + /// + /// + /// + public ReflectionProbe(byte[] data, int pos) + { + if (data.Length - pos >= 9) + { + Ambiance = Utils.Clamp(Utils.BytesToFloat(data, pos), 0, 1.0f); + ClipDistance = Utils.Clamp(Utils.BytesToFloat(data, pos + 4), 0, 1024f); + Flags = data[pos + 8]; + } + } + + /// + /// + /// + /// + public byte[] GetBytes() + { + byte[] data = new byte[9]; + Utils.FloatToBytes(Ambiance, data, 0); + Utils.FloatToBytes(ClipDistance, data, 4); + data[8] = Flags; + return data; + } + + public OSD GetOSD() + { + OSDMap map = new() + { + ["ambiance"] = OSD.FromReal(Ambiance), + ["clip_distance"] = OSD.FromReal(ClipDistance), + ["flags"] = OSD.FromInteger(Flags) + }; + return map; + } + + public static ReflectionProbe FromOSD(OSD osd) + { + ReflectionProbe probe = new ReflectionProbe(); + + if (osd.Type == OSDType.Map) + { + OSDMap map = (OSDMap)osd; + + probe.Ambiance = (float)map["ambiance"].AsReal(); + probe.ClipDistance = (float)map["clip_distance"].AsReal(); + probe.Flags = (byte)map["flags"].AsInteger(); + } + + return probe; + } + + public override int GetHashCode() + { + return Ambiance.GetHashCode() ^ ClipDistance.GetHashCode() ^ (int)Flags; + } + + /// + /// + /// + /// + public override string ToString() + { + return String.Format("ReflectionProbe: amb {0} clip {1} flags {2}", Ambiance, ClipDistance, Flags); + } + } + + /// + /// Information on the RenderMaterial properties of a primitive + /// + public class RenderMaterials + { + public struct RenderMaterialEntry : IComparable + { + public byte te_index; + public UUID id; + public int CompareTo(RenderMaterialEntry other) + { + return te_index.CompareTo(other.te_index); + } + } + + public struct RenderMaterialOverrideEntry : IComparable + { + public byte te_index; + public string data; + public int CompareTo(RenderMaterialEntry other) + { + return te_index.CompareTo(other.te_index); + } + } + + public RenderMaterialEntry[] entries = null; + public RenderMaterialOverrideEntry[] overrides = null; + + /// + /// Default constructor + /// + public RenderMaterials() + { + } + + /// + /// + /// + /// + /// + public RenderMaterials(byte[] data, int pos, int size) + { + if (size > 17) + { + int count = data[pos]; + ++pos; + if (size >= 1 + 17 * count) + { + entries = new RenderMaterialEntry[count]; + for (int i = 0; i < count; ++i) + { + entries[i].te_index = data[pos++]; + entries[i].id = new UUID(data, pos); + pos += 16; + } + } + } + } + + /// + /// + /// + /// + public byte[] GetBytes() + { + if (entries == null || entries.Length == 0) + { + return new byte[] {0}; + } + byte[] data = new byte[1 + 17 * entries.Length]; + data[0] = (byte)entries.Length; + int pos = 1; + for (int i = 0; i < entries.Length; ++i) + { + data[pos++] = entries[i].te_index; + entries[i].id.ToBytes(data, pos); + pos += 16; + } + return data; + } + + public OSD GetOSD() + { + OSDArray eMaterials = new OSDArray(); + if(entries != null) + { + for(int i = 0; i < entries.Length;++i) + { + OSDMap map = new OSDMap() + { + ["te_idx"] = OSD.FromInteger(entries[i].te_index), + ["id"] = OSD.FromUUID(entries[i].id) + }; + eMaterials[i] = map; + } + } + return eMaterials; + } + + public static RenderMaterials FromOSD(OSD osd) + { + RenderMaterials rm = new(); + try + { + if (osd.Type == OSDType.Array) + { + OSDArray mra = (OSDArray)osd; + if(mra.Count > 0) + { + RenderMaterialEntry[] entries = new RenderMaterialEntry[mra.Count]; + for(int i = 0; i < mra.Count; ++i) + { + OSDMap map = (OSDMap)mra[i]; + entries[i].te_index = (byte)map["te_idx"].AsInteger(); + entries[i].id = map["id"].AsUUID(); + } + rm.entries = entries; + } + } + } + catch + { + rm.entries = null; + } + return rm; + } + + public override int GetHashCode() + { + int h = entries.Length.GetHashCode(); + for(int i = 0 ; i < entries.Length; ++i) + h ^= (int)entries[i].te_index ^ entries[i].id.GetHashCode(); + return h; + } + + /// + /// + /// + /// + public override string ToString() + { + return String.Format("RenderMaterials: nentries {0}}", entries==null? 0:entries.Length); + } + } + /// /// Extended properties to describe an object /// @@ -983,7 +1224,7 @@ public Primitive(Primitive prim) TextColor = prim.TextColor; MediaURL = prim.MediaURL; Joint = prim.Joint; - JointPivot = prim.JointPivot; + JointPivot = prim.JointPivot; JointAxisOrAnchor = prim.JointAxisOrAnchor; if (prim.NameValues != null) { @@ -1148,10 +1389,10 @@ public static Primitive FromOSD(OSD osd) prim.Position = ((OSDArray)map["position"]).AsVector3(); prim.Rotation = ((OSDArray)map["rotation"]).AsQuaternion(); prim.Scale = ((OSDArray)map["scale"]).AsVector3(); - + if (map["flex"]) prim.Flexible = FlexibleData.FromOSD(map["flex"]); - + if (map["light"]) prim.Light = LightData.FromOSD(map["light"]); @@ -1162,7 +1403,7 @@ public static Primitive FromOSD(OSD osd) prim.Sculpt = SculptData.FromOSD(map["sculpt"]); prim.Textures = TextureEntry.FromOSD(map["textures"]); - + if (map["texture_anim"]) prim.TextureAnim = TextureAnimation.FromOSD(map["texture_anim"]); @@ -1412,22 +1653,22 @@ public override int GetHashCode() public static ushort PackBeginCut(float beginCut) { - return (ushort)Math.Round(beginCut / CUT_QUANTA); + return (ushort)MathF.Round(beginCut * CUT_QUANTAINV); } public static ushort PackEndCut(float endCut) { - return (ushort)(50000 - (ushort)Math.Round(endCut / CUT_QUANTA)); + return (ushort)(50000 - (ushort)MathF.Round(endCut * CUT_QUANTAINV)); } public static byte PackPathScale(float pathScale) { - return (byte)(200 - (byte)Math.Round(pathScale / SCALE_QUANTA)); + return (byte)(200 - (byte)MathF.Round(pathScale * SCALE_QUANTAINV)); } public static sbyte PackPathShear(float pathShear) { - return (sbyte)Math.Round(pathShear / SHEAR_QUANTA); + return (sbyte)MathF.Round(pathShear * SHEAR_QUANTAINV); } /// @@ -1438,22 +1679,22 @@ public static sbyte PackPathShear(float pathShear) /// Signed eight bit value containing the packed parameter public static sbyte PackPathTwist(float pathTwist) { - return (sbyte)Math.Round(pathTwist / SCALE_QUANTA); + return (sbyte)MathF.Round(pathTwist * SCALE_QUANTAINV); } public static sbyte PackPathTaper(float pathTaper) { - return (sbyte)Math.Round(pathTaper / TAPER_QUANTA); + return (sbyte)MathF.Round(pathTaper * TAPER_QUANTAINV); } public static byte PackPathRevolutions(float pathRevolutions) { - return (byte)Math.Round((pathRevolutions - 1f) / REV_QUANTA); + return (byte)MathF.Round((pathRevolutions - 1f) * REV_QUANTAINV); } public static ushort PackProfileHollow(float profileHollow) { - return (ushort)Math.Round(profileHollow / HOLLOW_QUANTA); + return (ushort)MathF.Round(profileHollow * HOLLOW_QUANTAINV); } #endregion Parameter Packing Methods diff --git a/OpenMetaverse/Rendering/Rendering.cs b/OpenMetaverse/Rendering/Rendering.cs index 9506eb5c..2c9f73d4 100644 --- a/OpenMetaverse/Rendering/Rendering.cs +++ b/OpenMetaverse/Rendering/Rendering.cs @@ -303,20 +303,14 @@ public static bool TryDecodeFromAsset(Primitive prim, AssetMesh meshAsset, Detai // Decode each individual face if (subMeshOsd is OSDMap) { - OSDMap subMeshMap = (OSDMap)subMeshOsd; - - // As per http://wiki.secondlife.com/wiki/Mesh/Mesh_Asset_Format, some Mesh Level - // of Detail Blocks (maps) contain just a NoGeometry key to signal there is no - // geometry for this submesh. - if (subMeshMap.ContainsKey("NoGeometry") && ((OSDBoolean)subMeshMap["NoGeometry"])) - continue; - Face oface = new Face(); oface.ID = faceNr; oface.Vertices = new List(); oface.Indices = new List(); oface.TextureFace = prim.Textures.GetFace((uint)faceNr); + OSDMap subMeshMap = (OSDMap)subMeshOsd; + Vector3 posMax; Vector3 posMin; diff --git a/Programs/AvatarPreview/AvatarPreview.csproj b/Programs/AvatarPreview/AvatarPreview.csproj index ca2e3d6e..2d0e5941 100644 --- a/Programs/AvatarPreview/AvatarPreview.csproj +++ b/Programs/AvatarPreview/AvatarPreview.csproj @@ -1,7 +1,8 @@  Local - net48 + net6.0-windows + true WinExe avatarpreview Millions Of Us @@ -11,9 +12,6 @@ True - - False - False ../../bin/Tao.OpenGl.dll diff --git a/Programs/AvatarPreview/GLMesh.cs b/Programs/AvatarPreview/GLMesh.cs index 27f08ee8..1dd8983b 100644 --- a/Programs/AvatarPreview/GLMesh.cs +++ b/Programs/AvatarPreview/GLMesh.cs @@ -109,6 +109,7 @@ public override void LoadMesh(string filename) } } + [Obsolete] public override void LoadLODMesh(int level, string filename) { LODMesh lod = new LODMesh(); diff --git a/Programs/Baker/Baker.csproj b/Programs/Baker/Baker.csproj index e836cf5a..66a006f6 100644 --- a/Programs/Baker/Baker.csproj +++ b/Programs/Baker/Baker.csproj @@ -1,16 +1,12 @@  Local - net48 + net6.0-windows + true WinExe True 1591,1574,0419,0618 - - - False - - diff --git a/Programs/GridImageUpload/GridImageUpload.csproj b/Programs/GridImageUpload/GridImageUpload.csproj index 6fc517f5..462eaa42 100644 --- a/Programs/GridImageUpload/GridImageUpload.csproj +++ b/Programs/GridImageUpload/GridImageUpload.csproj @@ -1,7 +1,8 @@  Local - net48 + net6.0-windows + true WinExe GridImageUpload Open Metaverse Foundation @@ -11,11 +12,6 @@ 1591,1574,0419,0618 True - - - False - - diff --git a/Programs/GridImageUpload/Properties/Resources.Designer.cs b/Programs/GridImageUpload/Properties/Resources.Designer.cs index f5a366c1..3f6b225b 100644 --- a/Programs/GridImageUpload/Properties/Resources.Designer.cs +++ b/Programs/GridImageUpload/Properties/Resources.Designer.cs @@ -1,17 +1,17 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:2.0.50727.42 +// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ -namespace GridImageUpload.Properties -{ - - +namespace GridImageUpload.Properties { + using System; + + /// /// A strongly-typed resource class, for looking up localized strings, etc. /// @@ -19,51 +19,43 @@ namespace GridImageUpload.Properties // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources - { - + internal class Resources { + private static global::System.Resources.ResourceManager resourceMan; - + private static global::System.Globalization.CultureInfo resourceCulture; - + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() - { + internal Resources() { } - + /// /// Returns the cached ResourceManager instance used by this class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager - { - get - { - if ((resourceMan == null)) - { + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("GridImageUpload.Properties.Resources", typeof(Resources).Assembly); resourceMan = temp; } return resourceMan; } } - + /// /// Overrides the current thread's CurrentUICulture property for all /// resource lookups using this strongly typed resource class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture - { - get - { + internal static global::System.Globalization.CultureInfo Culture { + get { return resourceCulture; } - set - { + set { resourceCulture = value; } } diff --git a/Programs/GridImageUpload/Properties/Settings.Designer.cs b/Programs/GridImageUpload/Properties/Settings.Designer.cs index 3c5c10ac..2f41626b 100644 --- a/Programs/GridImageUpload/Properties/Settings.Designer.cs +++ b/Programs/GridImageUpload/Properties/Settings.Designer.cs @@ -1,28 +1,24 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:2.0.50727.42 +// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ -namespace SLImageUpload.Properties -{ - - +namespace GridImageUpload.Properties { + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "8.0.0.0")] - internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase - { - + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.5.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); - - public static Settings Default - { - get - { + + public static Settings Default { + get { return defaultInstance; } } diff --git a/Programs/GridProxy/GridProxy.cs b/Programs/GridProxy/GridProxy.cs index ff1d182b..bad29d49 100644 --- a/Programs/GridProxy/GridProxy.cs +++ b/Programs/GridProxy/GridProxy.cs @@ -41,12 +41,15 @@ using System.Threading; using System.Xml; -using Nwc.XmlRpc; - using OpenMetaverse; using OpenMetaverse.Http; using OpenMetaverse.Packets; using OpenMetaverse.StructuredData; +using log4net; +using XmlRpcCore; +using System.Net.Security; +using System.Security.Cryptography.X509Certificates; +using System.Net.Http; namespace GridProxy { @@ -188,6 +191,8 @@ public class Proxy public ProxyConfig proxyConfig; private string loginURI; + private static readonly HttpClient HttpClient = new HttpClient(); + static List BinaryResponseCaps = new List() { "ViewerAsset", @@ -199,6 +204,23 @@ public class Proxy /* * Proxy Management */ + public static bool ValidateServerCertificate( + object sender, + X509Certificate certificate, + X509Chain chain, + SslPolicyErrors sslPolicyErrors) + { + //if (m_NoVerifyCertChain) + sslPolicyErrors &= ~SslPolicyErrors.RemoteCertificateChainErrors; + + //if (m_NoVerifyCertHostname) + sslPolicyErrors &= ~SslPolicyErrors.RemoteCertificateNameMismatch; + + if (sslPolicyErrors == SslPolicyErrors.None) + return true; + + return false; + } // Proxy: construct a proxy server with the given configuration public Proxy(ProxyConfig proxyConfig) @@ -207,7 +229,7 @@ public Proxy(ProxyConfig proxyConfig) ServicePointManager.Expect100Continue = false; ServicePointManager.DefaultConnectionLimit = 128; - ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true; + ServicePointManager.ServerCertificateValidationCallback = ValidateServerCertificate; InitializeLoginProxy(); InitializeSimProxy(); @@ -585,7 +607,7 @@ private void ProxyHTTP(Socket client) headers["method"] = meth; if (contentType == "application/llsd+xml" || contentType == "application/xml+llsd" || contentType == "application/xml") { - ProxyLoginSD(netStream, content); + ProxyLoginSD(netStream, content, headers); } else { @@ -620,9 +642,11 @@ private void ProxyHTTP(Socket client) public ObservableDictionary KnownCaps = new ObservableDictionary(); //private Dictionary SubHack = new Dictionary(); + private static Regex CapMainRegex = new Regex(@"^(https?)://([^:/]+)(:\d+)?(/.*)$", RegexOptions.Compiled | RegexOptions.CultureInvariant); + private static Regex CapUriRegex = new Regex(@"/?\?.*$", RegexOptions.Compiled | RegexOptions.CultureInvariant); private void ProxyCaps(NetworkStream netStream, string meth, string uri, Dictionary headers, byte[] content, int reqNo) { - Match match = new Regex(@"^(https?)://([^:/]+)(:\d+)?(/.*)$").Match(uri); + Match match = CapMainRegex.Match(uri); if (!match.Success) { OpenMetaverse.Logger.Log("[" + reqNo + "] Malformed proxy URI: " + uri, Helpers.LogLevel.Error); @@ -638,8 +662,7 @@ private void ProxyCaps(NetworkStream netStream, string meth, string uri, Diction CapInfo cap = null; lock (this) { - string capuri = Regex.Replace(uri, @"/?\?.*$", string.Empty); - + string capuri = CapUriRegex.Replace(uri, string.Empty); // detect AIS url int indx = capuri.IndexOf("/item/"); if (indx < 0) @@ -647,9 +670,14 @@ private void ProxyCaps(NetworkStream netStream, string meth, string uri, Diction if(indx > 0) capuri = capuri.Substring(0,indx); - if (KnownCaps.ContainsKey(capuri)) + if (!KnownCaps.TryGetValue(capuri, out cap)) { - cap = KnownCaps[capuri]; + indx = capuri.IndexOf("cap/"); + if(indx > 0) + { + capuri = capuri.Substring(0,indx + 36 + 4); + _ = KnownCaps.TryGetValue(capuri, out cap); + } } } @@ -1063,15 +1091,10 @@ private bool FixupEventQueueGet(CapsRequest capReq, CapsStage stage) { if (stage != CapsStage.Response) return false; - OSDMap map = null; - if (capReq.Response is OSDMap) - map = (OSDMap)capReq.Response; - else return false; + if (capReq.Response is not OSDMap map) + return false; - OSDArray array = null; - if (map.ContainsKey("events") && map["events"] is OSDArray) - array = (OSDArray)map["events"]; - else + if(!map.TryGetValue("events", out OSD oarray) || oarray is not OSDArray array) return false; for (int i = 0; i < array.Count; i++) @@ -1169,7 +1192,10 @@ private void ProxyLogin(NetworkStream netStream, byte[] content, Dictionary headers) { lock (this) { AutoResetEvent remoteComplete = new AutoResetEvent(false); CapsClient loginRequest = new CapsClient(proxyConfig.remoteLoginUri); + OSD response = null; loginRequest.OnComplete += new CapsClient.CompleteCallback( delegate (CapsClient client, OSD result, Exception error) @@ -1257,6 +1284,7 @@ private void ProxyLoginSD(NetworkStream netStream, byte[] content) remoteComplete.Set(); } ); + loginRequest.BeginGetResponse(content, "application/llsd+xml", 1000 * 100); remoteComplete.WaitOne(1000 * 100, false); @@ -2169,8 +2197,7 @@ public class CapInfo public CapInfo(string URI, IPEndPoint Sim, string CapType) : - this(URI, Sim, CapType, CapsDataFormat.OSD, CapsDataFormat.OSD) - { } + this(URI, Sim, CapType, CapsDataFormat.OSD, CapsDataFormat.OSD) { } public CapInfo(string URI, IPEndPoint Sim, string CapType, CapsDataFormat ReqFmt, CapsDataFormat RespFmt) { uri = URI; sim = Sim; type = CapType; reqFmt = ReqFmt; respFmt = RespFmt; @@ -2252,6 +2279,7 @@ public CapsRequest(CapInfo info) public string FullUri = string.Empty; public string Method = string.Empty; + public string ExtraInfo = string.Empty; } // XmlRpcRequestDelegate: specifies a delegate to be called for XML-RPC requests diff --git a/Programs/GridProxy/GridProxy.csproj b/Programs/GridProxy/GridProxy.csproj index 21da9dc5..a6ca4dbc 100644 --- a/Programs/GridProxy/GridProxy.csproj +++ b/Programs/GridProxy/GridProxy.csproj @@ -1,18 +1,12 @@  Local - net48 + net6.0 True 1591,1574,0419,0618 - - - - - False - ..\..\bin\XMLRPC.dll - + diff --git a/Programs/GridProxy/GridProxyLoader.cs b/Programs/GridProxy/GridProxyLoader.cs index 7adf98dd..cb1afe05 100644 --- a/Programs/GridProxy/GridProxyLoader.cs +++ b/Programs/GridProxy/GridProxyLoader.cs @@ -1,5 +1,4 @@ - -using Nwc.XmlRpc; +using XmlRpcCore; using OpenMetaverse; using OpenMetaverse.Packets; using System; diff --git a/Programs/GridProxyApp/GridProxyApp.csproj b/Programs/GridProxyApp/GridProxyApp.csproj index d0b9e776..3f43bdc1 100644 --- a/Programs/GridProxyApp/GridProxyApp.csproj +++ b/Programs/GridProxyApp/GridProxyApp.csproj @@ -1,7 +1,7 @@  Local - net48 + net6.0 Exe True 1591,1574,0419,0618 diff --git a/Programs/PrimWorkshop/PrimWorkshop.csproj b/Programs/PrimWorkshop/PrimWorkshop.csproj index 66e37f2d..433f6781 100644 --- a/Programs/PrimWorkshop/PrimWorkshop.csproj +++ b/Programs/PrimWorkshop/PrimWorkshop.csproj @@ -1,7 +1,8 @@  Local - net48 + net6.0-windows + true WinExe primpreview Metaverse Industries LLC @@ -19,9 +20,6 @@ False ..\..\bin\ICSharpCode.SharpZipLib.dll - - False - False ..\..\bin\Tao.OpenGl.dll diff --git a/Programs/PrimWorkshop/Properties/Resources.Designer.cs b/Programs/PrimWorkshop/Properties/Resources.Designer.cs index ab76bed3..d3db8c4f 100644 --- a/Programs/PrimWorkshop/Properties/Resources.Designer.cs +++ b/Programs/PrimWorkshop/Properties/Resources.Designer.cs @@ -1,17 +1,17 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:2.0.50727.42 +// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ -namespace PrimWorkshop.Properties -{ - - +namespace PrimWorkshop.Properties { + using System; + + /// /// A strongly-typed resource class, for looking up localized strings, etc. /// @@ -19,51 +19,43 @@ namespace PrimWorkshop.Properties // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources - { - + internal class Resources { + private static global::System.Resources.ResourceManager resourceMan; - + private static global::System.Globalization.CultureInfo resourceCulture; - + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() - { + internal Resources() { } - + /// /// Returns the cached ResourceManager instance used by this class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager - { - get - { - if ((resourceMan == null)) - { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("primpreview.Properties.Resources", typeof(Resources).Assembly); + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PrimWorkshop.Properties.Resources", typeof(Resources).Assembly); resourceMan = temp; } return resourceMan; } } - + /// /// Overrides the current thread's CurrentUICulture property for all /// resource lookups using this strongly typed resource class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture - { - get - { + internal static global::System.Globalization.CultureInfo Culture { + get { return resourceCulture; } - set - { + set { resourceCulture = value; } } diff --git a/Programs/PrimWorkshop/Properties/Settings.Designer.cs b/Programs/PrimWorkshop/Properties/Settings.Designer.cs index 2b903164..f20d649a 100644 --- a/Programs/PrimWorkshop/Properties/Settings.Designer.cs +++ b/Programs/PrimWorkshop/Properties/Settings.Designer.cs @@ -1,28 +1,24 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:2.0.50727.42 +// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ -namespace PrimWorkshop.Properties -{ - - +namespace PrimWorkshop.Properties { + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "8.0.0.0")] - internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase - { - + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.5.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); - - public static Settings Default - { - get - { + + public static Settings Default { + get { return defaultInstance; } } diff --git a/Programs/PrimWorkshop/frmBrowser.cs b/Programs/PrimWorkshop/frmBrowser.cs index 4e6aa76e..60082cd8 100644 --- a/Programs/PrimWorkshop/frmBrowser.cs +++ b/Programs/PrimWorkshop/frmBrowser.cs @@ -20,8 +20,8 @@ public partial class frmBrowser : Form const float DEG_TO_RAD = 0.0174532925f; const uint TERRAIN_START = (uint)Int32.MaxValue + 1; - ContextMenu ExportPrimMenu; - ContextMenu ExportTerrainMenu; + ContextMenuStrip ExportPrimMenu; + ContextMenuStrip ExportTerrainMenu; GridClient Client; Camera Camera; @@ -82,14 +82,14 @@ public frmBrowser() cboServer.SelectedIndex = 0; // Context menus - ExportPrimMenu = new ContextMenu(); - ExportPrimMenu.MenuItems.Add("Download", new EventHandler(DownloadMenu_Clicked)); - ExportPrimMenu.MenuItems.Add("Download All Objects", new EventHandler(DownloadAllMenu_Clicked)); - ExportTerrainMenu = new ContextMenu(); - ExportTerrainMenu.MenuItems.Add("Teleport", new EventHandler(TeleportMenu_Clicked)); - ExportTerrainMenu.MenuItems.Add("Export Terrain", new EventHandler(ExportTerrainMenu_Clicked)); - ExportTerrainMenu.MenuItems.Add("Import Object", new EventHandler(ImportObjectMenu_Clicked)); - ExportTerrainMenu.MenuItems.Add("Import Sim", new EventHandler(ImportSimMenu_Clicked)); + ExportPrimMenu = new ContextMenuStrip(); + ExportPrimMenu.Items.Add("Download", null,new EventHandler(DownloadMenu_Clicked) ); + ExportPrimMenu.Items.Add("Download All Objects",null, new EventHandler(DownloadAllMenu_Clicked)); + ExportTerrainMenu = new ContextMenuStrip(); + ExportTerrainMenu.Items.Add("Teleport", null, new EventHandler(TeleportMenu_Clicked)); + ExportTerrainMenu.Items.Add("Export Terrain",null, new EventHandler(ExportTerrainMenu_Clicked)); + ExportTerrainMenu.Items.Add("Import Object",null, new EventHandler(ImportObjectMenu_Clicked)); + ExportTerrainMenu.Items.Add("Import Sim",null, new EventHandler(ImportSimMenu_Clicked)); // Setup a timer for updating the progress bar ProgressTimer = new System.Timers.Timer(250); @@ -556,14 +556,14 @@ private void DownloadMenu_Clicked(object sender, EventArgs e) { // This should have already been fixed in the picking processing code Console.WriteLine("Download menu clicked when a child prim is selected!"); - glControl.ContextMenu = null; + glControl.ContextMenuStrip = null; LastHit = 0; } } else { Console.WriteLine("Download menu clicked when there is no selected prim!"); - glControl.ContextMenu = null; + glControl.ContextMenuStrip = null; LastHit = 0; } } @@ -696,7 +696,7 @@ private void TeleportMenu_Clicked(object sender, EventArgs e) else { // This shouldn't have happened... - glControl.ContextMenu = null; + glControl.ContextMenuStrip = null; } } } @@ -867,7 +867,7 @@ private void StopPicking() else { LastHit = 0; - glControl.ContextMenu = null; + glControl.ContextMenuStrip = null; } } @@ -903,7 +903,7 @@ private void ProcessHits(int hits, uint[] selectBuffer) if (LastHit >= TERRAIN_START) { // Terrain was clicked on, turn off the context menu - glControl.ContextMenu = ExportTerrainMenu; + glControl.ContextMenuStrip = ExportTerrainMenu; } else { @@ -922,7 +922,7 @@ private void ProcessHits(int hits, uint[] selectBuffer) if (RenderPrimList.TryGetValue(render.Prim.ParentID, out renderParent)) { // Turn on the context menu - glControl.ContextMenu = ExportPrimMenu; + glControl.ContextMenuStrip = ExportPrimMenu; // Change the clicked on prim to the parent. Camera position stays on the // clicked child but the highlighting is applied to all the children diff --git a/Programs/VisualParamGenerator/VisualParamGenerator.csproj b/Programs/VisualParamGenerator/VisualParamGenerator.csproj index 6d4e1ad7..cba7b22f 100644 --- a/Programs/VisualParamGenerator/VisualParamGenerator.csproj +++ b/Programs/VisualParamGenerator/VisualParamGenerator.csproj @@ -1,7 +1,7 @@  Local - net48 + net6.0 Exe True 1591,1574,0419,0618 diff --git a/Programs/VoiceTest/VoiceTest.csproj b/Programs/VoiceTest/VoiceTest.csproj index 014fa068..8292f5e3 100644 --- a/Programs/VoiceTest/VoiceTest.csproj +++ b/Programs/VoiceTest/VoiceTest.csproj @@ -1,7 +1,7 @@  Local - net48 + net6.0 Exe True 1591,1574,0419,0618 diff --git a/Programs/WinGridProxy/AboutBox1.cs b/Programs/WinGridProxy/AboutBox1.cs index e99af7b5..a120ac1f 100644 --- a/Programs/WinGridProxy/AboutBox1.cs +++ b/Programs/WinGridProxy/AboutBox1.cs @@ -32,7 +32,8 @@ public string AssemblyTitle return titleAttribute.Title; } } - return System.IO.Path.GetFileNameWithoutExtension(Assembly.GetExecutingAssembly().CodeBase); + + return System.IO.Path.GetFileNameWithoutExtension(Assembly.GetExecutingAssembly().Location); } } diff --git a/Programs/WinGridProxy/FormWinGridProxy.cs b/Programs/WinGridProxy/FormWinGridProxy.cs index 4193d3d7..e1652583 100644 --- a/Programs/WinGridProxy/FormWinGridProxy.cs +++ b/Programs/WinGridProxy/FormWinGridProxy.cs @@ -25,7 +25,7 @@ */ using GridProxy; -using Nwc.XmlRpc; +using XmlRpcCore; using OpenMetaverse; using OpenMetaverse.Interfaces; using OpenMetaverse.Packets; @@ -309,7 +309,7 @@ private void ProxyManager_OnMessageLog(CapsRequest req, CapsStage stage) } else { - capsSession = new SessionEvent(req.RawResponse, req.ResponseHeaders, req.Info.URI, req.Info.CapType, proto); + capsSession = new SessionEvent(req.RawResponse, req.ResponseHeaders, req.Info.URI, req.Info.CapType, proto, req.ExtraInfo); } string[] s = { PacketCounter.ToString(), capsSession.TimeStamp.ToString("HH:mm:ss.fff"), capsSession.Protocol, capsSession.Name, capsSession.Length.ToString(), capsSession.Host, capsSession.ContentType }; diff --git a/Programs/WinGridProxy/ProxyManager.cs b/Programs/WinGridProxy/ProxyManager.cs index 4a2a7a21..9993e5c2 100644 --- a/Programs/WinGridProxy/ProxyManager.cs +++ b/Programs/WinGridProxy/ProxyManager.cs @@ -25,7 +25,7 @@ */ using GridProxy; -using Nwc.XmlRpc; +using XmlRpcCore; using OpenMetaverse; using OpenMetaverse.Packets; using OpenMetaverse.StructuredData; @@ -170,30 +170,37 @@ private bool CapsHandler(CapsRequest req, CapsStage stage) /// private bool EventQueueGetHandler(CapsRequest req, CapsStage stage) { - if (stage == CapsStage.Response && req.Response is OSDMap) + if (stage == CapsStage.Response && req.Response is OSDMap map) { - OSDMap map = (OSDMap)req.Response; + if (OnEventMessageLog is null) + return false; - if (map.ContainsKey("events")) + if (map.TryGetValue("events", out OSD tmposd)) { - OSDArray eventsArray = (OSDArray)map["events"]; + OSDArray eventsArray = (OSDArray)tmposd; + int EventID = 0; + if(map.TryGetValue("id", out OSD idsd)) + EventID = idsd.AsInteger(); + + int events = eventsArray.Count; for (int i = 0; i < eventsArray.Count; i++) { OSDMap bodyMap = (OSDMap)eventsArray[i]; - if (OnEventMessageLog != null) - { - CapInfo capInfo = new CapInfo(req.Info.URI, req.Info.Sim, bodyMap["message"].AsString()); - CapsRequest capReq = new CapsRequest(capInfo); - capReq.RequestHeaders = req.RequestHeaders; - capReq.ResponseHeaders = req.ResponseHeaders; - capReq.Request = null;// req.Request; - capReq.RawRequest = null;// req.RawRequest; - capReq.RawResponse = OSDParser.SerializeLLSDXmlBytes(bodyMap); - capReq.Response = bodyMap; - - OnEventMessageLog(capReq, CapsStage.Response); - } + + CapInfo capInfo = new CapInfo(req.Info.URI, req.Info.Sim, bodyMap["message"].AsString()); + CapsRequest capReq = new CapsRequest(capInfo) + { + RequestHeaders = req.RequestHeaders, + ResponseHeaders = req.ResponseHeaders, + Request = null,// req.Request; + RawRequest = null,// req.RawRequest; + RawResponse = OSDParser.SerializeLLSDXmlBytes(bodyMap), + Response = bodyMap + }; + capReq.ExtraInfo = $"Event iD {EventID} Message {i + 1}/{events}"; + + OnEventMessageLog?.Invoke(capReq, CapsStage.Response); } } } diff --git a/Programs/WinGridProxy/SessionTypes.cs b/Programs/WinGridProxy/SessionTypes.cs index 16838b09..d95be245 100644 --- a/Programs/WinGridProxy/SessionTypes.cs +++ b/Programs/WinGridProxy/SessionTypes.cs @@ -38,7 +38,7 @@ using OpenMetaverse.StructuredData; using GridProxy; -using Nwc.XmlRpc; +using XmlRpcCore; namespace WinGridProxy { @@ -76,7 +76,7 @@ public virtual string ToRawString(Direction direction) public virtual byte[] ToBytes(Direction direction) { - return OpenMetaverse.Utils.EmptyBytes; + return Array.Empty(); } public virtual string ToXml(Direction direction) @@ -203,12 +203,12 @@ public SessionCaps(byte[] requestBytes, byte[] responseBytes, if (requestBytes != null) RequestBytes = requestBytes; else - RequestBytes = OpenMetaverse.Utils.EmptyBytes; + RequestBytes = Array.Empty(); if (responseBytes != null) ResponseBytes = responseBytes; else - ResponseBytes = OpenMetaverse.Utils.EmptyBytes; + ResponseBytes = Array.Empty(); RequestHeaders = requestHeaders; ResponseHeaders = responseHeaders; Protocol = proto; @@ -666,10 +666,11 @@ internal class SessionEvent : Session { private byte[] ResponseBytes; private WebHeaderCollection ResponseHeaders; + private string ExtraInfo; public SessionEvent() : base() { this.Protocol = "EventQ"; } public SessionEvent(byte[] responseBytes, WebHeaderCollection responseHeaders, - String uri, String capsKey, String proto) + String uri, String capsKey, String proto, string ExtraInfo) : base() { this.Protocol = proto; @@ -680,10 +681,8 @@ public SessionEvent(byte[] responseBytes, WebHeaderCollection responseHeaders, this.Name = capsKey; this.ContentType = responseHeaders.Get("Content-Type"); var ContentLength = responseHeaders.Get("Content-Length"); - if (ContentLength != null) - this.Length = Int32.Parse(ContentLength); - else - this.Length = 0; + this.Length = ContentLength is null ? 0 : Int32.Parse (ContentLength); + this.ExtraInfo = ExtraInfo; } public override string ToPrettyString(Direction direction) @@ -729,9 +728,16 @@ public override string ToRawString(Direction direction) StringBuilder result = new StringBuilder(); foreach (String key in ResponseHeaders.Keys) { - result.AppendFormat("{0} {1}" + Environment.NewLine, key, ResponseHeaders[key]); + //result.AppendFormat("{0} {1}" + Environment.NewLine, key, ResponseHeaders[key]); + result.AppendLine($"{key} {ResponseHeaders[key]}"); } result.AppendLine(); + if (!string.IsNullOrEmpty(this.ExtraInfo)) + { + result.Append(this.ExtraInfo); + result.AppendLine(); + result.AppendLine(); + } result.AppendLine(this.ToXml(direction)); return result.ToString(); } diff --git a/Programs/WinGridProxy/WinGridProxy.csproj b/Programs/WinGridProxy/WinGridProxy.csproj index d8a2ca26..c8ac894d 100644 --- a/Programs/WinGridProxy/WinGridProxy.csproj +++ b/Programs/WinGridProxy/WinGridProxy.csproj @@ -1,7 +1,8 @@  Local - net48 + net6.0-windows + true WinExe WinGridProxy OpenMetaverse @@ -13,7 +14,7 @@ True - + @@ -21,13 +22,6 @@ False ..\..\bin\Be.Windows.Forms.HexBox.dll - - False - - - False - ..\..\bin\XMLRPC.dll - diff --git a/Programs/examples/Dashboard/Dashboard.csproj b/Programs/examples/Dashboard/Dashboard.csproj index cfe23f15..3e1ef3d1 100644 --- a/Programs/examples/Dashboard/Dashboard.csproj +++ b/Programs/examples/Dashboard/Dashboard.csproj @@ -1,16 +1,12 @@  Local - net48 + net6.0-windows + true WinExe True 1591,1574,0419,0618 - - - False - - diff --git a/Programs/examples/GridAccountant/GridAccountant.csproj b/Programs/examples/GridAccountant/GridAccountant.csproj index d8ffd302..ecae4198 100644 --- a/Programs/examples/GridAccountant/GridAccountant.csproj +++ b/Programs/examples/GridAccountant/GridAccountant.csproj @@ -1,7 +1,8 @@  Local - net48 + net6.0-windows + true WinExe 1591,1574,0419,0618 True @@ -10,11 +11,6 @@ - - - False - - diff --git a/Programs/examples/Heightmap/Heightmap.csproj b/Programs/examples/Heightmap/Heightmap.csproj index a54e86a1..514f0460 100644 --- a/Programs/examples/Heightmap/Heightmap.csproj +++ b/Programs/examples/Heightmap/Heightmap.csproj @@ -1,16 +1,13 @@  Local - net48 + net6.0-windows + true + true WinExe 1591,1574,0419,0618 True - - - False - - diff --git a/Programs/examples/IRCGateway/IRCGateway.csproj b/Programs/examples/IRCGateway/IRCGateway.csproj index 5dc17432..fc2305dc 100644 --- a/Programs/examples/IRCGateway/IRCGateway.csproj +++ b/Programs/examples/IRCGateway/IRCGateway.csproj @@ -1,7 +1,7 @@  Local - net48 + net6.0 Exe True 1591,1574,0419,0618 diff --git a/Programs/examples/PacketDump/PacketDump.csproj b/Programs/examples/PacketDump/PacketDump.csproj index 5dc17432..fc2305dc 100644 --- a/Programs/examples/PacketDump/PacketDump.csproj +++ b/Programs/examples/PacketDump/PacketDump.csproj @@ -1,7 +1,7 @@  Local - net48 + net6.0 Exe True 1591,1574,0419,0618 diff --git a/Programs/examples/TestClient/TestClient.csproj b/Programs/examples/TestClient/TestClient.csproj index 597fa047..359b2d05 100644 --- a/Programs/examples/TestClient/TestClient.csproj +++ b/Programs/examples/TestClient/TestClient.csproj @@ -1,7 +1,7 @@  Local - net48 + net6.0 Exe TestClient TestClient @@ -9,11 +9,6 @@ True 1591,1574,0419,0618 - - - False - - diff --git a/Programs/examples/groupmanager/groupmanager.csproj b/Programs/examples/groupmanager/groupmanager.csproj index 359d27d6..8ae1ae36 100644 --- a/Programs/examples/groupmanager/groupmanager.csproj +++ b/Programs/examples/groupmanager/groupmanager.csproj @@ -1,16 +1,12 @@  Local - net48 + net6.0-windows + true WinExe 1591,1574,0419,0618 True - - - False - - diff --git a/Programs/importprimscript/importprimscript.csproj b/Programs/importprimscript/importprimscript.csproj index 55fb072e..2985612f 100644 --- a/Programs/importprimscript/importprimscript.csproj +++ b/Programs/importprimscript/importprimscript.csproj @@ -1,7 +1,7 @@  Local - net48 + net6.0 Exe 1591,1574,0419,0618 True diff --git a/Programs/mapgenerator/ProtocolManager.cs b/Programs/mapgenerator/ProtocolManager.cs index 659822a0..6196857a 100644 --- a/Programs/mapgenerator/ProtocolManager.cs +++ b/Programs/mapgenerator/ProtocolManager.cs @@ -656,9 +656,9 @@ private void LoadMapFile(string mapFile) r.Close(); map.Close(); } - catch (Exception e) + catch (Exception) { - throw e; + throw; } } diff --git a/Programs/mapgenerator/mapgenerator.csproj b/Programs/mapgenerator/mapgenerator.csproj index 10acbb0f..07225ee6 100644 --- a/Programs/mapgenerator/mapgenerator.csproj +++ b/Programs/mapgenerator/mapgenerator.csproj @@ -1,7 +1,7 @@  Local - net48 + net6.0 Exe True 1591,1574,0419,0618 diff --git a/bin/AvatarPreview.runtimeconfig.json b/bin/AvatarPreview.runtimeconfig.json new file mode 100644 index 00000000..1b351ac9 --- /dev/null +++ b/bin/AvatarPreview.runtimeconfig.json @@ -0,0 +1,19 @@ +{ + "runtimeOptions": { + "tfm": "net6.0", + "frameworks": [ + { + "name": "Microsoft.NETCore.App", + "version": "6.0.0" + }, + { + "name": "Microsoft.WindowsDesktop.App", + "version": "6.0.0" + } + ], + "configProperties": { + "System.Reflection.Metadata.MetadataUpdater.IsSupported": false, + "System.Runtime.TieredCompilation": false + } + } +} \ No newline at end of file diff --git a/bin/Baker.runtimeconfig.json b/bin/Baker.runtimeconfig.json new file mode 100644 index 00000000..1b351ac9 --- /dev/null +++ b/bin/Baker.runtimeconfig.json @@ -0,0 +1,19 @@ +{ + "runtimeOptions": { + "tfm": "net6.0", + "frameworks": [ + { + "name": "Microsoft.NETCore.App", + "version": "6.0.0" + }, + { + "name": "Microsoft.WindowsDesktop.App", + "version": "6.0.0" + } + ], + "configProperties": { + "System.Reflection.Metadata.MetadataUpdater.IsSupported": false, + "System.Runtime.TieredCompilation": false + } + } +} \ No newline at end of file diff --git a/bin/Dashboard.runtimeconfig.json b/bin/Dashboard.runtimeconfig.json new file mode 100644 index 00000000..1b351ac9 --- /dev/null +++ b/bin/Dashboard.runtimeconfig.json @@ -0,0 +1,19 @@ +{ + "runtimeOptions": { + "tfm": "net6.0", + "frameworks": [ + { + "name": "Microsoft.NETCore.App", + "version": "6.0.0" + }, + { + "name": "Microsoft.WindowsDesktop.App", + "version": "6.0.0" + } + ], + "configProperties": { + "System.Reflection.Metadata.MetadataUpdater.IsSupported": false, + "System.Runtime.TieredCompilation": false + } + } +} \ No newline at end of file diff --git a/bin/GridAccountant.runtimeconfig.json b/bin/GridAccountant.runtimeconfig.json new file mode 100644 index 00000000..1b351ac9 --- /dev/null +++ b/bin/GridAccountant.runtimeconfig.json @@ -0,0 +1,19 @@ +{ + "runtimeOptions": { + "tfm": "net6.0", + "frameworks": [ + { + "name": "Microsoft.NETCore.App", + "version": "6.0.0" + }, + { + "name": "Microsoft.WindowsDesktop.App", + "version": "6.0.0" + } + ], + "configProperties": { + "System.Reflection.Metadata.MetadataUpdater.IsSupported": false, + "System.Runtime.TieredCompilation": false + } + } +} \ No newline at end of file diff --git a/bin/GridImageUpload.runtimeconfig.json b/bin/GridImageUpload.runtimeconfig.json new file mode 100644 index 00000000..1b351ac9 --- /dev/null +++ b/bin/GridImageUpload.runtimeconfig.json @@ -0,0 +1,19 @@ +{ + "runtimeOptions": { + "tfm": "net6.0", + "frameworks": [ + { + "name": "Microsoft.NETCore.App", + "version": "6.0.0" + }, + { + "name": "Microsoft.WindowsDesktop.App", + "version": "6.0.0" + } + ], + "configProperties": { + "System.Reflection.Metadata.MetadataUpdater.IsSupported": false, + "System.Runtime.TieredCompilation": false + } + } +} \ No newline at end of file diff --git a/bin/GridProxyApp.runtimeconfig.json b/bin/GridProxyApp.runtimeconfig.json new file mode 100644 index 00000000..e355688b --- /dev/null +++ b/bin/GridProxyApp.runtimeconfig.json @@ -0,0 +1,13 @@ +{ + "runtimeOptions": { + "tfm": "net6.0", + "framework": { + "name": "Microsoft.NETCore.App", + "version": "6.0.0" + }, + "configProperties": { + "System.Reflection.Metadata.MetadataUpdater.IsSupported": false, + "System.Runtime.TieredCompilation": false + } + } +} \ No newline at end of file diff --git a/bin/Heightmap.runtimeconfig.json b/bin/Heightmap.runtimeconfig.json new file mode 100644 index 00000000..1b351ac9 --- /dev/null +++ b/bin/Heightmap.runtimeconfig.json @@ -0,0 +1,19 @@ +{ + "runtimeOptions": { + "tfm": "net6.0", + "frameworks": [ + { + "name": "Microsoft.NETCore.App", + "version": "6.0.0" + }, + { + "name": "Microsoft.WindowsDesktop.App", + "version": "6.0.0" + } + ], + "configProperties": { + "System.Reflection.Metadata.MetadataUpdater.IsSupported": false, + "System.Runtime.TieredCompilation": false + } + } +} \ No newline at end of file diff --git a/bin/ICSharpCode.SharpZipLib.dll b/bin/ICSharpCode.SharpZipLib.dll index 536337c2..3b268b7c 100755 Binary files a/bin/ICSharpCode.SharpZipLib.dll and b/bin/ICSharpCode.SharpZipLib.dll differ diff --git a/bin/IRCGateway.runtimeconfig.json b/bin/IRCGateway.runtimeconfig.json new file mode 100644 index 00000000..e355688b --- /dev/null +++ b/bin/IRCGateway.runtimeconfig.json @@ -0,0 +1,13 @@ +{ + "runtimeOptions": { + "tfm": "net6.0", + "framework": { + "name": "Microsoft.NETCore.App", + "version": "6.0.0" + }, + "configProperties": { + "System.Reflection.Metadata.MetadataUpdater.IsSupported": false, + "System.Runtime.TieredCompilation": false + } + } +} \ No newline at end of file diff --git a/bin/OpenMetaverse.dll.config b/bin/OpenMetaverse.dll.config index 6b7b9993..20b1df5e 100755 --- a/bin/OpenMetaverse.dll.config +++ b/bin/OpenMetaverse.dll.config @@ -1,7 +1,9 @@ - - - - - + + + + + + + diff --git a/bin/PacketDump.runtimeconfig.json b/bin/PacketDump.runtimeconfig.json new file mode 100644 index 00000000..e355688b --- /dev/null +++ b/bin/PacketDump.runtimeconfig.json @@ -0,0 +1,13 @@ +{ + "runtimeOptions": { + "tfm": "net6.0", + "framework": { + "name": "Microsoft.NETCore.App", + "version": "6.0.0" + }, + "configProperties": { + "System.Reflection.Metadata.MetadataUpdater.IsSupported": false, + "System.Runtime.TieredCompilation": false + } + } +} \ No newline at end of file diff --git a/bin/PrimWorkshop.runtimeconfig.json b/bin/PrimWorkshop.runtimeconfig.json new file mode 100644 index 00000000..1b351ac9 --- /dev/null +++ b/bin/PrimWorkshop.runtimeconfig.json @@ -0,0 +1,19 @@ +{ + "runtimeOptions": { + "tfm": "net6.0", + "frameworks": [ + { + "name": "Microsoft.NETCore.App", + "version": "6.0.0" + }, + { + "name": "Microsoft.WindowsDesktop.App", + "version": "6.0.0" + } + ], + "configProperties": { + "System.Reflection.Metadata.MetadataUpdater.IsSupported": false, + "System.Runtime.TieredCompilation": false + } + } +} \ No newline at end of file diff --git a/bin/TestClient.runtimeconfig.json b/bin/TestClient.runtimeconfig.json new file mode 100644 index 00000000..e355688b --- /dev/null +++ b/bin/TestClient.runtimeconfig.json @@ -0,0 +1,13 @@ +{ + "runtimeOptions": { + "tfm": "net6.0", + "framework": { + "name": "Microsoft.NETCore.App", + "version": "6.0.0" + }, + "configProperties": { + "System.Reflection.Metadata.MetadataUpdater.IsSupported": false, + "System.Runtime.TieredCompilation": false + } + } +} \ No newline at end of file diff --git a/bin/VisualParamGenerator.runtimeconfig.json b/bin/VisualParamGenerator.runtimeconfig.json new file mode 100644 index 00000000..e355688b --- /dev/null +++ b/bin/VisualParamGenerator.runtimeconfig.json @@ -0,0 +1,13 @@ +{ + "runtimeOptions": { + "tfm": "net6.0", + "framework": { + "name": "Microsoft.NETCore.App", + "version": "6.0.0" + }, + "configProperties": { + "System.Reflection.Metadata.MetadataUpdater.IsSupported": false, + "System.Runtime.TieredCompilation": false + } + } +} \ No newline at end of file diff --git a/bin/VoiceTest.runtimeconfig.json b/bin/VoiceTest.runtimeconfig.json new file mode 100644 index 00000000..e355688b --- /dev/null +++ b/bin/VoiceTest.runtimeconfig.json @@ -0,0 +1,13 @@ +{ + "runtimeOptions": { + "tfm": "net6.0", + "framework": { + "name": "Microsoft.NETCore.App", + "version": "6.0.0" + }, + "configProperties": { + "System.Reflection.Metadata.MetadataUpdater.IsSupported": false, + "System.Runtime.TieredCompilation": false + } + } +} \ No newline at end of file diff --git a/bin/WinGridProxy.runtimeconfig.json b/bin/WinGridProxy.runtimeconfig.json new file mode 100644 index 00000000..1b351ac9 --- /dev/null +++ b/bin/WinGridProxy.runtimeconfig.json @@ -0,0 +1,19 @@ +{ + "runtimeOptions": { + "tfm": "net6.0", + "frameworks": [ + { + "name": "Microsoft.NETCore.App", + "version": "6.0.0" + }, + { + "name": "Microsoft.WindowsDesktop.App", + "version": "6.0.0" + } + ], + "configProperties": { + "System.Reflection.Metadata.MetadataUpdater.IsSupported": false, + "System.Runtime.TieredCompilation": false + } + } +} \ No newline at end of file diff --git a/bin/XMLRPC.dll b/bin/XMLRPC.dll deleted file mode 100755 index 2189d090..00000000 Binary files a/bin/XMLRPC.dll and /dev/null differ diff --git a/bin/groupmanager.runtimeconfig.json b/bin/groupmanager.runtimeconfig.json new file mode 100644 index 00000000..1b351ac9 --- /dev/null +++ b/bin/groupmanager.runtimeconfig.json @@ -0,0 +1,19 @@ +{ + "runtimeOptions": { + "tfm": "net6.0", + "frameworks": [ + { + "name": "Microsoft.NETCore.App", + "version": "6.0.0" + }, + { + "name": "Microsoft.WindowsDesktop.App", + "version": "6.0.0" + } + ], + "configProperties": { + "System.Reflection.Metadata.MetadataUpdater.IsSupported": false, + "System.Runtime.TieredCompilation": false + } + } +} \ No newline at end of file diff --git a/bin/importprimscript.runtimeconfig.json b/bin/importprimscript.runtimeconfig.json new file mode 100644 index 00000000..e355688b --- /dev/null +++ b/bin/importprimscript.runtimeconfig.json @@ -0,0 +1,13 @@ +{ + "runtimeOptions": { + "tfm": "net6.0", + "framework": { + "name": "Microsoft.NETCore.App", + "version": "6.0.0" + }, + "configProperties": { + "System.Reflection.Metadata.MetadataUpdater.IsSupported": false, + "System.Runtime.TieredCompilation": false + } + } +} \ No newline at end of file diff --git a/bin/log4net.dll b/bin/log4net.dll deleted file mode 100755 index ffc57e11..00000000 Binary files a/bin/log4net.dll and /dev/null differ diff --git a/bin/mapgenerator.runtimeconfig.json b/bin/mapgenerator.runtimeconfig.json new file mode 100644 index 00000000..e355688b --- /dev/null +++ b/bin/mapgenerator.runtimeconfig.json @@ -0,0 +1,13 @@ +{ + "runtimeOptions": { + "tfm": "net6.0", + "framework": { + "name": "Microsoft.NETCore.App", + "version": "6.0.0" + }, + "configProperties": { + "System.Reflection.Metadata.MetadataUpdater.IsSupported": false, + "System.Runtime.TieredCompilation": false + } + } +} \ No newline at end of file diff --git a/bin/libopenjpeg-dotnet-2-1.5.0-dotnet-1-x86_64.so b/bin/openjpeg-dotnet-x86_64.so old mode 100755 new mode 100644 similarity index 100% rename from bin/libopenjpeg-dotnet-2-1.5.0-dotnet-1-x86_64.so rename to bin/openjpeg-dotnet-x86_64.so diff --git a/bin/openjpeg-dotnet.dll b/bin/openjpeg-dotnet.dll index 6377b8d9..677b1350 100755 Binary files a/bin/openjpeg-dotnet.dll and b/bin/openjpeg-dotnet.dll differ diff --git a/bin/libopenjpeg-dotnet-2-1.5.0-dotnet-1.dylib b/bin/openjpeg-dotnet.dylib old mode 100755 new mode 100644 similarity index 100% rename from bin/libopenjpeg-dotnet-2-1.5.0-dotnet-1.dylib rename to bin/openjpeg-dotnet.dylib diff --git a/bin/libopenjpeg-dotnet-2-1.5.0-dotnet-1-i686.so b/bin/openjpeg-dotnet.so old mode 100755 new mode 100644 similarity index 100% rename from bin/libopenjpeg-dotnet-2-1.5.0-dotnet-1-i686.so rename to bin/openjpeg-dotnet.so diff --git a/bin/openmetaverse_data/avatar_lad.xml b/bin/openmetaverse_data/avatar_lad.xml index 5d6b10c0..0c3fa9d4 100644 --- a/bin/openmetaverse_data/avatar_lad.xml +++ b/bin/openmetaverse_data/avatar_lad.xml @@ -1,6 +1,6 @@ + version="2.0" wearable_definition_version="22"> @@ -21,6 +22,7 @@ pie_slice="2" name="Skull" joint="mHead" + location="ATTACH_HEAD" position="0 0 0.15" rotation="0 0 90" visible_in_first_person="false" /> @@ -28,9 +30,10 @@ @@ -38,18 +41,21 @@ @@ -78,9 +87,10 @@ @@ -91,6 +101,7 @@ pie_slice="7" name="Spine" joint="mChest" + location="ATTACH_BACK" position="-0.15 0 -0.1" rotation="0 -90 90" visible_in_first_person="true" /> @@ -101,6 +112,7 @@ pie_slice="6" name="Pelvis" joint="mPelvis" + location="ATTACH_PELVIS" position="0 0 -0.15" rotation="0 0 0" visible_in_first_person="true" /> @@ -111,6 +123,7 @@ pie_slice="6" name="Mouth" joint="mHead" + location="ATTACH_MOUTH" position="0.12 0 0.001" rotation="0 0 0" visible_in_first_person="false"/> @@ -121,6 +134,7 @@ pie_slice="7" name="Chin" joint="mHead" + location="ATTACH_CHIN" position="0.12 0 -0.04" rotation="0 0 0" visible_in_first_person="false" /> @@ -131,6 +145,7 @@ pie_slice="4" name="Left Ear" joint="mHead" + location="ATTACH_LEAR" position="0.015 0.08 0.017" rotation="0 0 0" visible_in_first_person="false" /> @@ -141,6 +156,7 @@ pie_slice="0" name="Right Ear" joint="mHead" + location="ATTACH_REAR" position="0.015 -0.08 0.017" rotation="0 0 0" visible_in_first_person="false" /> @@ -151,6 +167,7 @@ pie_slice="3" name="Left Eyeball" joint="mEyeLeft" + location="ATTACH_LEYE" position="0 0 0" rotation="0 0 0" visible_in_first_person="false"/> @@ -161,6 +178,7 @@ pie_slice="1" name="Right Eyeball" joint="mEyeRight" + location="ATTACH_REYE" position="0 0 0" rotation="0 0 0" visible_in_first_person="false" /> @@ -171,6 +189,7 @@ pie_slice="5" name="Nose" joint="mHead" + location="ATTACH_NOSE" position="0.1 0 0.05" rotation="0 0 0" visible_in_first_person="false"/> @@ -178,9 +197,10 @@ @@ -188,9 +208,10 @@ @@ -198,9 +219,10 @@ @@ -208,9 +230,10 @@ @@ -218,9 +241,10 @@ @@ -228,9 +252,10 @@ @@ -238,9 +263,10 @@ @@ -248,9 +274,10 @@ @@ -258,9 +285,10 @@ @@ -268,9 +296,10 @@ @@ -281,6 +310,7 @@ pie_slice="5" name="Stomach" joint="mPelvis" + location="ATTACH_BELLY" position="0.092 0.0 0.088" rotation="0 0 0" visible_in_first_person="true" /> @@ -291,6 +321,7 @@ pie_slice="3" name="Left Pec" joint="mTorso" + location="ATTACH_LEFT_PEC" position="0.104 0.082 0.247" rotation="0 0 0" visible_in_first_person="true" /> @@ -301,15 +332,17 @@ pie_slice="1" name="Right Pec" joint="mTorso" + location="ATTACH_RIGHT_PEC" position="0.104 -0.082 0.247" rotation="0 0 0" visible_in_first_person="true" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + name="mSpine3" + scale="0 0 .05" /> + + + + + + + + + + + + + + + + + @@ -514,8 +771,12 @@ scale="0 0 0.05" /> + name="mSpine3" + scale="0 0 0.05" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -586,10 +937,26 @@ name="mTorso" scale="0.1 0.1 0" /> + + + + + + + + @@ -605,6 +972,37 @@ + + + + + + + + + + + + + + + + + + + + + @@ -643,6 +1041,17 @@ + + + + + @@ -650,7 +1059,7 @@ id="37" group="0" name="Hip Width" - label="Hip Width" + label="Hip Width" wearable="shape" edit_group="shape_legs" edit_group_order="3" @@ -665,6 +1074,14 @@ name="mPelvis" scale="0 0.1 0" /> + + + + + + + + + + + + + + + @@ -693,7 +1129,19 @@ - + + + + + + + + + + + + + + + @@ -732,6 +1196,26 @@ + + + + + + + + + + @@ -755,10 +1239,82 @@ name="mEyeRight" scale="0 0 0" offset="0 -.009 0" /> - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -801,9 +1507,10 @@ name="mEyeRight" scale="0 0 0" offset=".016 0 0" /> + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -831,7 +1612,7 @@ id="655" group="1" name="Head Size" - label="Head Size" + label="Head Size" wearable="shape" edit_group="shape_head" label_min="Small Head" @@ -840,6 +1621,36 @@ value_min="-.25" value_max=".10"> + + + + + + + + + + + + + + - - - - - + + name="mFaceEyeAltLeft" + scale="1 1 1" + offset="0 0 -0.001" /> - - - - - + name="mFaceEyeAltRight" + scale="1 1 1" + offset="0 0 -0.001" /> + + name="mFaceForeheadLeft" + scale="1 1 1" + offset="0 0 0" /> - - + name="mFaceForeheadCenter" + scale="1 1 1" + offset="0 0 0" /> - - - - - - - - - - + name="mFaceEyebrowInnerLeft" + scale="1 1 1" + offset="0 0 0" /> + name="mFaceEyebrowOuterRight" + scale="1 1 1" + offset="0 0 0" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + id="197" + group="1" + wearable="shoes" + name="Shoe_Heels" + edit_group="shoes" + label_min="No Heels" + label_max="High Heels" + value_min="0" + value_max="1"> + name="mFootRight" + scale="0 0 0" + offset="0 0 -.08" /> + name="mFootLeft" + scale="0 0 0" + offset="0 0 -.08" /> + name="mHindLimb4Left" + scale="0 0 0" + offset="0 0 -.08" /> + name="mHindLimb4Right" + scale="0 0 0" + offset="0 0 -.08" /> + + + + + + + + + + + + + + + edit_group_order="10" + label_min="Small Hands" + label_max="Large Hands" + value_min="-.3" + value_max=".3" + camera_elevation=".1" + camera_distance="1.4" + camera_angle="0"> + name="mWristRight" + scale="1 1 1" + offset="0 0 0" /> + name="mWristLeft" + scale="1 1 1" + offset="0 0 0" /> - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + scale="1 1 0" + offset="0 0 0" /> - - - - - - - - - - - - + value_max="1"> + + + + + + + + + + + + + + + + + + + + + + + + - + camera_distance="2.5"> + + + + + + + + + + + + + + + + + - + value_default=".6" + camera_distance="1.5"> + + + + + + + + + - + value_default="0" + camera_elevation=".3" + camera_distance=".8" + camera_angle="15"> + + + - + - + value_default="0" + camera_distance="2.5"> + + + + + + + + + + + - + id="30004" + group="1" + name="Broad_Nostrils" + value_min="-.5" + value_max="1"> + + + + + + + + + + + + + - + id="30517" + group="1" + name="Wide_Nose" + value_min="-.5" + value_max="1"> + + + + + - - + id="30656" + group="1" + name="Crooked_Nose" + value_min="-2" + value_max="2"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + name="Lip Width" + value_min="-0.9" + value_max="1.3" + value_default="0"> + + + + + + + + + + + + + + - - + name="Tall_Lips" + value_min="-1" + value_max="2"> + + + + + + + + + + + + + + + + + + + - - + value_max="0.7"> + + + + + + + + + + + + + + + + + + + + - - + value_max="1"> + + + + + + + + + + + + + + + + + + + + - + value_max="1.5"> + + + + + + + + + + + + + + + + + + + - + value_max="1.5"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + value_max="1.4"> + + + + + + + + + + + + + + + + + - - + value_max="1.4"> + + + - - - + + + + + - - - + + + + + - - - + - - + + + + + + + + + + + + + + + + + + + + - - - + + + + + + - + value_max="2"> + + + + + + + + + + + + + + + + - - + value_max="2"> + + + + + + + + + + + + + + + + - + name="Big_Ears" + value_min="-1" + value_max="2"> + + + + - + - + name="Ears_Out" + value_min="-.5" + value_max="1.5"> + + + + + + + + + + + + - + - + id="30185" + group="1" + name="Deep_Chin" + value_min="-1" + value_max="1"> + + + + - - + + + + - + - + name="Jaw_Angle" + value_min="-1.2" + value_max="2" + value_default="0"> + + + - + + - - + name="Jaw_Jut" + value_min="-2" + value_max="2"> + - - - + + + + + + - + name="Bulbous_Nose_Tip" + value_min="-1" + value_max="1.5"> + + + + - + - + name="Weak_Chin" + value_min="-.5" + value_max=".5"> + + + + + + + + + + + + + + + + + - + + - - + - - - + - - - + + + - - - + + + - - - + - - + - + - - + name="Eyelid_Corner_Up" + value_min="-1.3" + value_max="1.2"> + + - - + + - + - - + name="Eyelid_Inner_Corner_Up" + value_min="-1.3" + value_max="1.2"> + + + + + + - + name="Puffy_Lower_Lids" + value_min="-.3" + value_max="2.5"> + + + + + + + + + + + - - + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + - - + - - + + + + + + + + + + + - - + + - - + + - - + - - + + + + + + + + + + + + + + - - - - + value_max="2"> + + + + + + + + + + + + + + + + + + - + id="30011" + group="1" + name="Noble_Nose_Bridge" + value_min="-.5" + value_max="1.5"> + + + + + + + - + id="30758" + group="1" + name="Lower_Bridge_Nose" + value_min="-1.5" + value_max="1.5"> + + + + + + + + + + + + + + + - - + value_default="0.5"> + - - - + + + + + + - + id="30010" + group="1" + name="Sunken_Cheeks" + value_min="-1.5" + value_max="3"> + + + + + + - - + id="30017" + group="1" + name="Square_Jaw" + value_min="-0.5" + value_max="1"> + - - - + - - - + + + + + + + + + + + + + + + + + - - + value_max="2.5"> + - - - + + + + + + - + id="30021" + group="1" + name="Upper_Eyelid_Fold" + value_min="-0.2" + value_max="1.3"> + + + + + + + - - + value_max="1.5"> + - - + + + + + - - + value_max="1"> + - - - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + value_default="0"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + value_default="0.5"> + + + + + + + + + + + + + + + + - + id="30031" + group="1" + name="Arced_Eyebrows" + value_min="0" + value_max="2" + value_default=".5"> + + + + + + + + + + + + + + + + - + id="30757" + group="1" + name="Lower_Eyebrows" + value_min="-4" + value_max="2" + value_default="-1"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + camera_distance=".5" + camera_angle="20"> + camera_distance=".5" + camera_angle="20"> + camera_distance=".5" + camera_angle="90"> + camera_distance=".5" + camera_angle="90"> + camera_distance=".7" + camera_angle="90"> + camera_distance=".5" + camera_angle="20"> + name="Hair_Part_Middle" + label="Middle Part" + wearable="hair" + edit_group="hair_style" + edit_group_order="17" + label_min="No Part" + label_max="Part" + value_min="0" + value_max="2" + camera_elevation=".1" + camera_distance=".5" + camera_angle="0"> + name="Hair_Part_Right" + label="Right Part" + wearable="hair" + edit_group="hair_style" + edit_group_order="18" + label_min="No Part" + label_max="Part" + value_min="0" + value_max="2" + camera_elevation=".1" + camera_distance=".5" + camera_angle="0"> + value_max="2" + camera_elevation=".1" + camera_distance=".5" + camera_angle="0"> + camera_distance=".5" + camera_angle="20"> + value_max="1" + camera_elevation=".1" + camera_distance=".5" + camera_angle="20"> + clothing_morph="true" + name="Bangs_Front_Down" + label="Front Bangs Down" + wearable="hair" + edit_group="hair_style" + label_min="Bangs" + label_max="Bangs Down" + value_min="0" + value_max="5" + camera_elevation=".1" + camera_distance=".5" + camera_angle="20"> + name="Bangs_Sides_Up" + label="Side Bangs Up" + wearable="hair" + edit_group="hair_style" + label_min="Side Bangs" + label_max="Side Bangs Up" + value_min="0" + value_max="1" + camera_elevation=".1" + camera_distance=".5" + camera_angle="20"> - + value_max="2" + camera_elevation=".1" + camera_distance=".5" + camera_angle="20"> - + edit_group="hair_style" + label_min="Back Bangs" + label_max="Back Bangs Up" + value_min="0" + value_max="1" + camera_elevation=".1" + camera_distance=".5" + camera_angle="150"> - - - - - - - - + camera_distance=".5" + camera_angle="150"> - - - + @@ -2589,12 +4802,14 @@ + name="Hair_Back_Down" + label="Back Hair Down" + clothing_morph="true" + wearable="hair" + edit_group="hair_style" + label_min="Back Hair" + label_max="Back Hair Down" + value_min="0" + value_max="3" + camera_elevation=".1" + camera_distance=".5" + camera_angle="150"> + value_max="1" + camera_elevation=".1" + camera_distance=".5" + camera_angle="150"> + wearable="hair" + clothing_morph="true" + edit_group="hair_style" + edit_group_order="14.5" + label_min="Smooth Hair" + label_max="Rumpled Hair" + value_min="0" + value_max="1" + camera_elevation=".1" + camera_distance=".5" + camera_angle="20"> - + camera_elevation=".1" + camera_distance=".5" + camera_angle="90"> + + value_max="1" + camera_elevation=".1" + camera_distance=".5" + camera_angle="90"> + value_max="1" + camera_elevation=".1" + camera_distance=".5" + camera_angle="0"> + id="191" + group="1" + name="Hair_Tilt_Left" + label="Hair Tilted Left" + wearable="hair" + edit_group="hair_style" + label_min="Hair" + label_max="Tilt Left" + value_min="0" + value_max="1" + camera_elevation=".1" + camera_distance=".5" + camera_angle="0"> + id="192" + group="0" + name="Bangs_Part_Middle" + label="Part Bangs" + wearable="hair" + edit_group="hair_style" + edit_group_order="20" + label_min="No Part" + label_max="Part Bangs" + value_min="0" + value_max="1" + camera_elevation=".1" + camera_distance=".5" + camera_angle="0"> - + id="640" + group="1" + name="Hair_Egg_Head" + wearable="hair" + edit_group="hair_style" + cross_wearable="true" + value_min="-1.3" + value_max="1"> + id="641" + group="1" + name="Hair_Squash_Stretch_Head" + wearable="hair" + edit_group="hair_style" + cross_wearable="true" + value_min="-.5" + value_max="1"> + value_max="1"> + value_max="1"> + value_max="1"> + value_max="1"> + value_max="2"> - - - + value_max="1"> + + value_default="-0.3" + camera_elevation=".1" + camera_distance=".5" + camera_angle="100"> + camera_distance=".5" + camera_angle="30"> - - - - - - - - + camera_angle="160"> + id="755" + group="0" + name="Hair_Taper_Front" + wearable="hair" + edit_group="hair_style" + edit_group_order="13" + label="Taper Front" + label_min="Wide Front" + label_max="Narrow Front" + value_min="-1.5" + value_max="1.5" + value_default="0.05" + camera_elevation=".1" + camera_distance=".5" + camera_angle="20"> - - + + + + + + + + + + + + + + + + + + + + + name="Big_Brow" + value_min="-.3" + value_max="2"> + name="Nose_Big_Out" + value_min="-0.8" + value_max="2.5"> + name="Bulbous_Nose" + value_min="-.5" + value_max="1.5"> - + + name="Crooked_Nose" + value_min="-2" + value_max="2"> - + + name="Tall_Lips" + value_min="-1" + value_max="2"> - + + name="Mouth_Height" + value_min="-2" + value_max="2"> - + - - + name="Lip_Cleft_Deep" + value_min="-.5" + value_max="1.2"> + + - + name="Wide_Lip_Cleft" + value_min="-.8" + value_max="1.5"> + - + + name="Shift_Mouth" + value_min="-2" + value_max="2" + value_default="0"> - + - + name="Big_Ears" + value_min="-1" + value_max="2"> + - + - + name="Ears_Out" + value_min="-.5" + value_max="1.5"> + - - - + + name="Pointy_Ears" + value_min="-.4" + value_max="3"> - + - - + + name="Jaw_Jut" + value_min="-2" + value_max="2"> - + + name="Wide_Eyes" + value_min="-1.5" + value_max="2"> - - + + name="Eyelid_Corner_Up" + value_min="-1.3" + value_max="1.2"> - + + name="Puffy_Lower_Lids" + value_min="-.3" + value_max="2.5"> + name="Low_Septum_Nose" + value_min="-1" + value_max="1.5" + value_default="0.5"> + id="5" + group="0" + name="Cleft_Chin" + label="Chin Cleft" + wearable="shape" + edit_group="shape_chin" + edit_group_order="6" + label_min="Round" + label_max="Cleft" + value_min="-.1" + value_max="1" + camera_elevation="0" + camera_distance=".28" + camera_angle="-20"> + name="Weak_Chin" + value_min="-.5" + value_max=".5"> + name="Double_Chin" + value_min="-.5" + value_max="1.5"> - - - - - - - - - - - - - - - - + name="Sunken_Cheeks" + value_min="-1.5" + value_max="3"> + name="Noble_Nose_Bridge" + value_min="-.5" + value_max="1.5"> + id="20758" + group="1" + name="Lower_Bridge_Nose" + value_min="-1.5" + value_max="1.5"> + camera_distance=".4" + camera_angle="0"> + edit_group="shape_chin" + edit_group_order="7" + label_min="Round" + label_max="Cleft" + value_min="0" + value_max="1.5" + camera_elevation="0" + camera_distance=".28" + camera_angle="-20"> + name="High_Cheek_Bones" + value_min="-.5" + value_max="1"> + + camera_distance=".3"> + name="Square_Jaw" + value_min="-.5" + value_max="1"> + id="20018" + group="1" + name="Puffy_Upper_Cheeks" + value_min="-1.5" + value_max="2.5"> + id="20019" + group="1" + name="Upturned_Nose_Tip" + value_min="-1.5" + value_max="1"> - - + + id="20021" + group="1" + name="Upper_Eyelid_Fold" + value_min="-0.2" + value_max="1.3"> + edit_group="shape_ears" + edit_group_order="3" + label_min="Unattached" + label_max="Attached" + value_min="0" + value_max="1" + camera_elevation=".1" + camera_distance=".3" + camera_angle="45"> + name="Baggy_Eyes" + value_min="-.5" + value_max="1.5"> - + value_max=".7"> + name="Wide_Nose_Bridge" + value_min="-1.3" + value_max="1.2"> + value_max="2"> + name="Wide_Upper_Lip" + wearable="shape" + edit_group="driven" + value_min="-.7" + value_max="1.3"> + name="Wide_Lower_Lip" + wearable="shape" + edit_group="driven" + value_min="-.7" + value_max="1.3"> + + + name="Lower_Eyebrows" + label="Eyebrow Height" + show_simple="true" + wearable="hair" + edit_group="hair_eyebrows" + edit_group_order="2.5" + label_min="Higher" + label_max="Lower" + value_min="-2" + value_max="2"> + name="Egg_Head" + label="Egg Head" + wearable="shape" + edit_group="shape_head" + label_min="Chin Heavy" + label_max="Forehead Heavy" + value_min="-1.3" + value_max="1" + camera_elevation=".1" + camera_distance=".5" + camera_angle="20"> - + name="Squash_Stretch_Head" + label="Squash/Stretch Head" + wearable="shape" + edit_group="shape_head" + label_min="Squash Head" + label_max="Stretch Head" + value_min="-.5" + value_max="1" + camera_elevation=".1" + camera_distance=".5" + camera_angle="20"> + + + + value_max=".7" + camera_elevation=".1" + camera_distance=".5" + camera_angle="20"> + value_max="1" + camera_elevation=".1" + camera_distance=".5" + camera_angle="20"> + name="Eye_Spread" + wearable="shape" + edit_group="shape_eyes" + label_min="Eyes Together" + label_max="Eyes Spread" + value_min="-2" + value_max="2"> + value_max="2"> - + value_max="1" + camera_elevation=".3"> + + id="20880" + group="1" + name="Eyelid_Inner_Corner_Up" + value_min="-1.3" + value_max="1.2"> - - + + value_max="1.4" + camera_distance=".3" + camera_elevation=".04"> - + value_max="1.2" + camera_distance=".3" + camera_elevation=".04"> + value_max="1.5" + camera_distance=".3" + camera_elevation=".04"> - - - - - - - + value_max="1.5" + camera_distance=".3" + camera_elevation=".04"> + + label="Shear Face" + edit_group="shape_head" + label_min="Shear Left" + label_max="Shear Right" + value_min="-2" + value_max="2" + value_default="0" + camera_distance=".5" + camera_elevation=".04"> - + value_default="0" + camera_distance=".5" + camera_elevation=".04"> + + + + id="664" + group="0" + name="Pop_Eye" + wearable="shape" + label="Eye Pop" + edit_group="shape_eyes" + edit_group_order="8" + label_min="Pop Right Eye" + label_max="Pop Left Eye" + value_min="-1.3" + value_max="1.3" + value_default="0" + camera_elevation=".1" + camera_distance=".35"> + + + + - - - - - - - - + label="Eye Size" + edit_group="shape_eyes" + label_min="Beady Eyes" + label_max="Anime Eyes" + show_simple="true" + value_min="-2" + value_max="2" + value_default="0"> + + + + + + + - - - - - - - - - - + value_max="1"> + - - - - - - - - - - + value_max="1"> + - - - - - - - - - - - - + value_max="1"> + - - - - + value_max="1"> + value_max="1"> - - - + name="Express_Shrug_Emote" + value_min="0" + value_max="1"> + + id="306" + group="1" + name="Express_Kiss" + value_min="0" + value_max="1"> - + + id="307" + group="1" + name="Express_Bored_Emote" + value_min="0" + value_max="1"> - - - - - - - - - - - - - + - + + + value_min="0" + value_max="1"> + name="Old" + value_min="0" + value_max="1"> + + name="Surprised_Eyebrows" + value_min="0" + value_max="1"> - + + + + + + + + + + + + + + + + + + + + + reference="avatar_head.llm"> + reference="avatar_head.llm"> + reference="avatar_head.llm"> + reference="avatar_head.llm"> - - + label="Shear Face" + edit_group="shape_head" + label_min="Shear Left" + label_max="Shear Right" + value_min="-2" + value_max="2" + value_default="0" + camera_distance=".5" + camera_elevation=".04"> - - - - + label="Shear Face" + edit_group="shape_head" + label_min="Flat Head" + label_max="Long Head" + value_min="-1" + value_max="1" + value_default="0" + camera_distance=".5" + camera_elevation=".04"> + - - - + label="Eye Pop" + edit_group="shape_eyes" + edit_group_order="8" + label_min="Pop Right Eye" + label_max="Pop Left Eye" + value_min="-2" + value_max="2" + value_default="0" + camera_distance=".5" + camera_elevation=".04" + camera_angle="-20"> + - - - - - - + edit_group="shape_head" + label_min="Chin Heavy" + label_max="Forehead Heavy" + value_min="-1.3" + value_max="1" + camera_elevation=".1" + camera_distance=".5" + camera_angle="20"> + - - - - - - + edit_group="shape_head" + label_min="Squash Head" + label_max="Stretch Head" + value_min="-.5" + value_max="1" + camera_elevation=".1" + camera_distance=".5" + camera_angle="20"> + + + + + - - - - - - + label="Eyelash Length" + edit_group="shape_eyes" + edit_group_order="7" + label_min="Short" + label_max="Long" + value_min="-.3" + value_max="1.5" + camera_elevation=".1" + camera_distance=".30" + camera_angle="-20"> + + name="Head_Eyes_Big" + wearable="shape" + label="Eye Size" + edit_group="shape_eyes" + label_min="Beady Eyes" + label_max="Anime Eyes" + value_min="-2" + value_max="2" + show_simple="true" + value_default="0"> + name="Bug_Eyed_Head" + wearable="shape" + label="Eye Depth" + edit_group="shape_eyes" + edit_group_order="4.5" + label_min="Sunken Eyes" + label_max="Bug Eyes" + value_min="-2" + value_max="2" + value_default="0"> + shared="1" + id="20021" + group="1" + name="Upper_Eyelid_Fold" + value_min="-0.2" + value_max="1.3"> + name="Wide_Eyes" + value_min="-1.5" + value_max="2"> + name="Eyelid_Corner_Up" + value_min="-1.3" + value_max="1.2"> + + + + + + value_max="1"> + value_max="1"> + value_max="1"> - - - - + shared="1" + id="304" + group="1" + name="Express_Embarrassed_Emote" + value_min="0" + value_max="1"> + + value_max="1"> + value_max="1"> + value_max="1"> + value_max="1"> - - - - - - - + - - - - + name="Express_Afraid_Emote" + value_min="0" + value_max="1"> + + shared="1" + id="312" + group="1" + name="Express_Cry_Emote" + value_min="0" + value_max="1"> - - - - - - - - - - - - - - - - - - - - - - - + name="Express_Toothsmile" + value_min="0" + value_max="1"> - - - - - - - + name="Express_Smile" + value_min="0" + value_max="1"> + + name="Old" + value_min="0" + value_max="1"> - - - - + + name="Blink_Left" + value_min="0" + value_max="1"> + name="Blink_Right" + value_min="0" + value_max="1"> + - + type="upperBodyMesh" + lod="0" + file_name="avatar_upper_body.llm" + min_pixel_width="320"> + - + edit_group="driven" + value_min="0" + value_max="1"> + + + + - - - - - - - + value_max="1" + camera_elevation=".1" + camera_distance="1" + camera_angle="15"> + + + + - + value_max="1" + camera_elevation="0" + camera_distance=".28"> + + + + - + value_max="1" + camera_elevation="0" + camera_distance=".28"> + + + + - + value_max="1.4" + camera_elevation=".3" + camera_distance="1.2"> + + + + + + + + - - - - - + value_max="1.4" + camera_elevation=".3" + camera_distance="1.2"> + + + + + + + + - + value_max="1.3" + camera_elevation=".3" + camera_distance="1.2"> + + + + + + + + + + + - - - - - + value_max="1.3" + camera_elevation=".3" + camera_distance="1.2"> + + + + + + + + + + + - + camera_elevation=".3"> + + + + + + + + + + + + + + + + + + + + + + + + + + - + id="840" + group="0" + name="Shirtsleeve_flair" + label="Sleeve Looseness" + show_simple="true" + wearable="shirt" + edit_group="shirt" + edit_group_order="6" + clothing_morph="true" + label_min="Tight Sleeves" + label_max="Loose Sleeves" + value_min="0" + value_max="1.5" + camera_distance="1.8" + camera_angle="30" + camera_elevation="-.3"> - - + value_max="2"> + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - + sex="female" + name="Breast_Female_Cleavage" + label="Breast Cleavage" + wearable="shape" + edit_group="shape_torso" + edit_group_order="8" + label_min="Separate" + label_max="Join" + value_default="0" + value_min="-.3" + value_max="1.3" + camera_elevation=".3" + camera_distance=".8"> + + + + - + - - - + sex="male" + name="Chest_Male_No_Pecs" + label="Pectorals" + wearable="shape" + edit_group="shape_torso" + edit_group_order="5" + label_min="Big Pectorals" + label_max="Sunken Chest" + value_default="0" + value_min="-0.5" + value_max="1.1" + camera_elevation=".3" + camera_distance="1.2"> + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + value_max="1"> + + + + + + + + + + + + + + + - - + value_max="1"> + + - - + + - - + value_max="1"> + + - - + + - - + value_max="1"> + + - + + + - + + + - + + + - + + + - + + + - + + + - - + + - - - - - - - - - - - - + value_max="1"> + + - - + + + + + + + - - + + + + + + - - + + + + + - - + + + + + + - - + - - + - - + + - - + + - - + + - - + + - - + + + + + + - - - - + + + + - - - - - + value_max="1"> + + + + - - - - - - - - - - + + + + + + + + - - - + + + + + + + + - - + + + + + + + + - - - + + + - - + + + - + + + - - - - + + + - - - + + + - - - + + + - - + + + - - - - - - - - + + + - - + + + + + + + + + - - - + + + + + + - - - - - - + + + - - - + + + + + + + + + - - - - + + + + - - + - - - + + + - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + - - + + + + + + - - - + + + + + - - - + - - - - + - - - - + + - + + - + + - + + - + + + + + + + - + + + + - + + + + + - + + + + - + + + + + + - - - + + + + - - - - + + + + + - - - - - + + + + - - - - + + + + - - - + + + - + + + - - - - - - - - - - - - - + + + - - - + + + - - - - + + + - - - - + + + - + + + - + + + - + + + - + + + - + + + + - + + + + - + - + + - + + - + + - + + - - - - - - - + + + + + - + - + - + + + - + + + + + - + + + - + - + - + - - - + - - - + - - - + - - - - + + + + - - - - + + + + + - + - + - + - + - + - + - + - + - + - + + + - + + + - + + + - + + + - + + + - + + + - + - + - + - + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + color="0, 0, 0, 255" /> + color="255, 0, 0, 255" /> - + value_default="1"> + + color="0, 0, 0, 255" /> + color="0, 255, 0, 255" /> - + value_default="1"> + + + + + + + + + + + + + + + name="head bump definition" + render_pass="bump"> + + + + + value_max="1"> + domain="0" /> + + + + + + + + + + + + + value_max="1"> + color="0, 0, 0, 0" /> - + color="0, 0, 0, 128" /> + + + - - + + - - - + + +color="255, 255, 255, 0" /> + - + color="255, 255, 255, 64" /> + + + + + - + + + color="198, 71, 71, 0" /> - + color="198, 71, 71, 255" /> + + + - + + + + + + color="220, 115, 115, 0" /> - + + name="wrinkles_shading" + render_pass="bump" + fixed_color="0,0,0,100"> + + + + + + + + + + + + + tga_file="eyebrows_alpha.tga" + domain="0.1" /> - - - - - - - - - - - - + color="255,255,255,0" /> + color="255,255,255,255" /> - - - - - - - - - + value_max="1" + value_default="0.5"> - - - - + color="255,255,255,0" /> + color="255,255,255,255" /> - - - - - - - - - - + name="lipstick"> + value_default=".25" + camera_distance=".25"> + color="245,161,177,200" /> - - + color="216,37,67,200" /> - - + color="178,48,76,200" /> - - + color="68,0,11,200" /> - - + color="252,207,184,200" /> - - + color="241,136,106,200" /> - + + - + - - - - - - + + + + value_max=".9" + value_default="0.0" + camera_distance=".25"> + tga_file="lipstick_alpha.tga" + skip_if_zero="true" + domain="0.05" /> - - - - - - - - - - + name="lipgloss" + fixed_color="255,255,255,190"> - - - - - + value_max="1" + camera_distance=".25"> + - + name="blush"> + + + + value_max="1" + value_default=".5" + camera_distance=".3" + camera_elevation=".07" + camera_angle="20"> + color="253,162,193,200" /> - - - + color="247,131,152,200" /> - - - + - - - - - + - - + - - + color="195,128,122,200" /> + color="148,103,100,200" /> + + - + value_default=".5" + camera_distance=".3" + camera_elevation=".07" + camera_angle="20"> + + color="255,255,255,0" /> + color="255,255,255,255" /> + + + camera_distance=".3" + camera_elevation=".14"> + color="252,247,246,255" /> - - + color="255,206,206,255" /> - + + - - + - - - + - - - + - - - + - - - - + - - + - - + color="223,227,213,255" /> - - + color="96,116,87,255" /> - - + color="88,143,107,255" /> - - + color="194,231,223,255" /> - - + color="207,227,234,255" /> - - + color="41,171,212,255" /> - - - + - - - + - - + + + + + + + + + + + + + + - + value_default=".6" + camera_distance=".3" + camera_elevation=".14"> + + + + + - - + value_max=".7" + camera_distance=".3" + camera_elevation=".14"> + domain="0.05" /> + + + camera_distance=".3" + camera_elevation=".14"> + color="252,247,246,255" /> + color="255,206,206,255" /> + color="233,135,149,255" /> + color="220,168,192,255" /> + color="228,203,232,255" /> + color="255,234,195,255" /> + color="230,157,101,255" /> + color="255,147,86,255" /> - - - + color="228,110,89,255" /> - - + - - - + - - - - + - - + - - + color="194,231,223,255" /> - - + color="207,227,234,255" /> - - + color="41,171,212,255" /> + color="180,137,130,255" /> + + + + + + + + + + + + + + + + - + value_default=".7" + camera_distance=".3" + camera_elevation=".14"> + + color="255,255,255,0" /> + color="255,255,255,255" /> + value_default="0" + camera_distance=".3" + camera_elevation=".14"> + tga_file="eyeshadow_inner_alpha.tga" + skip_if_zero="true" + domain="0.2" /> + + + value_default="0.0" + camera_distance=".3" + camera_elevation=".14"> + tga_file="eyeliner_alpha.tga" + skip_if_zero="true" + domain="0.1" /> - - - - + camera_distance=".3" + camera_elevation=".14"> + color="24,98,40,250" /> + + color="9,100,127,250" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + name="Sideburns bump" + value_min="0" + value_max="1"> + domain="0.05" /> + domain="0.1" /> + domain="0.03" /> + + + + + + + + + name="facialhair" + global_color="hair_color"> + + tga_file="head_hair.tga" + file_is_mask="false" /> + value_max="1"> + tga_file="facehair_sideburns_alpha.tga" + skip_if_zero="true" + domain="0.05" /> + tga_file="facehair_soulpatch_alpha.tga" + skip_if_zero="true" + domain="0.1" /> + tga_file="facehair_chincurtains_alpha.tga" + skip_if_zero="true" + domain="0.03" /> + + + + + + + + + name="head_bodypaint"> - + local_texture="head_bodypaint" /> + + + + + - + local_texture="head_alpha" /> + + + + value_default="1"> + color="0, 0, 0, 255" /> + color="255, 0, 0, 255" /> - - + value_max="1" + value_default="1"> + + - - + + - - + value_max="1" + value_default="1"> + + - - + + - + + name="head_universal_tattoo"> - + local_texture="head_universal_tattoo" /> @@ -7626,11 +10109,11 @@ render_pass="bump"> @@ -7644,11 +10127,11 @@ render_pass="bump"> @@ -7661,260 +10144,324 @@ render_pass="bump"> - - - + - - - + + + + + + + + + value_max="1"> + domain="0" /> + + + + + + + + + + + + - + value_max="1"> + + + + + + name="highlight"> + tga_file="upperbody_highlights_alpha.tga" + file_is_mask="TRUE" /> - + + + + + + + + + + + + tga_file="upperbodyfreckles_alpha.tga" + skip_if_zero="true" + domain="0.6" /> + + + + - + value_max="1" + value_default="1"> + + + + + - + value_max="1" + value_default="1"> + + + + + - + value_max="1" + value_default="1"> + + + + + - + + name="upper_universal_tattoo"> - - - - + local_texture="upper_universal_tattoo" /> + id="1232" + group="1" + edit_group="colorpicker_driven" + wearable="universal" + name="tattoo_upper_universal_red" + value_min="0" + value_max="1" + value_default="1"> + color="0, 0, 0, 255" /> + color="255, 0, 0, 255" /> - + value_max="1" + value_default="1"> + + + + + - + value_max="1" + value_default="1"> + + + + + + + + + + + + + + + value_max="1" + value_default=".8"> + value_max="1" + value_default=".8"> + domain="0.05" /> + value_max="1" + value_default=".8"> + domain="0.05" /> + name="upper_undershirt"> + local_texture="upper_undershirt" /> @@ -7928,11 +10475,11 @@ render_pass="bump"> @@ -7946,11 +10493,11 @@ render_pass="bump"> @@ -7964,320 +10511,185 @@ render_pass="bump"> + wearable="undershirt" + edit_group="driven" + name="Sleeve Length" + value_min=".01" + value_max="1" + value_default=".4"> + value_max="1" + value_default=".8"> + value_max="1" + value_default=".8"> + value_default=".8"> + domain="0.05" /> + + + value_default="0.0" + camera_distance="1.6" + camera_elevation="-.4" + camera_angle="70"> + tga_file="nailpolish_alpha.tga" + skip_if_zero="true" + domain="0.1" /> - - - - - - - - - - - - - - - - - - - - - - - - - - + value_max="1" + camera_distance="1.6" + camera_elevation="-.4" + camera_angle="70"> - - - - - - - - + color="255,187,200,255" /> - - + color="194,102,127,255" /> - - - - - - - - - - - - - - - - - - - - + color="227,34,99,255" /> - - + color="168,41,60,255" /> - - + color="97,28,59,255" /> - - + color="234,115,93,255" /> - - + color="142,58,47,255" /> - - + color="114,30,46,255" /> + color="14,14,14,255" /> - + value_default=".8"> + value_default="1"> + tga_file="gloves_fingers_alpha.tga" + multiply_blend="true" + domain="0.01" /> + name="upper_gloves"> + local_texture="upper_gloves" /> @@ -8291,11 +10703,11 @@ render_pass="bump"> @@ -8309,11 +10721,11 @@ render_pass="bump"> @@ -8327,168 +10739,282 @@ render_pass="bump"> + value_default=".8"> + value_default="1"> + tga_file="gloves_fingers_alpha.tga" + multiply_blend="true" + domain="0.01" /> + name="upper_clothes_shadow"> + local_texture="upper_shirt" /> - - - + value_default="0"> + + + + + + + + + + + + + + + + + + + + + + + + name="upper_shirt base bump" + render_pass="bump" + fixed_color="128,128,128,255"> + local_texture="upper_shirt" + local_texture_alpha_only="true" /> - - + value_max="0.85"> + + - - + + - - + value_max="1"> + + - - + + + + + + + + + value_default="0"> + color="255, 255, 255, 0" /> + color="255, 255, 255, 255" /> + value_max="0.85"> - - - + + + + value_max="1"> + multiply_blend="true" + tga_file="shirt_collar_alpha.tga" + domain="0.05" /> + + + + + name="upper_clothes"> + local_texture="upper_shirt" /> @@ -8502,11 +11028,11 @@ render_pass="bump"> @@ -8520,11 +11046,11 @@ render_pass="bump"> @@ -8538,127 +11064,166 @@ render_pass="bump"> + value_max="0.85" + value_default=".7"> - - - - - - - - - + value_default=".8"> + + name="Collar Front Height Cloth" + value_min="0" + value_max="1" + value_default=".8"> + multiply_blend="true" + tga_file="shirt_collar_alpha.tga" + domain="0.05" /> + name="Collar Back Height Cloth" + value_min="0" + value_max="1" + value_default=".8"> + multiply_blend="true" + tga_file="shirt_collar_back_alpha.tga" + domain="0.05" /> + + + + + + + + + + + + + tga_file="bump_shirt_wrinkles.tga" /> + + id="875" + group="1" + wearable="jacket" + name="jacket upper Wrinkles" + value_min="0" + value_max="1" + value_default="0"> @@ -8669,43 +11234,89 @@ render_pass="bump"> + + + + + + + + + + + + + name="upper_jacket"> + local_texture="upper_jacket" /> @@ -8719,11 +11330,11 @@ render_pass="bump"> @@ -8737,15 +11348,15 @@ render_pass="bump"> - + id="833" + group="1" + edit_group="colorpicker_driven" + wearable="jacket" + name="upper_jacket_blue" + value_min="0" + value_max="1" + value_default="1"> + @@ -8755,140 +11366,222 @@ render_pass="bump"> + + + + + value_max="1"> + value_max="1"> + multiply_blend="true" + tga_file="shirt_collar_back_alpha.tga" + domain="0.05" /> - - - - + value_max="1" + value_default=".8" + camera_distance="1.2" + camera_angle="30" + camera_elevation=".2"> + value_max="1" + value_default=".8" + camera_distance="1.2" + camera_angle="30" + camera_elevation=".2"> + + + + + + + + + + + tga_file="bump_lowerbody_base.tga" + file_is_mask="FALSE" /> + + + + + + - + tga_file="body_skingrain.tga" /> + + + + + value_max="1"> + color="0, 0, 0, 0" /> + color="0, 0, 0, 128" /> + + + + - + + + + + + + + + + + + + + + + tga_file="bodyfreckles_alpha.tga" + skip_if_zero="true" + domain="0.6" /> + name="lower_tattoo"> + local_texture="lower_tattoo" /> @@ -8902,11 +11595,11 @@ render_pass="bump"> @@ -8920,11 +11613,11 @@ render_pass="bump"> @@ -8937,101 +11630,114 @@ render_pass="bump"> + + + - - - - + + + + + + + + - + value_default="1"> + + + + + - - - - + + + - + + + - - - - - + name="lower_underpants bump" + render_pass="bump" + fixed_color="128,128,128,255"> - + local_texture="lower_underpants" + local_texture_alpha_only="true" /> - - - + + + - + + + + - - + name="lower_underpants"> + local_texture="lower_underpants" /> @@ -9045,11 +11751,11 @@ render_pass="bump"> @@ -9063,11 +11769,11 @@ render_pass="bump"> @@ -9079,123 +11785,2167 @@ render_pass="bump"> color="0, 0, 255, 255" /> - - + value_default=".3" + camera_distance="1.2" + camera_angle="30" + camera_elevation="-.3"> + tga_file="pants_length_alpha.tga" + domain="0.01" /> + value_default=".8"> + tga_file="pants_waist_alpha.tga" + domain="0.05" /> + + + + + value_default="0.35"> + tga_file="shoe_height_alpha.tga" + domain="0.01" /> + + + + - - + value_default="1"> + + + + + + + value_default="1"> + + + + + + + + + + + + + + + + + tga_file="shoe_height_alpha.tga" + domain="0.01" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + max1="1" max2="1" min2="1" /> + + + + @@ -9631,8 +14395,8 @@ render_pass="bump"> edit_group="shape_mouth" edit_group_order="3.2" name="Lip Ratio" - label="Lip Ratio" - show_simple="true" + label="Lip Ratio" + show_simple="true" label_min="More Upper Lip" label_max="More Lower Lip" value_min="0" @@ -9655,6 +14419,21 @@ render_pass="bump"> max1="1" max2="1" min2="1" /> + + + + + @@ -9680,6 +14459,10 @@ render_pass="bump"> + + + @@ -9890,6 +14673,10 @@ render_pass="bump"> max1="1" max2="1" min2="1" /> + + + @@ -10362,6 +15149,21 @@ render_pass="bump"> max1="1" max2="1" min2="1" /> + + + + + @@ -10388,6 +15190,14 @@ render_pass="bump"> + + + @@ -10414,6 +15224,10 @@ render_pass="bump"> + + + @@ -10444,7 +15258,7 @@ render_pass="bump"> min2=".5" /> min1=".5" max1="1" max2="1" + min2="1" /> + + + + + + + + + + + + @@ -10636,7 +15483,7 @@ render_pass="bump"> edit_group="shape_head" edit_group_order="1" name="Head Size" - label="Head Size" + label="Head Size" label_min="Small Head" label_max="Big Head" show_simple="true" @@ -10670,16 +15517,17 @@ render_pass="bump"> edit_group="shape_eyes" edit_group_order="1" name="Eye Size" - label="Eye Size" + label="Eye Size" label_min="Beady Eyes" label_max="Anime Eyes" value_min="0" value_max="1" value_default=".5" - show_simple="true" + show_simple="true" camera_elevation=".1" camera_distance=".35"> + @@ -10697,6 +15545,10 @@ render_pass="bump"> + + + @@ -10967,19 +15819,44 @@ render_pass="bump"> min2=".3" /> + id="151" + min1=".3" + max1="1" + max2="1" + min2="1" /> + + + + + + + + - - + + + + + @@ -11580,6 +16461,8 @@ render_pass="bump"> + @@ -11603,6 +16486,8 @@ render_pass="bump"> + @@ -11625,13 +16510,15 @@ render_pass="bump"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bin/openmetaverse_data/avatar_skeleton.xml b/bin/openmetaverse_data/avatar_skeleton.xml index 6b07bbc1..2241a125 100644 --- a/bin/openmetaverse_data/avatar_skeleton.xml +++ b/bin/openmetaverse_data/avatar_skeleton.xml @@ -1,81 +1,232 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bin/prebuild.exe b/bin/prebuild.exe new file mode 100644 index 00000000..aada172a Binary files /dev/null and b/bin/prebuild.exe differ diff --git a/bin/prebuild.runtimeconfig.json b/bin/prebuild.runtimeconfig.json new file mode 100644 index 00000000..418df653 --- /dev/null +++ b/bin/prebuild.runtimeconfig.json @@ -0,0 +1,12 @@ +{ + "runtimeOptions": { + "tfm": "net6.0", + "framework": { + "name": "Microsoft.NETCore.App", + "version": "6.0.0" + }, + "configProperties": { + "System.Runtime.TieredCompilation": false + } + } +} \ No newline at end of file diff --git a/bin/zlib.net.dll b/bin/zlib.net.dll deleted file mode 100755 index 9d156547..00000000 Binary files a/bin/zlib.net.dll and /dev/null differ diff --git a/openjpeg-dotnet/DllOpenJPEG.sln b/openjpeg-dotnet/DllOpenJPEG.sln index b6c741d4..e2956d1a 100644 --- a/openjpeg-dotnet/DllOpenJPEG.sln +++ b/openjpeg-dotnet/DllOpenJPEG.sln @@ -1,7 +1,9 @@  -Microsoft Visual Studio Solution File, Format Version 10.00 -# Visual Studio 2008 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DllOpenJPEG", "DllOpenJPEG.vcproj", "{89AC992C-5E2C-4E6B-A453-61C1DF446216}" +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27130.2003 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DllOpenJPEG", "DllOpenJPEG.vcxproj", "{89AC992C-5E2C-4E6B-A453-61C1DF446216}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -23,4 +25,7 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {DCB4E0B5-36BA-489A-BC3E-27426CD34B43} + EndGlobalSection EndGlobal