├── .dockerignore ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ └── github.autobuild.yml ├── .gitignore ├── BetterSecondBot.sln ├── Dockerfile ├── LICENSE ├── LibreMetaverse.StructuredData ├── JSON │ ├── IJsonWrapper.cs │ ├── JsonData.cs │ ├── JsonException.cs │ ├── JsonMapper.cs │ ├── JsonReader.cs │ ├── JsonWriter.cs │ ├── Lexer.cs │ ├── OSDJson.cs │ └── ParserToken.cs ├── LLSD │ ├── BinaryLLSD.cs │ ├── NotationLLSD.cs │ └── XmlLLSD.cs ├── LibreMetaverse.StructuredData.csproj └── StructuredData.cs ├── LibreMetaverse.Types ├── CRC32.cs ├── CacheDictionary.cs ├── Color4.cs ├── DoubleDictionary.cs ├── Enums.cs ├── EnumsPrimitive.cs ├── ExpiringCache.cs ├── LibreMetaverse.Types.csproj ├── Matrix4.cs ├── MultiValueDictionary.cs ├── Quaternion.cs ├── Ray.cs ├── TokenBucket.cs ├── UUID.cs ├── Utils.cs ├── UtilsConversions.cs ├── Vector2.cs ├── Vector3.cs ├── Vector3d.cs └── Vector4.cs ├── LibreMetaverse ├── AgentManager.cs ├── AgentManagerCamera.cs ├── AgentManagerMovement.cs ├── AgentThrottle.cs ├── Animations.cs ├── AppearanceManager.cs ├── AssetCache.cs ├── AssetManager.cs ├── Assets │ ├── Archiving │ │ ├── ArchiveConstants.cs │ │ ├── AssetsArchiver.cs │ │ ├── OarFile.cs │ │ ├── RegionSettings.cs │ │ ├── TarArchiveReader.cs │ │ └── TarArchiveWriter.cs │ ├── Asset.cs │ └── AssetTypes │ │ ├── AssetAnimation.cs │ │ ├── AssetBodypart.cs │ │ ├── AssetCallingCard.cs │ │ ├── AssetClothing.cs │ │ ├── AssetGesture.cs │ │ ├── AssetLandmark.cs │ │ ├── AssetMaterial.cs │ │ ├── AssetMesh.cs │ │ ├── AssetMutable.cs │ │ ├── AssetNotecard.cs │ │ ├── AssetPrim.cs │ │ ├── AssetScriptBinary.cs │ │ ├── AssetScriptText.cs │ │ ├── AssetSettings.cs │ │ ├── AssetSound.cs │ │ ├── AssetTexture.cs │ │ └── AssetWearable.cs ├── Avatar.cs ├── AvatarManager.cs ├── BVHDecoder.cs ├── BitPack.cs ├── Capabilities │ ├── CapsBase.cs │ ├── CapsClient.cs │ ├── EventQueueClient.cs │ └── HttpCapsClient.cs ├── Caps.cs ├── CapsToPacket.cs ├── CoordinateFrame.cs ├── DirectoryManager.cs ├── DownloadManager.cs ├── EstateTools.cs ├── EventDictionary.cs ├── Formatters │ └── UUIDFormatter.cs ├── FriendsManager.cs ├── GridClient.cs ├── GridManager.cs ├── GroupManager.cs ├── Helpers.cs ├── Imaging │ ├── BakeLayer.cs │ ├── J2K.cs │ ├── ManagedImage.cs │ └── Targa.cs ├── ImportExport │ ├── Collada.cs │ ├── ColladalLoader.cs │ ├── Model.cs │ └── ModelUploader.cs ├── Interfaces │ ├── IByteBufferPool.cs │ ├── IMessage.cs │ └── IRendering.cs ├── Inventory │ ├── Inventory.cs │ ├── InventoryAISClient.cs │ ├── InventoryBase.cs │ ├── InventoryCache.cs │ ├── InventoryManager.cs │ ├── InventoryNode.cs │ └── InventoryNodeDictionary.cs ├── LibreMetaverse.csproj ├── LocationParser.cs ├── LockingDictionary.cs ├── Logger.cs ├── Login.cs ├── Materials │ ├── LegacyMaterial.cs │ └── LegacyMaterialAlphaMode.cs ├── Messages │ ├── LindenMessages.cs │ ├── MessageEventDecoder.cs │ └── Messages.cs ├── NameValue.cs ├── NetworkManager.cs ├── ObjectManager.cs ├── ObservableDictionary.cs ├── PacketDecoder.cs ├── ParcelManager.cs ├── Permissions.cs ├── Primitives │ ├── ObjectMedia.cs │ ├── ParticleSystem.cs │ ├── Primitive.cs │ └── TextureEntry.cs ├── ProtocolManager.cs ├── Rendering │ ├── EndianAwareBinaryReader.cs │ ├── LindenMesh.cs │ ├── LindenSkeleton.Ext.cs │ ├── LindenSkeleton.Xsd.cs │ └── Rendering.cs ├── Repeat.cs ├── Settings.cs ├── Simulator.cs ├── SoundManager.cs ├── Sounds.cs ├── TerrainCompressor.cs ├── TerrainManager.cs ├── TexturePipeline.cs ├── ThreadUtil.cs ├── Threading │ ├── Disposers │ │ ├── IAdvancedDisposable.cs │ │ ├── IUpgradeableLock.cs │ │ ├── OptimisticReadLock.cs │ │ ├── OptimisticUpgradeableLock.cs │ │ ├── OptimisticWriteLock.cs │ │ ├── SpinReadLock.cs │ │ ├── SpinUpgradeableLock.cs │ │ └── SpinWriteLock.cs │ ├── IEventWait.cs │ ├── IReaderWriterLock.cs │ ├── IReaderWriterLockSlim.cs │ ├── ManagedAutoResetEvent.cs │ ├── ManagedManualResetEvent.cs │ ├── ManagedSemaphore.cs │ ├── OptimisticReaderWriterLock.cs │ ├── SpinLockSlim.cs │ ├── SpinReaderWriterLock.cs │ ├── SpinReaderWriterLockSlim.cs │ └── WaitHandleAsyncFactory.cs ├── UDPBase.cs ├── UDPPacketBuffer.cs ├── UserReport.cs ├── UtilizationStatistics.cs ├── _Packets_.cs └── _VisualParam_.cs ├── NuGet.Config ├── README.md └── SecondBotEvents ├── Commands ├── Animation.cs ├── Avatars.cs ├── Chat.cs ├── Core.cs ├── Dialogs.cs ├── Discord.cs ├── Estate.cs ├── Friends.cs ├── Funds.cs ├── Group.cs ├── Info.cs ├── Inventory.cs ├── Movement.cs ├── Notecard.cs ├── ParcelCommands.cs ├── Self.cs ├── Services.cs └── StreamAdmin.cs ├── Config ├── BasicConfig.cs ├── ChatGptConfig.cs ├── CommandsConfig.cs ├── CustomCommandsConfig.cs ├── DataStoreConfig.cs ├── DialogRelayConfig.cs ├── DiscordConfig.cs ├── EventsConfig.cs ├── HomeboundConfig.cs ├── HttpConfig.cs ├── InteractionConfig.cs ├── OnEventConfig.cs ├── RelayConfig.cs ├── RlvConfig.cs ├── SmtpConfig.cs └── config.cs ├── EventsSecondBot.cs ├── Properties ├── Resources.Designer.cs ├── Resources.resx └── launchSettings.json ├── RLV ├── RLVAttachmentInfo.cs ├── RLVEventArgs.cs └── RLVRule.cs ├── SecondBotEvents.csproj ├── Services ├── BotClientService.cs ├── ChatGptService.cs ├── CommandsService.cs ├── CurrentOutfitFolder.cs ├── CustomCommandsService.cs ├── DataStoreService.cs ├── DialogService.cs ├── DiscordService.cs ├── EventsService.cs ├── HomeboundService.cs ├── HttpService.cs ├── InteractionService.cs ├── RLVService.cs ├── RecoveryService.cs ├── RelayService.cs ├── Services.cs ├── SmtpService.cs └── TriggerOnEventService.cs ├── Static ├── Helpers.cs ├── Inventory.cs ├── LogFormater.cs ├── SimpleIO.cs ├── http_commands_helper.cs ├── parcel.cs └── template.html ├── WikiService.cs └── settings.env /.dockerignore: -------------------------------------------------------------------------------- 1 | **/.classpath 2 | **/.dockerignore 3 | **/.env 4 | **/.gitignore 5 | **/.project 6 | **/.settings 7 | **/.toolstarget 8 | **/.vs 9 | **/.vscode 10 | **/*.*proj.user 11 | **/*.dbmdl 12 | **/*.jfm 13 | **/azds.yaml 14 | **/bin 15 | **/charts 16 | **/docker-compose* 17 | **/Dockerfile* 18 | **/node_modules 19 | **/npm-debug.log 20 | **/obj 21 | **/secrets.dev.yaml 22 | **/values.dev.yaml 23 | LICENSE 24 | README.md -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: Madpeterz 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Hardware (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Version [e.g. 22] 29 | - Running in docker: [Yes/No] 30 | - Running as linux service: [Yes/No] 31 | 32 | **Additional context** 33 | Add any other context about the problem here. 34 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: Madpeterz 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/github.autobuild.yml: -------------------------------------------------------------------------------- 1 | name: autobuild 2 | 3 | on: 4 | push: 5 | 6 | jobs: 7 | docker: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Checkout 11 | uses: actions/checkout@v4 12 | - name: Set up QEMU 13 | uses: docker/setup-qemu-action@v3 14 | - name: Set up Docker Buildx 15 | uses: docker/setup-buildx-action@v3 16 | - name: Login to Docker Hub 17 | uses: docker/login-action@v3 18 | with: 19 | username: ${{ secrets.DOCKERHUB_USERNAME }} 20 | password: ${{ secrets.DOCKERHUB_TOKEN }} 21 | - name: Build and push 22 | uses: docker/build-push-action@v6 23 | with: 24 | context: . 25 | push: true 26 | tags: madpeter/secondbot:events -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | compile.bat 2 | *.user 3 | *.userprefs 4 | *.suo 5 | *.cache 6 | *.pfx 7 | [Oo]bj/ 8 | [Bb]in/ 9 | packages/ 10 | .idea/ 11 | .vs/ 12 | /Programs/examples/TestClient/Properties/launchSettings.json 13 | .appveyor.yml 14 | LICENSE.txt 15 | mapgen.bat 16 | PrimMesher/ 17 | Programs/ 18 | libremetaverse-core/.gitignore 19 | BetterSecondbot/Dockerfile 20 | BetterSecondbot/wiki/ 21 | BetterSecondbot/debug.json 22 | SecondBotEvents/defaultBot/ 23 | -------------------------------------------------------------------------------- /LibreMetaverse.StructuredData/JSON/IJsonWrapper.cs: -------------------------------------------------------------------------------- 1 | #region Header 2 | /* 3 | * IJsonWrapper.cs 4 | * Interface that represents a type capable of handling all kinds of JSON 5 | * data. This is mainly used when mapping objects through JsonMapper, and 6 | * it's implemented by JsonData. 7 | * 8 | * The authors disclaim copyright to this source code. For more details, see 9 | * the COPYING file included with this distribution. 10 | */ 11 | #endregion 12 | 13 | 14 | using System.Collections; 15 | using System.Collections.Specialized; 16 | 17 | 18 | namespace LitJson 19 | { 20 | public enum JsonType 21 | { 22 | None, 23 | 24 | Object, 25 | Array, 26 | String, 27 | Int, 28 | Long, 29 | Double, 30 | Boolean 31 | } 32 | 33 | public interface IJsonWrapper : IList, IOrderedDictionary 34 | { 35 | bool IsArray { get; } 36 | bool IsBoolean { get; } 37 | bool IsDouble { get; } 38 | bool IsInt { get; } 39 | bool IsLong { get; } 40 | bool IsObject { get; } 41 | bool IsString { get; } 42 | 43 | bool GetBoolean (); 44 | double GetDouble (); 45 | int GetInt (); 46 | JsonType GetJsonType (); 47 | long GetLong (); 48 | string GetString (); 49 | 50 | void SetBoolean (bool val); 51 | void SetDouble (double val); 52 | void SetInt (int val); 53 | void SetJsonType (JsonType jtype); 54 | void SetLong (long val); 55 | void SetString (string val); 56 | 57 | string ToJson (); 58 | void ToJson (JsonWriter writer); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /LibreMetaverse.StructuredData/JSON/JsonException.cs: -------------------------------------------------------------------------------- 1 | #region Header 2 | /* 3 | * JsonException.cs 4 | * Base class throwed by LitJSON when a parsing error occurs. 5 | * 6 | * The authors disclaim copyright to this source code. For more details, see 7 | * the COPYING file included with this distribution. 8 | */ 9 | #endregion 10 | 11 | 12 | using System; 13 | 14 | 15 | namespace LitJson 16 | { 17 | [Serializable] 18 | public class JsonException : ApplicationException 19 | { 20 | public JsonException () 21 | { 22 | } 23 | 24 | internal JsonException (ParserToken token) : 25 | base ($"Invalid token '{token}' in input string") 26 | { 27 | } 28 | 29 | internal JsonException (ParserToken token, 30 | Exception inner_exception) : 31 | base ($"Invalid token '{token}' in input string", 32 | inner_exception) 33 | { 34 | } 35 | 36 | internal JsonException (int c) : 37 | base ($"Invalid character '{(char) c}' in input string") 38 | { 39 | } 40 | 41 | internal JsonException (int c, Exception inner_exception) : 42 | base ($"Invalid character '{(char) c}' in input string", 43 | inner_exception) 44 | { 45 | } 46 | 47 | 48 | public JsonException (string message) : base (message) 49 | { 50 | } 51 | 52 | public JsonException (string message, Exception inner_exception) : 53 | base (message, inner_exception) 54 | { 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /LibreMetaverse.StructuredData/JSON/ParserToken.cs: -------------------------------------------------------------------------------- 1 | #region Header 2 | /* 3 | * ParserToken.cs 4 | * Internal representation of the tokens used by the lexer and the parser. 5 | * 6 | * The authors disclaim copyright to this source code. For more details, see 7 | * the COPYING file included with this distribution. 8 | */ 9 | #endregion 10 | 11 | 12 | namespace LitJson 13 | { 14 | internal enum ParserToken 15 | { 16 | // Lexer tokens 17 | None = char.MaxValue + 1, 18 | Number, 19 | True, 20 | False, 21 | Null, 22 | CharSeq, 23 | // Single char 24 | Char, 25 | 26 | // Parser Rules 27 | Text, 28 | Object, 29 | ObjectPrime, 30 | Pair, 31 | PairRest, 32 | Array, 33 | ArrayPrime, 34 | Value, 35 | ValueRest, 36 | String, 37 | 38 | // End of input 39 | End, 40 | 41 | // The empty rule 42 | Epsilon 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /LibreMetaverse.StructuredData/LibreMetaverse.StructuredData.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | LibreMetaverse.StructuredData 4 | LibreMetaverse structured data library 5 | LibreMetaverse.StructuredData 6 | netstandard2.0;net8.0;net9.0 7 | Library 8 | LibreMetaverse.StructuredData 9 | true 10 | true 11 | snupkg 12 | $(NoWarn);CS0419;CS1591;CS1574 13 | AnyCPU 14 | ..\bin\ 15 | 16 | 17 | TRACE;DEBUG 18 | False 19 | 20 | 21 | true 22 | pdbonly 23 | TRACE 24 | True 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /LibreMetaverse.Types/LibreMetaverse.Types.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | LibreMetaverse.Types 4 | LibreMetaverse.Types 5 | LibreMetaverse type library 6 | netstandard2.0;net8.0;net9.0 7 | Library 8 | LibreMetaverse 9 | true 10 | true 11 | snupkg 12 | $(NoWarn);CS0419;CS1591;CS1574 13 | AnyCPU 14 | ..\bin\ 15 | 16 | 17 | TRACE;DEBUG 18 | False 19 | 20 | 21 | true 22 | pdbonly 23 | TRACE 24 | True 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /LibreMetaverse.Types/Ray.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006-2016, openmetaverse.co 3 | * All rights reserved. 4 | * 5 | * - Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * - Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * - Neither the name of the openmetaverse.co nor the names 11 | * of its contributors may be used to endorse or promote products derived from 12 | * this software without specific prior written permission. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | namespace OpenMetaverse 28 | { 29 | public struct Ray 30 | { 31 | public Vector3 Origin; 32 | public Vector3 Direction; 33 | 34 | public Ray(Vector3 origin, Vector3 direction) 35 | { 36 | Origin = origin; 37 | Direction = direction; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /LibreMetaverse/Assets/Asset.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006-2016, openmetaverse.co 3 | * All rights reserved. 4 | * 5 | * - Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * - Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * - Neither the name of the openmetaverse.co nor the names 11 | * of its contributors may be used to endorse or promote products derived from 12 | * this software without specific prior written permission. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | namespace OpenMetaverse.Assets 28 | { 29 | /// 30 | /// Base class for all Asset types 31 | /// 32 | public abstract class Asset 33 | { 34 | /// A byte array containing the raw asset data 35 | public byte[] AssetData; 36 | /// True if the asset it only stored on the server temporarily 37 | public bool Temporary; 38 | 39 | /// The assets unique ID 40 | public UUID AssetID { get; internal set; } 41 | 42 | /// 43 | /// The "type" of asset, Notecard, Animation, etc 44 | /// 45 | public abstract AssetType AssetType 46 | { 47 | get; 48 | } 49 | 50 | /// 51 | /// Construct a new Asset object 52 | /// 53 | protected Asset() { } 54 | 55 | /// 56 | /// Construct a new Asset object 57 | /// 58 | /// A unique specific to this asset 59 | /// A byte array containing the raw asset data 60 | protected Asset(UUID assetID, byte[] assetData) 61 | { 62 | AssetID = assetID; 63 | AssetData = assetData; 64 | } 65 | 66 | /// 67 | /// Regenerates the > byte array from the properties 68 | /// of the derived class. 69 | /// 70 | public abstract void Encode(); 71 | 72 | /// 73 | /// Decodes the AssetData, placing it in appropriate properties of the derived 74 | /// class. 75 | /// 76 | /// True if the asset decoding succeeded, otherwise false 77 | public abstract bool Decode(); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /LibreMetaverse/Assets/AssetTypes/AssetAnimation.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006-2016, openmetaverse.co 3 | * All rights reserved. 4 | * 5 | * - Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * - Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * - Neither the name of the openmetaverse.co nor the names 11 | * of its contributors may be used to endorse or promote products derived from 12 | * this software without specific prior written permission. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | namespace OpenMetaverse.Assets 28 | { 29 | /// 30 | /// Represents an Animation 31 | /// 32 | public class AssetAnimation : Asset 33 | { 34 | /// Override the base classes AssetType 35 | public override AssetType AssetType => AssetType.Animation; 36 | 37 | /// Default Constructor 38 | public AssetAnimation() { } 39 | 40 | /// 41 | /// Construct an Asset object of type Animation 42 | /// 43 | /// A unique specific to this asset 44 | /// A byte array containing the raw asset data 45 | public AssetAnimation(UUID assetID, byte[] assetData) 46 | : base(assetID, assetData) 47 | { 48 | } 49 | 50 | public sealed override void Encode() { } 51 | public sealed override bool Decode() { return true; } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /LibreMetaverse/Assets/AssetTypes/AssetBodypart.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006-2016, openmetaverse.co 3 | * All rights reserved. 4 | * 5 | * - Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * - Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * - Neither the name of the openmetaverse.co nor the names 11 | * of its contributors may be used to endorse or promote products derived from 12 | * this software without specific prior written permission. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | namespace OpenMetaverse.Assets 28 | { 29 | /// 30 | /// Represents an that represents an avatars body ie: Hair, Etc. 31 | /// 32 | public class AssetBodypart : AssetWearable 33 | { 34 | /// Override the base classes AssetType 35 | public override AssetType AssetType => AssetType.Bodypart; 36 | 37 | /// Initializes a new instance of an AssetBodyPart object 38 | public AssetBodypart() { } 39 | 40 | /// Initializes a new instance of an AssetBodyPart object with parameters 41 | /// A unique specific to this asset 42 | /// A byte array containing the raw asset data 43 | public AssetBodypart(UUID assetID, byte[] assetData) : base(assetID, assetData) { } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /LibreMetaverse/Assets/AssetTypes/AssetCallingCard.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006-2016, openmetaverse.co 3 | * All rights reserved. 4 | * 5 | * - Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * - Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * - Neither the name of the openmetaverse.co nor the names 11 | * of its contributors may be used to endorse or promote products derived from 12 | * this software without specific prior written permission. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | using System; 28 | 29 | namespace OpenMetaverse.Assets 30 | { 31 | /// 32 | /// Represents a Callingcard with AvatarID and Position vector 33 | /// 34 | public class AssetCallingCard : Asset 35 | { 36 | /// Override the base classes AssetType 37 | public override AssetType AssetType => AssetType.CallingCard; 38 | 39 | /// UUID of the Callingcard target avatar 40 | public UUID AvatarID = UUID.Zero; 41 | 42 | /// Construct an Asset of type Callingcard 43 | public AssetCallingCard() { } 44 | 45 | /// 46 | /// Construct an Asset object of type Callingcard 47 | /// 48 | /// A unique specific to this asset 49 | /// A byte array containing the raw asset data 50 | public AssetCallingCard(UUID assetID, byte[] assetData) 51 | : base(assetID, assetData) 52 | { 53 | Decode(); 54 | } 55 | 56 | /// 57 | /// Constuct an asset of type Callingcard 58 | /// 59 | /// UUID of the target avatar 60 | public AssetCallingCard(UUID avatarID) 61 | { 62 | AvatarID = avatarID; 63 | Encode(); 64 | } 65 | 66 | /// 67 | /// Encode the raw contents of a string with the specific Callingcard format 68 | /// 69 | public sealed override void Encode() 70 | { 71 | string temp = "Callingcard version 2\n"; 72 | temp += "avatar_id " + AvatarID + "\n"; 73 | AssetData = Utils.StringToBytes(temp); 74 | } 75 | 76 | /// 77 | /// Decode the raw asset data, populating the AvatarID and Position 78 | /// 79 | /// true if the AssetData was successfully decoded to a UUID and Vector 80 | public sealed override bool Decode() 81 | { 82 | String text = Utils.BytesToString(AssetData); 83 | if (text.ToLower().Contains("callingcard version 2")) 84 | { 85 | AvatarID = new UUID(text.Substring(text.IndexOf("avatar_id", StringComparison.Ordinal) + 10, 36)); 86 | return true; 87 | } 88 | return false; 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /LibreMetaverse/Assets/AssetTypes/AssetClothing.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006-2016, openmetaverse.co 3 | * All rights reserved. 4 | * 5 | * - Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * - Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * - Neither the name of the openmetaverse.co nor the names 11 | * of its contributors may be used to endorse or promote products derived from 12 | * this software without specific prior written permission. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | namespace OpenMetaverse.Assets 28 | { 29 | /// 30 | /// Represents an that can be worn on an avatar 31 | /// such as a Shirt, Pants, etc. 32 | /// 33 | public class AssetClothing : AssetWearable 34 | { 35 | /// Override the base classes AssetType 36 | public override AssetType AssetType => AssetType.Clothing; 37 | 38 | /// Initializes a new instance of an AssetScriptBinary object 39 | public AssetClothing() { } 40 | 41 | /// Initializes a new instance of an AssetScriptBinary object with parameters 42 | /// A unique specific to this asset 43 | /// A byte array containing the raw asset data 44 | public AssetClothing(UUID assetID, byte[] assetData) : base(assetID, assetData) { } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /LibreMetaverse/Assets/AssetTypes/AssetLandmark.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006-2016, openmetaverse.co 3 | * All rights reserved. 4 | * 5 | * - Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * - Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * - Neither the name of the openmetaverse.co nor the names 11 | * of its contributors may be used to endorse or promote products derived from 12 | * this software without specific prior written permission. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | using System; 28 | 29 | namespace OpenMetaverse.Assets 30 | { 31 | /// 32 | /// Represents a Landmark with RegionID and Position vector 33 | /// 34 | public class AssetLandmark : Asset 35 | { 36 | /// Override the base classes AssetType 37 | public override AssetType AssetType => AssetType.Landmark; 38 | 39 | /// UUID of the Landmark target region 40 | public UUID RegionID = UUID.Zero; 41 | /// Local position of the target 42 | public Vector3 Position = Vector3.Zero; 43 | 44 | /// Construct an Asset of type Landmark 45 | public AssetLandmark() { } 46 | 47 | /// 48 | /// Construct an Asset object of type Landmark 49 | /// 50 | /// A unique specific to this asset 51 | /// A byte array containing the raw asset data 52 | public AssetLandmark(UUID assetID, byte[] assetData) 53 | : base(assetID, assetData) 54 | { 55 | } 56 | 57 | /// 58 | /// Encode the raw contents of a string with the specific Landmark format 59 | /// 60 | public sealed override void Encode() 61 | { 62 | string temp = "Landmark version 2\n"; 63 | temp += "region_id " + RegionID + "\n"; 64 | temp += string.Format(Utils.EnUsCulture, "local_pos {0:0.00} {1:0.00} {2:0.00}\n", Position.X, Position.Y, Position.Z); 65 | AssetData = Utils.StringToBytes(temp); 66 | } 67 | 68 | /// 69 | /// Decode the raw asset data, populating the RegionID and Position 70 | /// 71 | /// true if the AssetData was successfully decoded to a UUID and Vector 72 | public sealed override bool Decode() 73 | { 74 | string text = Utils.BytesToString(AssetData); 75 | if (text.ToLower().Contains("landmark version 2")) 76 | { 77 | RegionID = new UUID(text.Substring(text.IndexOf("region_id", StringComparison.Ordinal) + 10, 36)); 78 | const string vecDelim = " "; 79 | string[] vecStrings = text.Substring(text.IndexOf("local_pos", StringComparison.Ordinal) + 10).Split(vecDelim.ToCharArray()); 80 | if (vecStrings.Length == 3) 81 | { 82 | Position = new Vector3(float.Parse(vecStrings[0], System.Globalization.CultureInfo.InvariantCulture), float.Parse(vecStrings[1], System.Globalization.CultureInfo.InvariantCulture), float.Parse(vecStrings[2], System.Globalization.CultureInfo.InvariantCulture)); 83 | return true; 84 | } 85 | } 86 | return false; 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /LibreMetaverse/Assets/AssetTypes/AssetMaterial.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024, Sjofn LLC 3 | * All rights reserved. 4 | * 5 | * - Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * - Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * - Neither the name of the openmetaverse.co nor the names 11 | * of its contributors may be used to endorse or promote products derived from 12 | * this software without specific prior written permission. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | namespace OpenMetaverse.Assets 28 | { 29 | public class AssetMaterial : Asset 30 | { 31 | public override AssetType AssetType => AssetType.Material; 32 | 33 | /// Initializes a new instance of an AssetMaterial object 34 | public AssetMaterial() { } 35 | 36 | /// 37 | /// Construct an Asset object of type Material 38 | /// 39 | /// A unique specific to this asset 40 | /// A byte array containing the raw asset data 41 | public AssetMaterial(UUID assetId, byte[] assetData) 42 | : base(assetId, assetData) 43 | { 44 | Decode(); 45 | } 46 | 47 | public override void Encode() 48 | { 49 | throw new System.NotImplementedException(); 50 | } 51 | 52 | public sealed override bool Decode() 53 | { 54 | throw new System.NotImplementedException(); 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /LibreMetaverse/Assets/AssetTypes/AssetMesh.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006-2016, openmetaverse.co 3 | * All rights reserved. 4 | * 5 | * - Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * - Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * - Neither the name of the openmetaverse.co nor the names 11 | * of its contributors may be used to endorse or promote products derived from 12 | * this software without specific prior written permission. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | using System; 28 | using System.IO; 29 | using OpenMetaverse.StructuredData; 30 | 31 | namespace OpenMetaverse.Assets 32 | { 33 | /// 34 | /// Represents Mesh asset 35 | /// 36 | public class AssetMesh : Asset 37 | { 38 | /// Override the base classes AssetType 39 | public override AssetType AssetType => AssetType.Mesh; 40 | 41 | /// 42 | /// Decoded mesh data 43 | /// 44 | public OSDMap MeshData; 45 | 46 | /// Initializes a new instance of an AssetMesh object 47 | public AssetMesh() { } 48 | 49 | /// Initializes a new instance of an AssetMesh object with parameters 50 | /// A unique specific to this asset 51 | /// A byte array containing the raw asset data 52 | public AssetMesh(UUID assetID, byte[] assetData) 53 | : base(assetID, assetData) 54 | { 55 | } 56 | 57 | /// 58 | /// TODO: Encodes Collada file into LLMesh format 59 | /// 60 | public sealed override void Encode() { } 61 | 62 | /// 63 | /// Decodes mesh asset. See 64 | /// to furter decode it for rendering 65 | /// true 66 | public sealed override bool Decode() 67 | { 68 | try 69 | { 70 | MeshData = new OSDMap(); 71 | 72 | using (MemoryStream data = new MemoryStream(AssetData)) 73 | { 74 | OSDMap header = (OSDMap)OSDParser.DeserializeLLSDBinary(data); 75 | MeshData["asset_header"] = header; 76 | long start = data.Position; 77 | 78 | foreach(string partName in header.Keys) 79 | { 80 | if (header[partName].Type != OSDType.Map) 81 | { 82 | MeshData[partName] = header[partName]; 83 | continue; 84 | } 85 | 86 | OSDMap partInfo = (OSDMap)header[partName]; 87 | if (partInfo["offset"] < 0 || partInfo["size"] == 0) 88 | { 89 | MeshData[partName] = partInfo; 90 | continue; 91 | } 92 | 93 | byte[] part = new byte[partInfo["size"]]; 94 | Buffer.BlockCopy(AssetData, partInfo["offset"] + (int)start, part, 0, part.Length); 95 | MeshData[partName] = Helpers.DecompressOSD(part); 96 | } 97 | } 98 | return true; 99 | } 100 | catch (Exception ex) 101 | { 102 | Logger.Log("Failed to decode mesh asset", Helpers.LogLevel.Error, ex); 103 | return false; 104 | } 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /LibreMetaverse/Assets/AssetTypes/AssetMutable.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006-2016, openmetaverse.co 3 | * All rights reserved. 4 | * 5 | * - Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * - Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * - Neither the name of the openmetaverse.co nor the names 11 | * of its contributors may be used to endorse or promote products derived from 12 | * this software without specific prior written permission. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | namespace OpenMetaverse.Assets 28 | { 29 | /// 30 | /// Represents an Animation 31 | /// 32 | public class AssetMutable : Asset 33 | { 34 | public AssetType currentType; 35 | 36 | /// Override the base classes AssetType 37 | public override AssetType AssetType => currentType; 38 | 39 | /// Default Constructor 40 | public AssetMutable(AssetType type) 41 | { 42 | currentType = type; 43 | } 44 | 45 | /// 46 | /// Construct an Asset object of type Animation 47 | /// 48 | /// Asset type 49 | /// A unique specific to this asset 50 | /// A byte array containing the raw asset data 51 | public AssetMutable(AssetType type, UUID assetID, byte[] assetData) 52 | : base(assetID, assetData) 53 | { 54 | currentType = type; 55 | } 56 | 57 | public override void Encode() { } 58 | public override bool Decode() { return true; } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /LibreMetaverse/Assets/AssetTypes/AssetScriptBinary.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006-2016, openmetaverse.co 3 | * All rights reserved. 4 | * 5 | * - Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * - Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * - Neither the name of the openmetaverse.co nor the names 11 | * of its contributors may be used to endorse or promote products derived from 12 | * this software without specific prior written permission. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | namespace OpenMetaverse.Assets 28 | { 29 | /// 30 | /// Represents an AssetScriptBinary object containing the 31 | /// LSO compiled bytecode of an LSL script 32 | /// 33 | public class AssetScriptBinary : Asset 34 | { 35 | /// Override the base classes AssetType 36 | public override AssetType AssetType => AssetType.LSLBytecode; 37 | 38 | /// Initializes a new instance of an AssetScriptBinary object 39 | public AssetScriptBinary() { } 40 | 41 | /// Initializes a new instance of an AssetScriptBinary object with parameters 42 | /// A unique specific to this asset 43 | /// A byte array containing the raw asset data 44 | public AssetScriptBinary(UUID assetID, byte[] assetData) 45 | : base(assetID, assetData) 46 | { 47 | } 48 | 49 | /// 50 | /// TODO: Encodes a scripts contents into a LSO Bytecode file 51 | /// 52 | public sealed override void Encode() { } 53 | 54 | /// 55 | /// TODO: Decode LSO Bytecode into a string 56 | /// 57 | /// true 58 | public sealed override bool Decode() { return true; } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /LibreMetaverse/Assets/AssetTypes/AssetScriptText.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006-2016, openmetaverse.co 3 | * All rights reserved. 4 | * 5 | * - Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * - Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * - Neither the name of the openmetaverse.co nor the names 11 | * of its contributors may be used to endorse or promote products derived from 12 | * this software without specific prior written permission. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | namespace OpenMetaverse.Assets 28 | { 29 | /// 30 | /// Represents an LSL Text object containing a string of UTF encoded characters 31 | /// 32 | public class AssetScriptText : Asset 33 | { 34 | /// Override the base classes AssetType 35 | public override AssetType AssetType => AssetType.LSLText; 36 | 37 | /// A string of characters represting the script contents 38 | public string Source; 39 | 40 | /// Initializes a new AssetScriptText object 41 | public AssetScriptText() { } 42 | 43 | /// 44 | /// Initializes a new AssetScriptText object with parameters 45 | /// 46 | /// A unique specific to this asset 47 | /// A byte array containing the raw asset data 48 | public AssetScriptText(UUID assetID, byte[] assetData) : base(assetID, assetData) { } 49 | 50 | /// 51 | /// Encode a string containing the scripts contents into byte encoded AssetData 52 | /// 53 | public sealed override void Encode() 54 | { 55 | AssetData = Utils.StringToBytes(Source); 56 | } 57 | 58 | /// 59 | /// Decode a byte array containing the scripts contents into a string 60 | /// 61 | /// true if decoding is successful 62 | public sealed override bool Decode() 63 | { 64 | Source = Utils.BytesToString(AssetData); 65 | return true; 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /LibreMetaverse/Assets/AssetTypes/AssetSettings.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024, Sjofn LLC 3 | * All rights reserved. 4 | * 5 | * - Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * - Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * - Neither the name of the openmetaverse.co nor the names 11 | * of its contributors may be used to endorse or promote products derived from 12 | * this software without specific prior written permission. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | using OpenMetaverse.StructuredData; 28 | 29 | namespace OpenMetaverse.Assets 30 | { 31 | public class AssetSettings : Asset 32 | { 33 | public override AssetType AssetType => AssetType.Settings; 34 | 35 | public OSD Settings; 36 | 37 | /// Initializes a new instance of an AssetSettings object 38 | public AssetSettings() { } 39 | 40 | /// 41 | /// Construct an Asset object of type Settings 42 | /// 43 | /// A unique specific to this asset 44 | /// A byte array containing the raw asset data 45 | public AssetSettings(UUID assetId, byte[] assetData) 46 | : base(assetId, assetData) 47 | { 48 | Decode(); 49 | } 50 | 51 | public override void Encode() 52 | { 53 | AssetData = Utils.StringToBytes(Settings.AsString()); 54 | } 55 | 56 | public sealed override bool Decode() 57 | { 58 | if (AssetData != null && AssetData.Length > 0) 59 | { 60 | try 61 | { 62 | var raw = Utils.BytesToString(AssetData); 63 | Settings = OSD.FromString(raw); 64 | return true; 65 | } 66 | catch 67 | { 68 | return false; 69 | } 70 | } 71 | 72 | return false; 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /LibreMetaverse/Assets/AssetTypes/AssetTexture.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006-2016, openmetaverse.co 3 | * Copyright (c) 2021-2024, Sjofn LLC. 4 | * All rights reserved. 5 | * 6 | * - Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * - Redistributions of source code must retain the above copyright notice, this 10 | * list of conditions and the following disclaimer. 11 | * - Neither the name of the openmetaverse.co nor the names 12 | * of its contributors may be used to endorse or promote products derived from 13 | * this software without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | * POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | using CoreJ2K; 29 | using OpenMetaverse.Imaging; 30 | 31 | namespace OpenMetaverse.Assets 32 | { 33 | /// 34 | /// Represents a texture 35 | /// 36 | public class AssetTexture : Asset 37 | { 38 | /// Override the base classes AssetType 39 | public override AssetType AssetType => AssetType.Texture; 40 | 41 | /// A object containing image data 42 | public ManagedImage Image; 43 | 44 | /// 45 | public int Components; 46 | 47 | /// Initializes a new instance of an AssetTexture object 48 | public AssetTexture() { } 49 | 50 | /// 51 | /// Initializes a new instance of an AssetTexture object 52 | /// 53 | /// A unique specific to this asset 54 | /// A byte array containing the raw asset data 55 | public AssetTexture(UUID assetID, byte[] assetData) : base(assetID, assetData) { } 56 | 57 | /// 58 | /// Initializes a new instance of an AssetTexture object 59 | /// 60 | /// A object containing texture data 61 | public AssetTexture(ManagedImage image) 62 | { 63 | Image = image; 64 | Components = 0; 65 | if ((Image.Channels & ManagedImage.ImageChannels.Color) != 0) 66 | Components += 3; 67 | if ((Image.Channels & ManagedImage.ImageChannels.Gray) != 0) 68 | ++Components; 69 | if ((Image.Channels & ManagedImage.ImageChannels.Bump) != 0) 70 | ++Components; 71 | if ((Image.Channels & ManagedImage.ImageChannels.Alpha) != 0) 72 | ++Components; 73 | } 74 | 75 | /// 76 | /// Populates the byte array with a JPEG2000 77 | /// encoded image created from the data in 78 | /// 79 | public sealed override void Encode() 80 | { 81 | AssetData = J2K.ToBytes(Image.ExportBitmap()); 82 | } 83 | 84 | /// 85 | /// Decodes the JPEG2000 data in > to the 86 | /// object 87 | /// 88 | /// True if the decoding was successful, otherwise false 89 | public sealed override bool Decode() 90 | { 91 | if (AssetData == null || AssetData.Length <= 0) { return false; } 92 | 93 | this.Components = 0; 94 | 95 | var image = J2kImage.FromBytes(AssetData); 96 | Image = new ManagedImage(image); 97 | 98 | if ((Image.Channels & ManagedImage.ImageChannels.Color) != 0) 99 | Components += 3; 100 | if ((Image.Channels & ManagedImage.ImageChannels.Gray) != 0) 101 | ++Components; 102 | if ((Image.Channels & ManagedImage.ImageChannels.Bump) != 0) 103 | ++Components; 104 | if ((Image.Channels & ManagedImage.ImageChannels.Alpha) != 0) 105 | ++Components; 106 | 107 | return true; 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /LibreMetaverse/Formatters/UUIDFormatter.cs: -------------------------------------------------------------------------------- 1 | using MessagePack; 2 | using MessagePack.Formatters; 3 | using System; 4 | using System.Buffers; 5 | using System.Collections.Generic; 6 | using System.Text; 7 | 8 | namespace OpenMetaverse.Formatters 9 | { 10 | public class UUIDFormatter : IMessagePackFormatter 11 | { 12 | public static readonly UUIDFormatter Instance = new UUIDFormatter(); 13 | 14 | public void Serialize(ref MessagePackWriter writer, UUID value, MessagePackSerializerOptions options) 15 | { 16 | writer.Write(value.GetBytes()); 17 | } 18 | 19 | public UUID Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) 20 | { 21 | var sequence = reader.ReadBytes(); 22 | if (sequence == null) 23 | { 24 | throw new MessagePackSerializationException("Invalid UUID"); 25 | } 26 | 27 | var bytes = sequence.Value.ToArray(); 28 | return new UUID(bytes, 0); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /LibreMetaverse/Interfaces/IByteBufferPool.cs: -------------------------------------------------------------------------------- 1 | namespace OpenMetaverse.Interfaces 2 | { 3 | /// 4 | /// Interface to a class that can supply cached byte arrays 5 | /// 6 | public interface IByteBufferPool 7 | { 8 | /// 9 | /// Leases a byte array from the pool 10 | /// 11 | /// Minimum size the array must be to satisfy this request 12 | /// A poooled array that is at least minSize 13 | byte[] LeaseBytes(int minSize); 14 | 15 | /// 16 | /// Returns a byte array to the pool 17 | /// 18 | /// The bytes being returned 19 | void ReturnBytes(byte[] bytes); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /LibreMetaverse/Interfaces/IMessage.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006-2016, openmetaverse.co 3 | * All rights reserved. 4 | * 5 | * - Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * - Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * - Neither the name of the openmetaverse.co nor the names 11 | * of its contributors may be used to endorse or promote products derived from 12 | * this software without specific prior written permission. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | using OpenMetaverse.StructuredData; 28 | 29 | 30 | namespace OpenMetaverse.Interfaces 31 | { 32 | /// 33 | /// Interface requirements for Messaging system 34 | /// 35 | public interface IMessage 36 | { 37 | OSDMap Serialize(); 38 | void Deserialize(OSDMap map); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /LibreMetaverse/Interfaces/IRendering.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006-2016, openmetaverse.co 3 | * All rights reserved. 4 | * 5 | * - Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * - Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * - Neither the name of the openmetaverse.co nor the names 11 | * of its contributors may be used to endorse or promote products derived from 12 | * this software without specific prior written permission. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | using System; 28 | using System.Collections.Generic; 29 | using SkiaSharp; 30 | 31 | namespace OpenMetaverse.Rendering 32 | { 33 | [AttributeUsage(AttributeTargets.Class)] 34 | public class RendererNameAttribute : System.Attribute 35 | { 36 | private string _name; 37 | 38 | public RendererNameAttribute(string name) 39 | { 40 | _name = name; 41 | } 42 | 43 | public override string ToString() 44 | { 45 | return _name; 46 | } 47 | } 48 | 49 | /// 50 | /// Abstract base for rendering plugins 51 | /// 52 | public interface IRendering 53 | { 54 | /// 55 | /// Generates a basic mesh structure from a primitive 56 | /// 57 | /// Primitive to generate the mesh from 58 | /// Level of detail to generate the mesh at 59 | /// The generated mesh 60 | SimpleMesh GenerateSimpleMesh(Primitive prim, DetailLevel lod); 61 | 62 | /// 63 | /// Generates a basic mesh structure from a sculpted primitive and 64 | /// texture 65 | /// 66 | /// Sculpted primitive to generate the mesh from 67 | /// Sculpt texture 68 | /// Level of detail to generate the mesh at 69 | /// The generated mesh 70 | SimpleMesh GenerateSimpleSculptMesh(Primitive prim, SKBitmap sculptTexture, DetailLevel lod); 71 | 72 | /// 73 | /// Generates a series of faces, each face containing a mesh and 74 | /// metadata 75 | /// 76 | /// Primitive to generate the mesh from 77 | /// Level of detail to generate the mesh at 78 | /// The generated mesh 79 | FacetedMesh GenerateFacetedMesh(Primitive prim, DetailLevel lod); 80 | 81 | /// 82 | /// Generates a series of faces for a sculpted prim, each face 83 | /// containing a mesh and metadata 84 | /// 85 | /// Sculpted primitive to generate the mesh from 86 | /// Sculpt texture 87 | /// Level of detail to generate the mesh at 88 | /// The generated mesh 89 | FacetedMesh GenerateFacetedSculptMesh(Primitive prim, SKBitmap sculptTexture, DetailLevel lod); 90 | 91 | /// 92 | /// Apply texture coordinate modifications from a 93 | /// to a list of vertices 94 | /// 95 | /// Vertex list to modify texture coordinates for 96 | /// Center-point of the face 97 | /// Face texture parameters 98 | /// Scale of the prim 99 | void TransformTexCoords (List vertices, Vector3 center, Primitive.TextureEntryFace teFace, Vector3 primScale); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /LibreMetaverse/Inventory/InventoryNode.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006-2016, openmetaverse.co 3 | * Copyright (c) 2021-2024, Sjofn LLC. 4 | * All rights reserved. 5 | * 6 | * - Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * - Redistributions of source code must retain the above copyright notice, this 10 | * list of conditions and the following disclaimer. 11 | * - Neither the name of the openmetaverse.co nor the names 12 | * of its contributors may be used to endorse or promote products derived from 13 | * this software without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | * POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | using System; 29 | using MessagePack; 30 | 31 | namespace OpenMetaverse 32 | { 33 | [MessagePackObject] 34 | public partial class InventoryNode 35 | { 36 | private InventoryNodeDictionary nodes; 37 | 38 | [Key("Data")] 39 | public InventoryBase Data { get; set; } 40 | 41 | /// User data 42 | [IgnoreMember] 43 | public object Tag { get; set; } 44 | 45 | [IgnoreMember] 46 | public InventoryNode Parent { get; set; } 47 | 48 | [IgnoreMember] 49 | public InventoryNodeDictionary Nodes 50 | { 51 | get => nodes ?? (nodes = new InventoryNodeDictionary(this)); 52 | set => nodes = value; 53 | } 54 | 55 | /// 56 | /// For inventory folder nodes specifies weather the folder needs to be 57 | /// refreshed from the server 58 | /// 59 | [IgnoreMember] 60 | public bool NeedsUpdate { get; set; } = true; 61 | 62 | [IgnoreMember] 63 | public DateTime ModifyTime 64 | { 65 | get 66 | { 67 | if (Data is InventoryItem item) 68 | { 69 | return item.CreationDate; 70 | } 71 | DateTime newest = default(DateTime); //.MinValue; 72 | if (Data is InventoryFolder) 73 | { 74 | foreach (var node in Nodes.Values) 75 | { 76 | var t = node.ModifyTime; 77 | if (t > newest) newest = t; 78 | } 79 | } 80 | return newest; 81 | } 82 | } 83 | 84 | public void Sort() 85 | { 86 | Nodes.Sort(); 87 | } 88 | 89 | public InventoryNode() 90 | { 91 | } 92 | 93 | /// 94 | public InventoryNode(InventoryBase data) 95 | { 96 | this.Data = data; 97 | } 98 | 99 | /// 100 | /// De-serialization constructor for the InventoryNode Class 101 | /// 102 | public InventoryNode(InventoryBase data, InventoryNode parent) 103 | { 104 | this.Data = data; 105 | this.Parent = parent; 106 | 107 | if (parent != null) 108 | { 109 | // Add this node to the collection of parent nodes 110 | lock (parent.Nodes.SyncRoot) parent.Nodes.Add(data.UUID, this); 111 | } 112 | } 113 | 114 | public override string ToString() 115 | { 116 | return this.Data == null ? "[Empty Node]" : this.Data.ToString(); 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /LibreMetaverse/LibreMetaverse.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | LibreMetaverse 4 | LibreMetaverse 5 | LibreMetaverse allows your code to read and work with data send across a SecondLife, Halcyon, OpenSimulator, or related connection. 6 | Library 7 | LibreMetaverse 8 | true 9 | true 10 | true 11 | true 12 | true 13 | snupkg 14 | $(NoWarn);CS0419;CS8981;CS1591;CS1574 15 | netstandard2.0;net8.0;net9.0 16 | AnyCPU 17 | ..\bin\ 18 | 19 | 20 | TRACE;DEBUG 21 | 22 | 23 | true 24 | pdbonly 25 | TRACE 26 | True 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /LibreMetaverse/LocationParser.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Sjofn, LLC 3 | * All rights reserved. 4 | * 5 | * - Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * - Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * - Neither the name of the openmetaverse.co nor the names 11 | * of its contributors may be used to endorse or promote products derived from 12 | * this software without specific prior written permission. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | using System; 28 | 29 | namespace OpenMetaverse 30 | { 31 | public class LocationParser 32 | { 33 | public string Sim { get; } 34 | public int X { get; } 35 | public int Y { get; } 36 | public int Z { get; } 37 | 38 | public LocationParser(string location) 39 | { 40 | if (location == null ) { throw new ArgumentNullException(nameof(location), "Location cannot be null."); } 41 | if (location.Length == 0) { throw new ArgumentException("Location cannot be empty."); } 42 | 43 | string toParse; 44 | if (location.StartsWith("secondlife://")) { toParse = location.Substring(13); } 45 | else if (location.StartsWith("uri:")) { toParse = location.Substring(4); } 46 | else { toParse = location; } 47 | 48 | string[] elements = toParse.Split('/'); 49 | Sim = elements[0]; 50 | int parsed; 51 | X = (elements.Length > 1 && int.TryParse(elements[1], out parsed)) ? parsed : 128; 52 | Y = (elements.Length > 2 && int.TryParse(elements[2], out parsed)) ? parsed : 128; 53 | Z = (elements.Length > 3 && int.TryParse(elements[3], out parsed)) ? parsed : 0; 54 | } 55 | 56 | public string GetRawLocation() 57 | { 58 | return $"{Sim}/{X}/{Y}/{Z}"; 59 | } 60 | 61 | public string GetSlurl() 62 | { 63 | return $"secondlife://{Sim}/{X}/{Y}/{Z}/"; 64 | } 65 | 66 | public string GetStartLocationUri() 67 | { 68 | return $"uri:{Sim}&{X}&{Y}&{Z}"; 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /LibreMetaverse/Materials/LegacyMaterial.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using OpenMetaverse; 4 | using OpenMetaverse.StructuredData; 5 | 6 | namespace LibreMetaverse.Materials 7 | { 8 | public class LegacyMaterial 9 | { 10 | public UUID ID { get; set; } 11 | 12 | public UUID NormalMap { get; set; } 13 | public double NormalMapOffsetX { get; set; } 14 | public double NormalMapOffsetY { get; set; } 15 | public double NormalMapRepeatX { get; set; } 16 | public double NormalMapRepeatY { get; set; } 17 | public double NormalMapRotation { get; set; } 18 | 19 | public UUID SpecularMap { get; set; } 20 | public double SpecularMapOffsetX { get; set; } 21 | public double SpecularMapOffsetY { get; set; } 22 | public double SpecularMapRepeatX { get; set; } 23 | public double SpecularMapRepeatY { get; set; } 24 | public double SpecularMapRotation { get; set; } 25 | 26 | public Color4 SpecularColor { get; set; } 27 | public byte SpecularExponent { get; set; } 28 | public byte EnvironmentIntensity { get; set; } 29 | public byte AlphaMaskCutoff { get; set; } 30 | 31 | public LegacyMaterialAlphaMode DiffuseAlphaMode { get; set; } 32 | 33 | public LegacyMaterial() 34 | { 35 | 36 | } 37 | 38 | private const double MaterialsMultiplier = 10000.0; 39 | 40 | public LegacyMaterial(OSDMap mapOrig) 41 | { 42 | if (!(mapOrig.ContainsKey("ID") && mapOrig.ContainsKey("Material"))) 43 | { 44 | throw new InvalidOperationException("Legacy material needs to contain 'ID' and 'Material' keys."); 45 | } 46 | 47 | if (mapOrig["ID"] is OSDBinary idBinary) 48 | { 49 | ID = new UUID(idBinary.AsBinary(), 0); 50 | } 51 | else if (mapOrig["ID"] is OSDArray idArray) 52 | { 53 | ID = new UUID(idArray.AsBinary(), 0); 54 | } 55 | else if (mapOrig["ID"] is OSDUUID idUUID) 56 | { 57 | ID = idUUID.AsUUID(); 58 | } 59 | else 60 | { 61 | throw new InvalidOperationException("LegacyMaterial ID is of an unknown type " + mapOrig["ID"].Type); 62 | } 63 | 64 | if (mapOrig["Material"] is OSDMap map) 65 | { 66 | NormalMap = map["NormMap"].AsUUID(); 67 | NormalMapOffsetX = map["NormOffsetX"].AsInteger() / MaterialsMultiplier; 68 | NormalMapOffsetY = map["NormOffsetY"].AsInteger() / MaterialsMultiplier; 69 | NormalMapRepeatX = map["NormRepeatX"].AsInteger() / MaterialsMultiplier; 70 | NormalMapRepeatY = map["NormRepeatX"].AsInteger() / MaterialsMultiplier; 71 | NormalMapRotation = map["NormRotation"].AsInteger() / MaterialsMultiplier; 72 | 73 | SpecularMap = map["NormMap"].AsUUID(); 74 | SpecularMapOffsetX = map["NormOffsetX"].AsInteger() / MaterialsMultiplier; 75 | SpecularMapOffsetY = map["NormOffsetY"].AsInteger() / MaterialsMultiplier; 76 | SpecularMapRepeatX = map["NormRepeatX"].AsInteger() / MaterialsMultiplier; 77 | SpecularMapRepeatY = map["NormRepeatX"].AsInteger() / MaterialsMultiplier; 78 | SpecularMapRotation = map["NormRotation"].AsInteger() / MaterialsMultiplier; 79 | 80 | SpecularColor = map["SpecColor"].AsColor4(); 81 | SpecularExponent = (byte)map["SpecExp"].AsInteger(); 82 | EnvironmentIntensity = (byte)map["EnvIntensity"].AsInteger(); 83 | AlphaMaskCutoff = (byte)map["AlphaMaskCutoff"].AsInteger(); 84 | DiffuseAlphaMode = (LegacyMaterialAlphaMode)map["DiffuseAlphaMode"].AsInteger(); 85 | } 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /LibreMetaverse/Materials/LegacyMaterialAlphaMode.cs: -------------------------------------------------------------------------------- 1 | namespace LibreMetaverse.Materials 2 | { 3 | public enum LegacyMaterialAlphaMode : byte 4 | { 5 | None = 0, 6 | Blend = 1, 7 | Mask = 2, 8 | Emissive = 3, 9 | Default = 4, 10 | } 11 | } -------------------------------------------------------------------------------- /LibreMetaverse/Messages/Messages.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006-2016, openmetaverse.co 3 | * All rights reserved. 4 | * 5 | * - Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * - Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * - Neither the name of the openmetaverse.co nor the names 11 | * of its contributors may be used to endorse or promote products derived from 12 | * this software without specific prior written permission. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | using System; 28 | using System.Collections.Generic; 29 | using System.Net; 30 | using OpenMetaverse.StructuredData; 31 | 32 | namespace OpenMetaverse.Messages 33 | { 34 | public static partial class MessageUtils 35 | { 36 | public static IPAddress ToIP(OSD osd) 37 | { 38 | byte[] binary = osd.AsBinary(); 39 | if (binary != null && binary.Length == 4) 40 | return new IPAddress(binary); 41 | else 42 | return IPAddress.Any; 43 | } 44 | 45 | public static OSD FromIP(IPAddress address) 46 | { 47 | if (address != null && !Equals(address, IPAddress.Any)) 48 | return OSD.FromBinary(address.GetAddressBytes()); 49 | else 50 | return new OSD(); 51 | } 52 | 53 | public static Dictionary ToDictionaryString(OSD osd) 54 | { 55 | if (osd.Type == OSDType.Map) 56 | { 57 | OSDMap map = (OSDMap)osd; 58 | Dictionary dict = new Dictionary(map.Count); 59 | foreach (KeyValuePair entry in map) 60 | dict.Add(entry.Key, entry.Value.AsString()); 61 | return dict; 62 | } 63 | 64 | return new Dictionary(0); 65 | } 66 | 67 | public static Dictionary ToDictionaryUri(OSD osd) 68 | { 69 | if (osd.Type == OSDType.Map) 70 | { 71 | OSDMap map = (OSDMap)osd; 72 | Dictionary dict = new Dictionary(map.Count); 73 | foreach (KeyValuePair entry in map) 74 | dict.Add(new Uri(entry.Key), entry.Value.AsUri()); 75 | return dict; 76 | } 77 | 78 | return new Dictionary(0); 79 | } 80 | 81 | public static OSDMap FromDictionaryString(Dictionary dict) 82 | { 83 | if (dict != null) 84 | { 85 | OSDMap map = new OSDMap(dict.Count); 86 | foreach (KeyValuePair entry in dict) 87 | map.Add(entry.Key, OSD.FromString(entry.Value)); 88 | return map; 89 | } 90 | 91 | return new OSDMap(0); 92 | } 93 | 94 | public static OSDMap FromDictionaryUri(Dictionary dict) 95 | { 96 | if (dict != null) 97 | { 98 | OSDMap map = new OSDMap(dict.Count); 99 | foreach (KeyValuePair entry in dict) 100 | map.Add(entry.Key.ToString(), OSD.FromUri(entry.Value)); 101 | return map; 102 | } 103 | 104 | return new OSDMap(0); 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /LibreMetaverse/Repeat.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2025, Sjofn LLC. 3 | * All rights reserved. 4 | * 5 | * - Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * - Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * - Neither the name of the openmetaverse.co nor the names 11 | * of its contributors may be used to endorse or promote products derived from 12 | * this software without specific prior written permission. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | using System; 28 | using System.Threading.Tasks; 29 | using System.Threading; 30 | 31 | namespace LibreMetaverse 32 | { 33 | internal static class Repeat 34 | { 35 | /// 36 | /// Execute a given at a given interval in a loop 37 | /// 38 | /// Interval for executing action 39 | /// Essentially the action you wish to execute 40 | /// Cancellation token 41 | /// When set, executes the action immediately instead of waiting for the interval 42 | /// 43 | public static Task Interval( 44 | TimeSpan pollInterval, 45 | Action action, 46 | CancellationToken token, 47 | bool immediately = false) 48 | { 49 | return Task.Factory.StartNew( 50 | () => 51 | { 52 | if (immediately) { action(); } 53 | 54 | for (; ; ) 55 | { 56 | if (token.WaitCancellationRequested(pollInterval)) { break; } 57 | action(); 58 | } 59 | }, token, TaskCreationOptions.LongRunning, TaskScheduler.Default); 60 | } 61 | 62 | /// 63 | /// Execute a given at a given interval in a loop 64 | /// 65 | /// Interval for executing action 66 | /// Essentially the action you wish to execute 67 | /// Cancellation token 68 | /// When set, executes the action immediately instead of waiting for the interval 69 | /// 70 | public static Task IntervalAsync( 71 | TimeSpan pollInterval, 72 | Func asyncAction, 73 | CancellationToken token, 74 | bool immediately = false) 75 | { 76 | return Task.Factory.StartNew( 77 | async () => 78 | { 79 | if (immediately) 80 | { 81 | await asyncAction(); } 82 | 83 | for (; ; ) 84 | { 85 | if (token.WaitCancellationRequested(pollInterval)) { break; } 86 | await asyncAction(); 87 | } 88 | }, token, TaskCreationOptions.LongRunning, TaskScheduler.Default); 89 | } 90 | } 91 | 92 | internal static class CancellationTokenExtensions 93 | { 94 | public static bool WaitCancellationRequested( 95 | this CancellationToken token, 96 | TimeSpan timeout) 97 | { 98 | return token.WaitHandle.WaitOne(timeout); 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /LibreMetaverse/ThreadUtil.cs: -------------------------------------------------------------------------------- 1 | // Written by Peter A. Bromberg, found at 2 | // http://www.eggheadcafe.com/articles/20060727.asp 3 | 4 | using System; 5 | 6 | /// 7 | /// 8 | /// 9 | public class ThreadUtil 10 | { 11 | /// 12 | /// Delegate to wrap another delegate and its arguments 13 | /// 14 | /// 15 | /// 16 | delegate void DelegateWrapper(Delegate d, object[] args); 17 | 18 | /// 19 | /// An instance of DelegateWrapper which calls InvokeWrappedDelegate, 20 | /// which in turn calls the DynamicInvoke method of the wrapped 21 | /// delegate 22 | /// 23 | static readonly DelegateWrapper wrapperInstance = InvokeWrappedDelegate; 24 | 25 | /// 26 | /// Callback used to call EndInvoke on the asynchronously 27 | /// invoked DelegateWrapper 28 | /// 29 | static readonly AsyncCallback callback = EndWrapperInvoke; 30 | 31 | /// 32 | /// Executes the specified delegate with the specified arguments 33 | /// asynchronously on a thread pool thread 34 | /// 35 | /// 36 | /// 37 | public static void FireAndForget(Delegate d, params object[] args) 38 | { 39 | // Invoke the wrapper asynchronously, which will then 40 | // execute the wrapped delegate synchronously (in the 41 | // thread pool thread) 42 | if (d != null) wrapperInstance.BeginInvoke(d, args, callback, null); 43 | } 44 | 45 | /// 46 | /// Invokes the wrapped delegate synchronously 47 | /// 48 | /// 49 | /// 50 | private static void InvokeWrappedDelegate(Delegate d, object[] args) 51 | { 52 | d.DynamicInvoke(args); 53 | } 54 | 55 | /// 56 | /// Calls EndInvoke on the wrapper and Close on the resulting WaitHandle 57 | /// to prevent resource leaks 58 | /// 59 | /// 60 | public static void EndWrapperInvoke(IAsyncResult ar) 61 | { 62 | wrapperInstance.EndInvoke(ar); 63 | ar.AsyncWaitHandle.Close(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /LibreMetaverse/Threading/Disposers/IAdvancedDisposable.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024, Sjofn LLC 3 | * All rights reserved. 4 | * 5 | * - Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * - Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * - Neither the name of the openmetaverse.co nor the names 11 | * of its contributors may be used to endorse or promote products derived from 12 | * this software without specific prior written permission. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | using System; 28 | 29 | namespace LibreMetaverse.Threading.Disposers 30 | { 31 | /// 32 | /// Interface for disposable objects that can inform they are already 33 | /// disposed without throwing an exception. 34 | /// 35 | public interface IAdvancedDisposable: 36 | IDisposable 37 | { 38 | /// 39 | /// Gets a value indicating if the object was already disposed. 40 | /// 41 | bool WasDisposed { get; } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /LibreMetaverse/Threading/Disposers/IUpgradeableLock.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024, Sjofn LLC 3 | * All rights reserved. 4 | * 5 | * - Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * - Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * - Neither the name of the openmetaverse.co nor the names 11 | * of its contributors may be used to endorse or promote products derived from 12 | * this software without specific prior written permission. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | using System; 28 | 29 | namespace LibreMetaverse.Threading.Disposers 30 | { 31 | /// 32 | /// Interface implemented by ReaderWriterLocks' result to the 33 | /// UpgradeableLock method. 34 | /// 35 | public interface IUpgradeableLock: 36 | IDisposable 37 | { 38 | /// 39 | /// Upgrades this lock to a write-lock, returning an object 40 | /// so you can return to the upgradeable lock mode. 41 | /// 42 | IDisposable DisposableUpgrade(); 43 | 44 | /// 45 | /// Upgrades this lock to an write lock, but it is 46 | /// not possible to return to the upgradeable lock any more. 47 | /// At the end, both the upgradeable and the write-lock 48 | /// will be released. 49 | /// 50 | bool Upgrade(); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /LibreMetaverse/Threading/Disposers/OptimisticReadLock.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024, Sjofn LLC 3 | * All rights reserved. 4 | * 5 | * - Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * - Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * - Neither the name of the openmetaverse.co nor the names 11 | * of its contributors may be used to endorse or promote products derived from 12 | * this software without specific prior written permission. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | using System; 28 | 29 | namespace LibreMetaverse.Threading.Disposers 30 | { 31 | /// 32 | /// Class returned by ReadLock method. 33 | /// 34 | public struct OptimisticReadLock: 35 | IDisposable 36 | { 37 | private OptimisticReaderWriterLock _lock; 38 | internal OptimisticReadLock(OptimisticReaderWriterLock yieldLock) 39 | { 40 | _lock = yieldLock; 41 | } 42 | 43 | /// 44 | /// Releases the lock. 45 | /// 46 | public void Dispose() 47 | { 48 | var yieldLock = _lock; 49 | 50 | if (yieldLock != null) 51 | { 52 | _lock = null; 53 | yieldLock.ExitReadLock(); 54 | } 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /LibreMetaverse/Threading/Disposers/OptimisticUpgradeableLock.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024, Sjofn LLC 3 | * All rights reserved. 4 | * 5 | * - Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * - Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * - Neither the name of the openmetaverse.co nor the names 11 | * of its contributors may be used to endorse or promote products derived from 12 | * this software without specific prior written permission. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | using System; 28 | 29 | namespace LibreMetaverse.Threading.Disposers 30 | { 31 | /// 32 | /// Class returned by UpgradeableLock method. 33 | /// 34 | public struct OptimisticUpgradeableLock: 35 | IUpgradeableLock 36 | { 37 | private OptimisticReaderWriterLock _lock; 38 | private bool _upgraded; 39 | 40 | internal OptimisticUpgradeableLock(OptimisticReaderWriterLock yieldLock) 41 | { 42 | _lock = yieldLock; 43 | _upgraded = false; 44 | } 45 | 46 | /// 47 | /// Upgrades this lock to a write-lock. 48 | /// 49 | public OptimisticWriteLock DisposableUpgrade() 50 | { 51 | var yieldLock = _lock; 52 | if (yieldLock == null) 53 | throw new ObjectDisposedException(GetType().FullName); 54 | 55 | yieldLock.UncheckedUpgradeToWriteLock(); 56 | return new OptimisticWriteLock(yieldLock); 57 | } 58 | 59 | /// 60 | /// Upgrades the lock to a write-lock. 61 | /// Returns true if the lock was upgraded, false if it was 62 | /// already upgraded before. 63 | /// 64 | public bool Upgrade() 65 | { 66 | var yieldLock = _lock; 67 | if (yieldLock == null) 68 | throw new ObjectDisposedException(GetType().FullName); 69 | 70 | if (_upgraded) 71 | return false; 72 | 73 | yieldLock.UncheckedUpgradeToWriteLock(); 74 | _upgraded = true; 75 | return true; 76 | } 77 | 78 | /// 79 | /// Releases the lock. 80 | /// 81 | public void Dispose() 82 | { 83 | var yieldLock = _lock; 84 | 85 | if (yieldLock != null) 86 | { 87 | _lock = null; 88 | 89 | yieldLock.ExitUpgradeableLock(_upgraded); 90 | } 91 | } 92 | 93 | IDisposable IUpgradeableLock.DisposableUpgrade() 94 | { 95 | return DisposableUpgrade(); 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /LibreMetaverse/Threading/Disposers/OptimisticWriteLock.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024, Sjofn LLC 3 | * All rights reserved. 4 | * 5 | * - Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * - Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * - Neither the name of the openmetaverse.co nor the names 11 | * of its contributors may be used to endorse or promote products derived from 12 | * this software without specific prior written permission. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | using System; 28 | 29 | namespace LibreMetaverse.Threading.Disposers 30 | { 31 | /// 32 | /// Class returned by WriteLock method. 33 | /// 34 | public struct OptimisticWriteLock: 35 | IDisposable 36 | { 37 | private OptimisticReaderWriterLock _lock; 38 | internal OptimisticWriteLock(OptimisticReaderWriterLock yieldLock) 39 | { 40 | _lock = yieldLock; 41 | } 42 | 43 | /// 44 | /// Releases the lock. 45 | /// 46 | public void Dispose() 47 | { 48 | var yieldLock = _lock; 49 | 50 | if (yieldLock != null) 51 | { 52 | _lock = null; 53 | yieldLock.ExitWriteLock(); 54 | } 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /LibreMetaverse/Threading/Disposers/SpinReadLock.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024, Sjofn LLC 3 | * All rights reserved. 4 | * 5 | * - Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * - Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * - Neither the name of the openmetaverse.co nor the names 11 | * of its contributors may be used to endorse or promote products derived from 12 | * this software without specific prior written permission. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | using System; 28 | 29 | namespace LibreMetaverse.Threading.Disposers 30 | { 31 | /// 32 | /// Class returned by ReadLock method. 33 | /// 34 | public struct SpinReadLock: 35 | IDisposable 36 | { 37 | private SpinReaderWriterLock _lock; 38 | internal SpinReadLock(SpinReaderWriterLock yieldLock) 39 | { 40 | _lock = yieldLock; 41 | } 42 | 43 | /// 44 | /// Releases the lock. 45 | /// 46 | public void Dispose() 47 | { 48 | var yieldLock = _lock; 49 | 50 | if (yieldLock != null) 51 | { 52 | _lock = null; 53 | yieldLock.Lock.ExitReadLock(); 54 | } 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /LibreMetaverse/Threading/Disposers/SpinUpgradeableLock.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024, Sjofn LLC 3 | * All rights reserved. 4 | * 5 | * - Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * - Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * - Neither the name of the openmetaverse.co nor the names 11 | * of its contributors may be used to endorse or promote products derived from 12 | * this software without specific prior written permission. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | using System; 28 | 29 | namespace LibreMetaverse.Threading.Disposers 30 | { 31 | /// 32 | /// Class returned by UpgradeableLock method. 33 | /// 34 | public struct SpinUpgradeableLock: 35 | IUpgradeableLock 36 | { 37 | private SpinReaderWriterLock _lock; 38 | private bool _upgraded; 39 | 40 | internal SpinUpgradeableLock(SpinReaderWriterLock yieldLock) 41 | { 42 | _lock = yieldLock; 43 | _upgraded = false; 44 | } 45 | 46 | /// 47 | /// Upgrades this lock to a write-lock. 48 | /// 49 | public SpinWriteLock DisposableUpgrade() 50 | { 51 | var yieldLock = _lock; 52 | if (yieldLock == null) 53 | throw new ObjectDisposedException(GetType().FullName); 54 | 55 | yieldLock.Lock.UncheckedUpgradeToWriteLock(); 56 | return new SpinWriteLock(yieldLock); 57 | } 58 | 59 | /// 60 | /// Upgrades the lock to a write-lock. 61 | /// Returns true if the lock was upgraded, false if it was 62 | /// already upgraded before. 63 | /// 64 | public bool Upgrade() 65 | { 66 | var yieldLock = _lock; 67 | if (yieldLock == null) 68 | throw new ObjectDisposedException(GetType().FullName); 69 | 70 | if (_upgraded) 71 | return false; 72 | 73 | yieldLock.Lock.UncheckedUpgradeToWriteLock(); 74 | _upgraded = true; 75 | return true; 76 | } 77 | 78 | /// 79 | /// Releases the lock. 80 | /// 81 | public void Dispose() 82 | { 83 | var yieldLock = _lock; 84 | 85 | if (yieldLock != null) 86 | { 87 | _lock = null; 88 | 89 | yieldLock.Lock.ExitUpgradeableLock(_upgraded); 90 | } 91 | } 92 | 93 | IDisposable IUpgradeableLock.DisposableUpgrade() 94 | { 95 | return DisposableUpgrade(); 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /LibreMetaverse/Threading/Disposers/SpinWriteLock.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024, Sjofn LLC 3 | * All rights reserved. 4 | * 5 | * - Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * - Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * - Neither the name of the openmetaverse.co nor the names 11 | * of its contributors may be used to endorse or promote products derived from 12 | * this software without specific prior written permission. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | using System; 28 | 29 | namespace LibreMetaverse.Threading.Disposers 30 | { 31 | /// 32 | /// Class returned by WriteLock method. 33 | /// 34 | public struct SpinWriteLock: 35 | IDisposable 36 | { 37 | private SpinReaderWriterLock _lock; 38 | internal SpinWriteLock(SpinReaderWriterLock yieldLock) 39 | { 40 | _lock = yieldLock; 41 | } 42 | 43 | /// 44 | /// Releases the lock. 45 | /// 46 | public void Dispose() 47 | { 48 | var yieldLock = _lock; 49 | 50 | if (yieldLock != null) 51 | { 52 | _lock = null; 53 | yieldLock.Lock.ExitWriteLock(); 54 | } 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /LibreMetaverse/Threading/IEventWait.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024, Sjofn LLC 3 | * All rights reserved. 4 | * 5 | * - Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * - Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * - Neither the name of the openmetaverse.co nor the names 11 | * of its contributors may be used to endorse or promote products derived from 12 | * this software without specific prior written permission. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | using System; 28 | 29 | namespace LibreMetaverse.Threading 30 | { 31 | /// 32 | /// Interface implemented by PooledEventWait. And, thanks to StructuralCaster, can be used to 33 | /// access custom EventWait objects. 34 | /// 35 | public interface IEventWait: 36 | IDisposable 37 | { 38 | /// 39 | /// Waits for this event to be signalled. 40 | /// 41 | void WaitOne(); 42 | 43 | /// 44 | /// Waits for this event to be signalled or times-out. 45 | /// Returns if the object was signalled. 46 | /// 47 | bool WaitOne(int millisecondsTimeout); 48 | 49 | /// 50 | /// Waits for this event to be signalled or times-out. 51 | /// Returns if the object was signalled. 52 | /// 53 | bool WaitOne(TimeSpan timeout); 54 | 55 | /// 56 | /// Resets (unsignals) this wait event. 57 | /// 58 | void Reset(); 59 | 60 | /// 61 | /// Sets (signals) this wait event. 62 | /// 63 | void Set(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /LibreMetaverse/Threading/IReaderWriterLock.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024, Sjofn LLC 3 | * All rights reserved. 4 | * 5 | * - Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * - Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * - Neither the name of the openmetaverse.co nor the names 11 | * of its contributors may be used to endorse or promote products derived from 12 | * this software without specific prior written permission. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | using System; 28 | using LibreMetaverse.Threading.Disposers; 29 | 30 | namespace LibreMetaverse.Threading 31 | { 32 | /// 33 | /// Defines the contract that ReaderWriterLocks must follow. 34 | /// Note that if you want an Enter/Exit pair, you should 35 | /// use the IReaderWriterLockSlim. 36 | /// 37 | public interface IReaderWriterLock 38 | { 39 | /// 40 | /// Obtains a read lock. You should use it in a using clause 41 | /// so at the end the lock is released. 42 | /// 43 | IDisposable ReadLock(); 44 | 45 | /// 46 | /// Obtains an upgradeable lock. You can use the returned 47 | /// value to upgrade the lock. Also, you should dispose 48 | /// the returned object (an using block is preferreable) to 49 | /// release the lock. 50 | /// 51 | IUpgradeableLock UpgradeableLock(); 52 | 53 | /// 54 | /// Obtains an write lock. Call this method in a using clause 55 | /// so the lock is released at the end. 56 | /// 57 | IDisposable WriteLock(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /LibreMetaverse/Threading/IReaderWriterLockSlim.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024, Sjofn LLC 3 | * All rights reserved. 4 | * 5 | * - Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * - Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * - Neither the name of the openmetaverse.co nor the names 11 | * of its contributors may be used to endorse or promote products derived from 12 | * this software without specific prior written permission. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | namespace LibreMetaverse.Threading 28 | { 29 | /// 30 | /// Interface that must be implemented by reader-writer lock 31 | /// classes that are "slim". That is, they have Enter/Exit 32 | /// methods instead of returning disposable instances (which 33 | /// makes them faster, but more error prone). 34 | /// 35 | public interface IReaderWriterLockSlim 36 | { 37 | /// 38 | /// Enters a read lock. Many readers can enter 39 | /// the read lock at the same time. 40 | /// 41 | void EnterReadLock(); 42 | 43 | /// 44 | /// Exits a previously entered read lock. 45 | /// 46 | void ExitReadLock(); 47 | 48 | /// 49 | /// Enters an upgradeable read lock. Many read locks can 50 | /// be obtained at the same time that a single upgradeable 51 | /// read lock is active, but two upgradeable or an 52 | /// upgradeable and an write lock are not permitted. 53 | /// 54 | void EnterUpgradeableLock(); 55 | 56 | /// 57 | /// Exits a previously entered upgradeable read lock. 58 | /// You should pass the boolean telling if the lock was 59 | /// upgraded or not. 60 | /// 61 | /// 62 | void ExitUpgradeableLock(bool upgraded); 63 | 64 | /// 65 | /// Exits an upgradeable read lock, considering it was never 66 | /// upgraded. 67 | /// 68 | void UncheckedExitUpgradeableLock(); 69 | 70 | /// 71 | /// Upgraded a previously obtained upgradeable lock to a write 72 | /// lock, but does not check if the lock was already upgraded. 73 | /// 74 | void UncheckedUpgradeToWriteLock(); 75 | 76 | /// 77 | /// Upgraded the upgradeable lock to a write lock, checking if 78 | /// it was already upgraded or not (and also updating the upgraded 79 | /// boolean). To upgrade, the lock will wait all readers to end. 80 | /// 81 | void UpgradeToWriteLock(ref bool upgraded); 82 | 83 | /// 84 | /// Exits an upgradeable lock that was also upgraded in a single 85 | /// task. 86 | /// 87 | void UncheckedExitUpgradedLock(); 88 | 89 | /// 90 | /// Enters a write lock. That is, the lock will only be obtained when 91 | /// there are no readers, be them upgradeable or not. 92 | /// 93 | void EnterWriteLock(); 94 | 95 | /// 96 | /// Exits a previously obtained write lock. 97 | /// 98 | void ExitWriteLock(); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /LibreMetaverse/Threading/ManagedAutoResetEvent.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024, Sjofn LLC 3 | * All rights reserved. 4 | * 5 | * - Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * - Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * - Neither the name of the openmetaverse.co nor the names 11 | * of its contributors may be used to endorse or promote products derived from 12 | * this software without specific prior written permission. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | using System; 28 | using System.Threading; 29 | using LibreMetaverse.Threading.Disposers; 30 | 31 | namespace LibreMetaverse.Threading 32 | { 33 | /// 34 | /// An auto reset event that uses only Monitor methods to work, avoiding 35 | /// operating system events. 36 | /// 37 | public sealed class ManagedAutoResetEvent: 38 | IAdvancedDisposable, 39 | IEventWait 40 | { 41 | private readonly object _lock = new object(); 42 | private bool _value; 43 | private bool _wasDisposed; 44 | 45 | /// 46 | /// Creates a new event, not signaled. 47 | /// 48 | public ManagedAutoResetEvent() 49 | { 50 | } 51 | 52 | /// 53 | /// Creates a new event, letting you say if it starts signaled or not. 54 | /// 55 | public ManagedAutoResetEvent(bool initialState) 56 | { 57 | _value = initialState; 58 | } 59 | 60 | /// 61 | /// Disposes this event. After disposing, it is always set. 62 | /// Calling Reset will not work and it will not throw exceptions, so you can 63 | /// dispose it when there are threads waiting on it. 64 | /// 65 | public void Dispose() 66 | { 67 | lock(_lock) 68 | { 69 | _wasDisposed = true; 70 | _value = true; 71 | Monitor.PulseAll(_lock); 72 | } 73 | } 74 | 75 | /// 76 | /// Gets a value indicating if this event was disposed. 77 | /// 78 | public bool WasDisposed => _wasDisposed; 79 | 80 | /// 81 | /// Gets a value indicating if this auto-reset event is set. 82 | /// 83 | public bool IsSet => _value; 84 | 85 | /// 86 | /// Resets this event (makes it non-signaled). 87 | /// 88 | public void Reset() 89 | { 90 | lock(_lock) 91 | { 92 | if (_wasDisposed) 93 | return; 94 | 95 | _value = false; 96 | } 97 | } 98 | 99 | /// 100 | /// Signals the event, releasing one thread waiting on it. 101 | /// 102 | public void Set() 103 | { 104 | lock(_lock) 105 | { 106 | _value = true; 107 | Monitor.Pulse(_lock); 108 | } 109 | } 110 | 111 | /// 112 | /// Waits until this event is signaled. 113 | /// 114 | public void WaitOne() 115 | { 116 | lock(_lock) 117 | { 118 | while(!_value) 119 | Monitor.Wait(_lock); 120 | 121 | if (!_wasDisposed) 122 | _value = false; 123 | } 124 | } 125 | 126 | /// 127 | /// Waits until this event is signaled or until the timeout arrives. 128 | /// Return of true means it was signaled, false means timeout. 129 | /// 130 | public bool WaitOne(int millisecondsTimeout) 131 | { 132 | lock(_lock) 133 | { 134 | while(!_value) 135 | if (!Monitor.Wait(_lock, millisecondsTimeout)) 136 | return false; 137 | 138 | if (!_wasDisposed) 139 | _value = false; 140 | } 141 | 142 | return true; 143 | } 144 | 145 | /// 146 | /// Waits until this event is signaled or until the timeout arrives. 147 | /// Return of true means it was signaled, false means timeout. 148 | /// 149 | public bool WaitOne(TimeSpan timeout) 150 | { 151 | lock(_lock) 152 | { 153 | while(!_value) 154 | if (!Monitor.Wait(_lock, timeout)) 155 | return false; 156 | 157 | if (!_wasDisposed) 158 | _value = false; 159 | } 160 | 161 | return true; 162 | } 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /LibreMetaverse/Threading/ManagedManualResetEvent.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024, Sjofn LLC 3 | * All rights reserved. 4 | * 5 | * - Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * - Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * - Neither the name of the openmetaverse.co nor the names 11 | * of its contributors may be used to endorse or promote products derived from 12 | * this software without specific prior written permission. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | using System; 28 | using System.Threading; 29 | using LibreMetaverse.Threading.Disposers; 30 | 31 | namespace LibreMetaverse.Threading 32 | { 33 | /// 34 | /// A manual reset event that uses only Monitor methods to work, avoiding 35 | /// operating system events. 36 | /// 37 | public sealed class ManagedManualResetEvent: 38 | IAdvancedDisposable, 39 | IEventWait 40 | { 41 | private readonly object _lock = new object(); 42 | private bool _value; 43 | private bool _wasDisposed; 44 | 45 | /// 46 | /// Creates a new event, not signaled. 47 | /// 48 | public ManagedManualResetEvent() 49 | { 50 | } 51 | 52 | /// 53 | /// Creates a new event, letting you say if it starts signaled or not. 54 | /// 55 | public ManagedManualResetEvent(bool initialState) 56 | { 57 | _value = initialState; 58 | } 59 | 60 | /// 61 | /// Disposes this event. After disposing, it is always set. 62 | /// Calling Reset will not work and it will not throw exceptions, so you can 63 | /// dispose it when there are threads waiting on it. 64 | /// 65 | public void Dispose() 66 | { 67 | lock(_lock) 68 | { 69 | _wasDisposed = true; 70 | _value = true; 71 | Monitor.PulseAll(_lock); 72 | } 73 | } 74 | 75 | /// 76 | /// Gets a value indicating if this event was disposed. 77 | /// 78 | public bool WasDisposed => _wasDisposed; 79 | 80 | /// 81 | /// Gets a value indicating if this auto-reset event is set. 82 | /// 83 | public bool IsSet => _value; 84 | 85 | /// 86 | /// Resets this event (makes it non-signaled). 87 | /// 88 | public void Reset() 89 | { 90 | lock(_lock) 91 | { 92 | if (_wasDisposed) 93 | return; 94 | 95 | _value = false; 96 | } 97 | } 98 | 99 | /// 100 | /// Signals the event, releasing any threads waiting on it. 101 | /// 102 | public void Set() 103 | { 104 | lock(_lock) 105 | { 106 | _value = true; 107 | Monitor.PulseAll(_lock); 108 | } 109 | } 110 | 111 | /// 112 | /// Waits until this event is signaled. 113 | /// 114 | public void WaitOne() 115 | { 116 | lock(_lock) 117 | { 118 | while(!_value) 119 | Monitor.Wait(_lock); 120 | } 121 | } 122 | 123 | /// 124 | /// Waits until this event is signaled or until the timeout arrives. 125 | /// Return of true means it was signaled, false means timeout. 126 | /// 127 | public bool WaitOne(int millisecondsTimeout) 128 | { 129 | lock(_lock) 130 | { 131 | while(!_value) 132 | if (!Monitor.Wait(_lock, millisecondsTimeout)) 133 | return false; 134 | } 135 | 136 | return true; 137 | } 138 | 139 | /// 140 | /// Waits until this event is signaled or until the timeout arrives. 141 | /// Return of true means it was signaled, false means timeout. 142 | /// 143 | public bool WaitOne(TimeSpan timeout) 144 | { 145 | lock(_lock) 146 | { 147 | while(!_value) 148 | if (!Monitor.Wait(_lock, timeout)) 149 | return false; 150 | } 151 | 152 | return true; 153 | } 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /LibreMetaverse/Threading/ManagedSemaphore.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024, Sjofn LLC 3 | * All rights reserved. 4 | * 5 | * - Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * - Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * - Neither the name of the openmetaverse.co nor the names 11 | * of its contributors may be used to endorse or promote products derived from 12 | * this software without specific prior written permission. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | using System; 28 | using System.Threading; 29 | using LibreMetaverse.Threading.Disposers; 30 | 31 | namespace LibreMetaverse.Threading 32 | { 33 | /// 34 | /// A semaphore class that uses only Monitor class for synchronization, avoiding 35 | /// operating system events. 36 | /// 37 | public sealed class ManagedSemaphore: 38 | IAdvancedDisposable 39 | { 40 | private readonly object _lock = new object(); 41 | private int _availableCount; 42 | 43 | /// 44 | /// Creates a new semaphore with the given availableCount. 45 | /// 46 | public ManagedSemaphore(int availableCount) 47 | { 48 | if (availableCount < 1) 49 | throw new ArgumentException("availableCount must be at least 1.", nameof(availableCount)); 50 | 51 | _availableCount = availableCount; 52 | } 53 | 54 | /// 55 | /// Disposes this semaphore. 56 | /// If you try to enter or exit it after this, the action will always return immediately. 57 | /// 58 | public void Dispose() 59 | { 60 | lock(_lock) 61 | { 62 | _availableCount = -1; 63 | Monitor.PulseAll(_lock); 64 | } 65 | } 66 | 67 | /// 68 | /// Gets a value indicating if this semaphore was disposed. 69 | /// 70 | public bool WasDisposed => _availableCount == -1; 71 | 72 | /// 73 | /// Enters the actual semaphore. 74 | /// 75 | public void Enter() 76 | { 77 | lock(_lock) 78 | { 79 | while(true) 80 | { 81 | if (_availableCount == -1) 82 | return; 83 | 84 | if (_availableCount > 0) 85 | { 86 | _availableCount--; 87 | return; 88 | } 89 | 90 | Monitor.Wait(_lock); 91 | } 92 | } 93 | } 94 | 95 | /// 96 | /// Enters the actual semaphore with the given count value. 97 | /// If you pass a value higher than the one used to create it, you will dead-lock (at least until 98 | /// the semaphore is disposed). 99 | /// 100 | public void Enter(int count) 101 | { 102 | if (count <= 0) 103 | throw new ArgumentException("count of semaphores to enter must be at least 1.", nameof(count)); 104 | 105 | lock(_lock) 106 | { 107 | while(true) 108 | { 109 | if (_availableCount == -1) 110 | return; 111 | 112 | if (_availableCount >= count) 113 | { 114 | _availableCount -= count; 115 | return; 116 | } 117 | 118 | Monitor.Wait(_lock); 119 | } 120 | } 121 | } 122 | 123 | /// 124 | /// Exits the semaphore. One thread can enter it and another one exit it. There is no check for that. 125 | /// 126 | public void Exit() 127 | { 128 | lock(_lock) 129 | { 130 | if (_availableCount == -1) 131 | return; 132 | 133 | _availableCount++; 134 | Monitor.Pulse(_lock); 135 | } 136 | } 137 | 138 | /// 139 | /// Exits the semaphore the given amount. One thread can enter it and another one exit it. There is no check for that. 140 | /// 141 | public void Exit(int count) 142 | { 143 | if (count <= 0) 144 | throw new ArgumentException("count of semaphores to exit must be at least 1.", nameof(count)); 145 | 146 | if (count == -1) 147 | { 148 | Exit(); 149 | return; 150 | } 151 | 152 | lock(_lock) 153 | { 154 | if (_availableCount == -1) 155 | return; 156 | 157 | _availableCount += count; 158 | Monitor.PulseAll(_lock); 159 | } 160 | } 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /LibreMetaverse/Threading/SpinLockSlim.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024, Sjofn LLC 3 | * All rights reserved. 4 | * 5 | * - Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * - Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * - Neither the name of the openmetaverse.co nor the names 11 | * of its contributors may be used to endorse or promote products derived from 12 | * this software without specific prior written permission. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | using System.Threading; 28 | 29 | namespace LibreMetaverse.Threading 30 | { 31 | /// 32 | /// A real slim SpinWait (the Microsoft version is slower than the normal use of 33 | /// the lock keyword for uncontended locks). 34 | /// This lock never verifies ownership, so it will dead-lock if you try 35 | /// to enter it twice and it will allow one thread to enter the lock and 36 | /// another thread to release it (if you want that, it will be great... if not, 37 | /// you will be causing bugs). 38 | /// It should only be used in situations where the lock is expected to be 39 | /// held for very short times and when performance is really critical. 40 | /// This is a struct, so if you for some reason need to pass it as a parameter, 41 | /// use it as a ref, or else you will end-up using a copy of the lock instead 42 | /// of working on the real one. 43 | /// 44 | public struct SpinLockSlim 45 | { 46 | private int _locked; 47 | 48 | /// 49 | /// Enters the lock. So you can do your actions in a safe manner. 50 | /// 51 | public void Enter() 52 | { 53 | if (Interlocked.CompareExchange(ref _locked, 1, 0) == 0) 54 | return; 55 | 56 | SpinWait spinWait = new SpinWait(); 57 | while(true) 58 | { 59 | spinWait.SpinOnce(); 60 | 61 | if (Interlocked.CompareExchange(ref _locked, 1, 0) == 0) 62 | return; 63 | } 64 | } 65 | 66 | /// 67 | /// Exits the lock. If the same thread exits and enters the lock constantly, it will 68 | /// probably got the lock many times before letting other threads get it, even if those 69 | /// other threads started to wait before the actual thread releases the lock. Fairness 70 | /// is not a strong point of this lock. 71 | /// 72 | public void Exit() 73 | { 74 | // There is no need to use a "volatile" write as all .NET writes 75 | // have "release" semantics. 76 | _locked = 0; 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /LibreMetaverse/Threading/SpinReaderWriterLock.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024, Sjofn LLC 3 | * All rights reserved. 4 | * 5 | * - Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * - Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * - Neither the name of the openmetaverse.co nor the names 11 | * of its contributors may be used to endorse or promote products derived from 12 | * this software without specific prior written permission. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | using System; 28 | using LibreMetaverse.Threading.Disposers; 29 | 30 | namespace LibreMetaverse.Threading 31 | { 32 | /// 33 | /// A reader writer lock that uses SpinWait if it does not have the lock. If the locks are held for 34 | /// to much time, this is CPU consuming. 35 | /// In my general tests, it is about 20 times faster than ReaderWriterLockSlim class and two times 36 | /// faster than the YieldReaderWriterLock. 37 | /// 38 | public sealed class SpinReaderWriterLock: 39 | IReaderWriterLock 40 | { 41 | #region Fields 42 | internal SpinReaderWriterLockSlim Lock; 43 | #endregion 44 | 45 | #region ReadLock 46 | /// 47 | /// Acquires a read lock that must be used in a using clause. 48 | /// 49 | public SpinReadLock ReadLock() 50 | { 51 | Lock.EnterReadLock(); 52 | return new SpinReadLock(this); 53 | } 54 | #endregion 55 | #region UpgradeableLock 56 | /// 57 | /// Acquires a upgradeable read lock that must be used in a using clause. 58 | /// 59 | public SpinUpgradeableLock UpgradeableLock() 60 | { 61 | Lock.EnterUpgradeableLock(); 62 | return new SpinUpgradeableLock(this); 63 | } 64 | #endregion 65 | #region WriteLock 66 | /// 67 | /// Acquires a write lock that must be used in a using clause. 68 | /// If you are using a UpgradeableLock use the Upgrade method of the 69 | /// YieldUpgradeableLock instead or you will cause a dead-lock. 70 | /// 71 | public SpinWriteLock WriteLock() 72 | { 73 | Lock.EnterWriteLock(); 74 | return new SpinWriteLock(this); 75 | } 76 | #endregion 77 | 78 | #region IReaderWriterLock Members 79 | IDisposable IReaderWriterLock.ReadLock() 80 | { 81 | return ReadLock(); 82 | } 83 | 84 | IUpgradeableLock IReaderWriterLock.UpgradeableLock() 85 | { 86 | return UpgradeableLock(); 87 | } 88 | 89 | IDisposable IReaderWriterLock.WriteLock() 90 | { 91 | return WriteLock(); 92 | } 93 | #endregion 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /LibreMetaverse/UDPPacketBuffer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | 4 | namespace OpenMetaverse 5 | { 6 | // this class encapsulates a single packet that 7 | // is either sent or received by a UDP socket 8 | public class UDPPacketBuffer 9 | { 10 | /// Size of the byte array used to store raw packet data 11 | public const int DEFAULT_BUFFER_SIZE = 4096; 12 | 13 | /// Raw packet data buffer 14 | public readonly byte[] Data; 15 | 16 | /// Length of the data to transmit 17 | public int DataLength; 18 | 19 | /// EndPoint of the remote host 20 | public EndPoint RemoteEndPoint; 21 | 22 | /// 23 | /// Create an allocated UDP packet buffer for receiving a packet 24 | /// 25 | public UDPPacketBuffer() 26 | { 27 | Data = new byte[DEFAULT_BUFFER_SIZE]; 28 | // Will be modified later by BeginReceiveFrom() 29 | RemoteEndPoint = new IPEndPoint(Settings.BIND_ADDR, 0); 30 | } 31 | 32 | /// 33 | /// Create an allocated UDP packet buffer for sending a packet 34 | /// 35 | /// EndPoint of the remote host 36 | public UDPPacketBuffer(IPEndPoint endPoint) 37 | { 38 | Data = new byte[DEFAULT_BUFFER_SIZE]; 39 | RemoteEndPoint = endPoint; 40 | } 41 | 42 | /// 43 | /// Create an allocated UDP packet buffer for sending a packet 44 | /// 45 | /// EndPoint of the remote host 46 | /// Size of the buffer to allocate for packet data 47 | public UDPPacketBuffer(IPEndPoint endPoint, int bufferSize) 48 | { 49 | Data = new byte[bufferSize]; 50 | RemoteEndPoint = endPoint; 51 | } 52 | 53 | /// 54 | /// Create an allocated UDP packet buffer for sending a packet 55 | /// 56 | public UDPPacketBuffer(byte[] buffer, int bufferSize, IPEndPoint destination, int category) 57 | { 58 | Data = new byte[bufferSize]; 59 | this.CopyFrom(buffer, bufferSize); 60 | DataLength = bufferSize; 61 | 62 | RemoteEndPoint = destination; 63 | } 64 | 65 | /// 66 | /// Create an allocated UDP packet buffer for sending a packet 67 | /// 68 | /// EndPoint of the remote host 69 | /// The actual buffer to use for packet data (no allocation). 70 | public UDPPacketBuffer(IPEndPoint endPoint, byte[] data) 71 | { 72 | Data = data; 73 | RemoteEndPoint = endPoint; 74 | } 75 | 76 | public void CopyFrom(Array src, int length) 77 | { 78 | Buffer.BlockCopy(src, 0, this.Data, 0, length); 79 | } 80 | 81 | public void CopyFrom(Array src) 82 | { 83 | this.CopyFrom(src, src.Length); 84 | } 85 | 86 | public void ResetEndpoint() 87 | { 88 | RemoteEndPoint = new IPEndPoint(Settings.BIND_ADDR, 0); 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /LibreMetaverse/UtilizationStatistics.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006-2016, openmetaverse.co 3 | * All rights reserved. 4 | * 5 | * - Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * - Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * - Neither the name of the openmetaverse.co nor the names 11 | * of its contributors may be used to endorse or promote products derived from 12 | * this software without specific prior written permission. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | using System.Collections.Generic; 28 | using System.Linq; 29 | 30 | namespace OpenMetaverse.Stats 31 | { 32 | public enum Type 33 | { 34 | Packet, 35 | Message 36 | } 37 | 38 | public class UtilizationStatistics 39 | { 40 | public class Stat 41 | { 42 | public Type Type { get; set; } 43 | public long TxCount { get; set; } 44 | public long RxCount { get; set; } 45 | public long TxBytes { get; set; } 46 | public long RxBytes { get; set; } 47 | } 48 | 49 | private readonly Dictionary m_StatsCollection; 50 | 51 | public UtilizationStatistics() 52 | { 53 | m_StatsCollection = new Dictionary(); 54 | } 55 | 56 | internal void Update(string key, Type type, long txBytes, long rxBytes) 57 | { 58 | lock (m_StatsCollection) 59 | { 60 | Stat stat; 61 | 62 | if (m_StatsCollection.TryGetValue(key, out var value)) 63 | { 64 | stat = value; 65 | } 66 | else 67 | { 68 | stat = new Stat() 69 | { 70 | Type = type 71 | }; 72 | m_StatsCollection.Add(key, stat); 73 | } 74 | 75 | if (rxBytes > 0) 76 | { 77 | stat.RxCount += 1; 78 | stat.RxBytes += rxBytes; 79 | } 80 | 81 | if (txBytes > 0) 82 | { 83 | stat.TxCount += 1; 84 | stat.TxBytes += txBytes; 85 | } 86 | } 87 | } 88 | 89 | public Dictionary GetStatistics() 90 | { 91 | lock (m_StatsCollection) 92 | { 93 | return m_StatsCollection.ToDictionary( 94 | e => e.Key, 95 | e => new Stat() 96 | { 97 | Type = e.Value.Type, 98 | RxBytes = e.Value.RxBytes, 99 | RxCount = e.Value.RxCount, 100 | TxBytes = e.Value.TxBytes, 101 | TxCount = e.Value.TxCount 102 | }); 103 | } 104 | } 105 | } 106 | } -------------------------------------------------------------------------------- /NuGet.Config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ``` 4 | _____ _ _ _ 5 | / ___| | | | | | 6 | \ `--. ___ ___ ___ _ __ __| | |__ ___ | |_ 7 | `--. \/ _ \/ __/ _ \| '_ \ / _` | '_ \ / _ \| __| 8 | /\__/ / __/ (_| (_) | | | | (_| | |_) | (_) | |_ 9 | \____/ \___|\___\___/|_| |_|\__,_|_.__/ \___/ \__| 10 | ``` 11 | # Secondbot 12 | Secondbot is a CommandLine based bot for SecondLife based on libremetaverse retargeted for .net core. 13 | 14 | [madpeter/secondbot on dockerhub](https://hub.docker.com/r/madpeter/secondbot) 15 | 16 | Current tags 17 | ==== 18 | events - the most upto date stable version of the bot 19 | 20 | debug - used for feature tested 21 | 22 | 23 | Archived tags 24 | ==== 25 | classic - the older pre events update version of the bot (if you can please use a current tag) 26 | 27 | 28 | 29 | ### Status 30 | --- 31 | [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/3765/badge)](https://bestpractices.coreinfrastructure.org/projects/3765) 32 | 33 | 34 | ### Getting started guides 35 | --- 36 | Wiki / [Docker-with-Portainer](https://github.com/Madpeterz/SecondBot/wiki/Setting-up-(Docker-with-Portainer)) 37 | 38 | 39 | ### Running on a pi? 40 | --- 41 | [arm32 v7 docker image provided by shadoskill](https://hub.docker.com/r/shadoskill/secondbot_arm) 42 | 43 | -------------------------------------------------------------------------------- /SecondBotEvents/Commands/Animation.cs: -------------------------------------------------------------------------------- 1 | using OpenMetaverse; 2 | using SecondBotEvents.Services; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | 7 | namespace SecondBotEvents.Commands 8 | { 9 | [ClassInfo("Animations and Gestures")] 10 | internal class AnimationCommands(EventsSecondBot setmaster) : CommandsAPI(setmaster) 11 | { 12 | [About("Toggles if animation requests from this avatar (used for remote poseballs) are accepted")] 13 | [ReturnHints("Granted perm animation")] 14 | [ReturnHints("Removed perm animation")] 15 | [ReturnHintsFailure("avatar lookup")] 16 | [ArgHints("avatar", "Who to accept requests from", "AVATAR")] 17 | [CmdTypeSet()] 18 | public object AddToAllowAnimations(string avatar) 19 | { 20 | ProcessAvatar(avatar); 21 | if (avataruuid == UUID.Zero) 22 | { 23 | return BasicReply("avatar lookup", [avatar]); 24 | } 25 | // @todo accept storage 26 | return Failure("@todo"); 27 | } 28 | 29 | [About("Attempts to play a gesture")] 30 | [ReturnHintsFailure("Error with gesture")] 31 | [ReturnHints("Accepted")] 32 | [ArgHints("gesture", "What gesture to trigger", "UUID")] 33 | [CmdTypeDo()] 34 | public object PlayGesture(string gesture) 35 | { 36 | if (UUID.TryParse(gesture, out UUID gestureUUID) == false) 37 | { 38 | return BasicReply("Error with gesture", [gesture]); 39 | } 40 | InventoryItem itm = GetClient().Inventory.FetchItem(gestureUUID, GetClient().Self.AgentID, TimeSpan.FromSeconds(15)); 41 | GetClient().Self.PlayGesture(itm.AssetUUID); 42 | return BasicReply("Accepted", [gesture]); 43 | } 44 | 45 | [About("Resets the animation stack for the bot")] 46 | [ReturnHints("Accepted - X stopped animations")] 47 | [CmdTypeDo()] 48 | public object ResetAnimations() 49 | { 50 | List animations = [.. GetClient().Self.SignaledAnimations.Copy().Keys]; 51 | foreach (UUID anim in animations) 52 | { 53 | GetClient().Self.AnimationStop(anim, true); 54 | } 55 | return BasicReply("Accepted - "+animations.Count.ToString()+" stopped animations"); 56 | } 57 | 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /SecondBotEvents/Commands/Core.cs: -------------------------------------------------------------------------------- 1 | using SecondBotEvents.Services; 2 | 3 | namespace SecondBotEvents.Commands 4 | { 5 | [ClassInfo("Used to test interaction with the bot... hello world for avartars")] 6 | public class Core(EventsSecondBot setmaster) : CommandsAPI(setmaster) 7 | { 8 | [About("Used to check connections")] 9 | [ReturnHints("world")] 10 | [CmdTypeGet()] 11 | public object Hello() 12 | { 13 | return BasicReply("world"); 14 | } 15 | } 16 | 17 | public class CommandLibCall 18 | { 19 | public string Command { get; set; } 20 | public string[] Args { get; set; } 21 | public string AuthCode { get; set; } 22 | } 23 | 24 | public class NearMeDetails 25 | { 26 | public string id { get; set; } 27 | public string name { get; set; } 28 | public int x { get; set; } 29 | public int y { get; set; } 30 | public int z { get; set; } 31 | public int range { get; set; } 32 | 33 | } 34 | 35 | 36 | } 37 | -------------------------------------------------------------------------------- /SecondBotEvents/Commands/Dialogs.cs: -------------------------------------------------------------------------------- 1 | using OpenMetaverse; 2 | using SecondBotEvents.Services; 3 | 4 | 5 | namespace SecondBotEvents.Commands 6 | { 7 | [ClassInfo("Script dialog box interaction / events when displayed")] 8 | public class Dialogs(EventsSecondBot setmaster) : CommandsAPI(setmaster) 9 | { 10 | [About("adds a avatar dialog relay target [or removes if it exists]")] 11 | [ReturnHints("added")] 12 | [ReturnHints("removed")] 13 | [ReturnHintsFailure("unable to find avatar")] 14 | [ReturnHintsFailure("looking up avatar please try again")] 15 | [ArgHints("avatar", "Who to send the dialog relay to", "AVATAR")] 16 | [CmdTypeSet()] 17 | public object DialogRelayAvatarTarget(string avatar) 18 | { 19 | if(UUID.TryParse(avatar, out UUID avUUID) == false) 20 | { 21 | string avataruuid = master.DataStoreService.GetAvatarUUID(avatar); 22 | if (avataruuid == "lookup") 23 | { 24 | return Failure("looking up avatar please try again"); 25 | } 26 | if (UUID.TryParse(avataruuid, out avUUID) == false) 27 | { 28 | return Failure("unable to find avatar"); 29 | } 30 | } 31 | return BasicReply(master.DialogService.AvatarRelayTarget(avUUID)); 32 | } 33 | 34 | [About("adds a chat dialog relay target [or removes if it exists]")] 35 | [ReturnHints("added")] 36 | [ReturnHints("removed")] 37 | [ReturnHintsFailure("channel must be zero or more")] 38 | [ReturnHintsFailure("channel is not vaild")] 39 | [ArgHints("channel", "what channel number to send the reply to (must be zero or higher)","Number", "123")] 40 | [CmdTypeSet()] 41 | public object DialogRelayChatTarget(string channel) 42 | { 43 | if (int.TryParse(channel, out int channelnum) == false) 44 | { 45 | return Failure("channel is not vaild"); 46 | } 47 | if(channelnum < 0) 48 | { 49 | return Failure("channel must be zero or more"); 50 | } 51 | return BasicReply(master.DialogService.ChannelRelayTarget(channelnum)); 52 | } 53 | 54 | [About("adds a http dialog relay target [or removes if it exists]")] 55 | [ReturnHints("added")] 56 | [ReturnHints("removed")] 57 | [ReturnHintsFailure("url must start with http")] 58 | [ArgHints("url", "the URL to send the replys to","URL","http://mycoolsite.com/botdialog.php")] 59 | [CmdTypeSet()] 60 | public object DialogRelayHttpTarget(string url) 61 | { 62 | if(url.StartsWith("http") == false) 63 | { 64 | return Failure("url must start with http"); 65 | } 66 | return BasicReply(master.DialogService.HttpRelayTarget(url)); 67 | } 68 | 69 | 70 | [About("Makes the bot interact with the dialog [dialogid] with the button [buttontext]")] 71 | [ReturnHints("action")] 72 | [ReturnHintsFailure("Invaild dialog window")] 73 | [ReturnHintsFailure("Invaild dialog button")] 74 | [ReturnHintsFailure("bad dialog id")] 75 | [ArgHints("dialogid", "The ID for the dialog","Number","442")] 76 | [ArgHints("buttontext", "The button text to push","Text","Unlock")] 77 | [CmdTypeDo()] 78 | public object DialogResponce(string dialogid, string buttontext) 79 | { 80 | if (int.TryParse(dialogid, out int dialogidnum) == false) 81 | { 82 | return Failure("bad dialog id", [dialogid, buttontext]); 83 | } 84 | return BasicReply(master.DialogService.DialogAction(dialogidnum, buttontext)); 85 | } 86 | 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /SecondBotEvents/Commands/Funds.cs: -------------------------------------------------------------------------------- 1 | using OpenMetaverse; 2 | using SecondBotEvents.Services; 3 | 4 | 5 | namespace SecondBotEvents.Commands 6 | { 7 | [ClassInfo("Money makes the world go round")] 8 | public class Funds(EventsSecondBot setmaster) : CommandsAPI(setmaster) 9 | { 10 | [About("Requests the current balance and requests the balance to update.")] 11 | [ReturnHints("Current fund level")] 12 | [ReturnHintsFailure("Funds commands are disabled")] 13 | [CmdTypeGet()] 14 | public object Balance() 15 | { 16 | if (master.CommandsService.myConfig.GetAllowFundsCommands() == false) 17 | { 18 | return Failure("Funds commands are disabled"); 19 | } 20 | GetClient().Self.RequestBalance(); 21 | return BasicReply(GetClient().Self.Balance.ToString()); 22 | } 23 | 24 | [About("Makes the bot pay a avatar")] 25 | [ReturnHints("Accepted")] 26 | [ReturnHintsFailure("avatar lookup")] 27 | [ReturnHintsFailure("Amount out of range")] 28 | [ReturnHintsFailure("Invaild amount")] 29 | [ReturnHintsFailure("Transfer funds to avatars disabled")] 30 | [ArgHints("avatar", "Who to pay", "AVATAR")] 31 | [ArgHints("amount", "the amount to pay (from 1 to current balance)", "Number", "442")] 32 | [CmdTypeDo()] 33 | public object PayAvatar(string avatar, string amount) 34 | { 35 | if (master.CommandsService.myConfig.GetAllowFundsCommands() == false) 36 | { 37 | return Failure("Transfer funds to avatars disabled", [avatar, amount]); 38 | } 39 | ProcessAvatar(avatar); 40 | if (avataruuid == UUID.Zero) 41 | { 42 | return BasicReply("avatar lookup", [avatar, amount]); 43 | } 44 | if (int.TryParse(amount, out int amountvalue) == false) 45 | { 46 | return Failure("Invaild amount", [avatar, amount]); 47 | } 48 | if ((amountvalue < 0) || (amountvalue > GetClient().Self.Balance)) 49 | { 50 | GetClient().Self.RequestBalance(); 51 | return Failure("Amount out of range current max: "+ GetClient().Self.Balance.ToString(), [avatar, amount]); 52 | } 53 | GetClient().Self.GiveAvatarMoney(avataruuid, amountvalue); 54 | return BasicReply("Accepted", [avatar, amount]); 55 | } 56 | 57 | [About("Makes the bot pay a object")] 58 | [ReturnHints("ok")] 59 | [ReturnHintsFailure("Primname is empty")] 60 | [ReturnHintsFailure("Invaild object UUID")] 61 | [ReturnHintsFailure("Invaild amount")] 62 | [ReturnHintsFailure("Amount out of range")] 63 | [ReturnHintsFailure("Funds commands are disabled")] 64 | [ArgHints("object", "Object to pay","UUID")] 65 | [ArgHints("primname", "The name of the prim on the object to pay","Text","MyBank")] 66 | [ArgHints("amount", "the amount to pay (from 1 to current balance)","Number","312")] 67 | [CmdTypeDo()] 68 | public object PayObject(string objectuuid,string primname,string amount) 69 | { 70 | if (master.CommandsService.myConfig.GetAllowFundsCommands() == false) 71 | { 72 | return Failure("Funds commands are disabled", [objectuuid, primname, amount]); 73 | } 74 | if (UUID.TryParse(objectuuid, out UUID objectUUID) == false) 75 | { 76 | return Failure("Invaild object UUID", [objectuuid, primname, amount]); 77 | } 78 | if (int.TryParse(amount, out int amountvalue) == false) 79 | { 80 | return Failure("Invaild amount", [objectuuid, primname, amount]); 81 | } 82 | if((amountvalue < 0) || (amountvalue > GetClient().Self.Balance)) 83 | { 84 | return Failure("Amount out of range", [objectuuid, primname, amount]); 85 | } 86 | if(SecondbotHelpers.notempty(primname) == false) 87 | { 88 | return Failure("Primname is empty", [objectuuid, primname, amount]); 89 | } 90 | GetClient().Self.GiveObjectMoney(objectUUID, amountvalue, primname); 91 | return BasicReply("ok", [objectuuid, primname, amount]); 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /SecondBotEvents/Commands/StreamAdmin.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using OpenMetaverse; 3 | using RestSharp; 4 | using SecondBotEvents.Services; 5 | using System; 6 | 7 | namespace SecondBotEvents.Commands 8 | { 9 | [ClassInfo("Interface for streamadmin to create notecards, you will prob never need this")] 10 | public class StreamAdmin(EventsSecondBot setmaster) : CommandsAPI(setmaster) 11 | { 12 | [About("A streamadin command")] 13 | [ReturnHints("True|False")] 14 | [ReturnHintsFailure("Bad reply: ...")] 15 | [ReturnHintsFailure("Endpoint is empty")] 16 | [ReturnHintsFailure("Endpointcode is empty")] 17 | [ReturnHintsFailure("HTTP status code: ...")] 18 | [ReturnHintsFailure("Error: ...")] 19 | [ReturnHintsFailure("Notecard title is to short")] 20 | [ArgHints("endpoint", "The end point","Text","No help given")] 21 | [ArgHints("endpointcode", "The end point code", "Text", "No help given")] 22 | [CmdTypeGet()] 23 | public object FetchNextNotecard(string endpoint, string endpointcode) 24 | { 25 | if (SecondbotHelpers.notempty(endpoint) == false) 26 | { 27 | return Failure("Endpoint is empty", [endpoint, endpointcode]); 28 | } 29 | if (SecondbotHelpers.notempty(endpointcode) == false) 30 | { 31 | return Failure("Endpointcode is empty", [endpoint, endpointcode]); 32 | } 33 | 34 | string attempt_endpoint = endpoint + "sys.php"; 35 | string token = SecondbotHelpers.GetSHA1(SecondbotHelpers.UnixTimeNow().ToString() + "NotecardNext" + endpointcode); 36 | var client = new RestClient(attempt_endpoint); 37 | var request = new RestRequest("Notecard/Next", Method.Post); 38 | string unixtime = SecondbotHelpers.UnixTimeNow().ToString(); 39 | request.AddParameter("token", token); 40 | request.AddParameter("unixtime", unixtime); 41 | request.AddParameter("method", "Notecard"); 42 | request.AddParameter("action", "Next"); 43 | request.AddHeader("content-type", "application/x-www-form-urlencoded"); 44 | RestResponse endpoint_checks = client.ExecutePostAsync(request).Result; 45 | if (endpoint_checks.StatusCode != System.Net.HttpStatusCode.OK) 46 | { 47 | return Failure("HTTP status code: " + endpoint_checks.StatusCode.ToString(), [endpoint, endpointcode]); 48 | } 49 | try 50 | { 51 | NotecardEndpoint server_reply = JsonConvert.DeserializeObject(endpoint_checks.Content); 52 | if (server_reply.status == false) 53 | { 54 | return Failure("Bad reply: " + server_reply.message, [endpoint, endpointcode]); 55 | } 56 | if (server_reply.NotecardTitle.Length < 3) 57 | { 58 | return Failure("Notecard title is to short", [endpoint, endpointcode]); 59 | } 60 | ProcessAvatar(server_reply.AvatarUUID); 61 | if(avataruuid == UUID.Zero) 62 | { 63 | return Failure("Unable to unpack avatar", [endpoint, endpointcode]); 64 | } 65 | bool result = master.BotClient.SendNotecard(server_reply.NotecardTitle, server_reply.NotecardContent, avataruuid); 66 | if (result == false) 67 | { 68 | return Failure("Failed to create/send notecard", [endpoint, endpointcode]); 69 | } 70 | return BasicReply("ok"); 71 | } 72 | catch (Exception e) 73 | { 74 | return Failure("Error: " + e.Message + "", [endpoint, endpointcode]); 75 | } 76 | } 77 | 78 | public class NotecardEndpoint : BasicEndpoint 79 | { 80 | public string AvatarUUID { get; set; } 81 | public string NotecardTitle { get; set; } 82 | public string NotecardContent { get; set; } 83 | } 84 | 85 | public class BasicEndpoint 86 | { 87 | public bool status { get; set; } 88 | public string message { get; set; } 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /SecondBotEvents/Config/BasicConfig.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace SecondBotEvents.Config 6 | { 7 | public class BasicConfig(bool fromENV, string fromFolder = "") : Config(fromENV, fromFolder) 8 | { 9 | protected override void MakeSettings() 10 | { 11 | filename = "basic"; 12 | settings.Add("Username"); 13 | settings.Add("Password"); 14 | settings.Add("LoginURI"); 15 | settings.Add("LogCommands"); 16 | settings.Add("DefaultHoverHeight"); 17 | } 18 | 19 | public double GetDefaultHoverHeight() 20 | { 21 | return ReadSettingAsDouble("DefaultHoverHeight", 0.1); 22 | } 23 | public bool GetLogCommands() 24 | { 25 | return ReadSettingAsBool("LogCommands", true); 26 | } 27 | public string GetUsername() 28 | { 29 | return ReadSettingAsString("Username","Firstname Lastname"); 30 | } 31 | 32 | public string GetPassword() 33 | { 34 | return ReadSettingAsString("Password", "passwordHere"); 35 | } 36 | 37 | public string GetFirstName() 38 | { 39 | 40 | string[] bits = GetUsername().Split(" "); 41 | return bits[0]; 42 | } 43 | 44 | public string GetLastName() 45 | { 46 | string[] bits = GetUsername().Split(" "); 47 | if(bits.Length == 2) 48 | { 49 | return bits[1]; 50 | } 51 | return "Resident"; 52 | } 53 | 54 | public string GetLoginURI() 55 | { 56 | return ReadSettingAsString("LoginURI", "secondlife"); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /SecondBotEvents/Config/CommandsConfig.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Linq; 5 | 6 | namespace SecondBotEvents.Config 7 | { 8 | public class CommandsConfig(bool fromENV, string fromFolder = "") : Config(fromENV, fromFolder) 9 | { 10 | protected override void MakeSettings() 11 | { 12 | filename = "commands"; 13 | settings.Add("AllowFundsCommands"); 14 | settings.Add("AllowIMcontrol"); 15 | settings.Add("SharedSecret"); 16 | settings.Add("EnableMasterControls"); 17 | settings.Add("MastersCSV"); 18 | settings.Add("CheckDotNames"); 19 | settings.Add("EnforceTimeWindow"); 20 | settings.Add("TimeWindowSecs"); 21 | settings.Add("Enabled"); 22 | settings.Add("ObjectMasterOptout"); 23 | settings.Add("AllowServiceControl"); 24 | settings.Add("CommandHistoryLogResults"); 25 | settings.Add("HideStatusOutput"); 26 | } 27 | 28 | 29 | public bool GetCommandHistoryLogResults() 30 | { 31 | return ReadSettingAsBool("CommandHistoryLogResults", false); 32 | } 33 | public bool GetAllowServiceControl() 34 | { 35 | return ReadSettingAsBool("AllowServiceControl", false); 36 | } 37 | public bool GetEnabled() 38 | { 39 | return ReadSettingAsBool("Enabled", true); 40 | } 41 | 42 | public bool GetCheckDotNames() 43 | { 44 | return ReadSettingAsBool("CheckDotNames", false); 45 | } 46 | 47 | public bool GetObjectMasterOptout() 48 | { 49 | return ReadSettingAsBool("ObjectMasterOptout", false); 50 | } 51 | 52 | public string[] GetMastersCSV() 53 | { 54 | return ReadSettingAsString("MastersCSV", "Madpeter Zond").Split(","); 55 | } 56 | 57 | public bool GetEnforceTimeWindow() 58 | { 59 | return ReadSettingAsBool("EnforceTimeWindow", false); 60 | } 61 | 62 | public int GetTimeWindowSecs() 63 | { 64 | return ReadSettingAsInt("TimeWindowSecs", 35); 65 | } 66 | 67 | public bool GetEnableMasterControls() 68 | { 69 | return ReadSettingAsBool("EnableMasterControls", true); 70 | } 71 | 72 | 73 | public bool GetAllowFundsCommands() 74 | { 75 | return ReadSettingAsBool("AllowFundsCommands", false); 76 | } 77 | 78 | public bool GetAllowIMcontrol() 79 | { 80 | return ReadSettingAsBool("AllowIMcontrol", true); 81 | } 82 | 83 | public string GetSharedSecret() 84 | { 85 | return ReadSettingAsString("SharedSecret", "ThisIsMySecret"); 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /SecondBotEvents/Config/CustomCommandsConfig.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace SecondBotEvents.Config 6 | { 7 | public class CustomCommandsConfig(bool fromENV, string fromFolder = "") : Config(fromENV, fromFolder) 8 | { 9 | protected override void MakeSettings() 10 | { 11 | filename = "customcommands"; 12 | settings.Add("count"); 13 | settings.Add("HideStatusOutput"); 14 | int loop = 1; 15 | while(loop <= GetCount()) 16 | { 17 | settings.Add(loop.ToString() + "_trigger"); 18 | settings.Add(loop.ToString() + "_args"); 19 | settings.Add(loop.ToString() + "_steps"); 20 | int loop2 = 1; 21 | while(loop2 <= GetCommandSteps(loop)) 22 | { 23 | settings.Add(loop.ToString() + "_commands_"+loop2.ToString()); 24 | loop2++; 25 | } 26 | loop++; 27 | } 28 | } 29 | 30 | public string GetCommandStep(int commandIndex, int step) 31 | { 32 | return ReadSettingAsString(commandIndex.ToString() + "_commands_"+ step.ToString(), "Logoff"); 33 | } 34 | 35 | public string GetCommandTrigger(int commandIndex) 36 | { 37 | return ReadSettingAsString(commandIndex.ToString() + "_trigger", "exitplease"); 38 | } 39 | 40 | public int GetCommandSteps(int commandIndex) 41 | { 42 | return ReadSettingAsInt(commandIndex.ToString() + "_steps", 0); 43 | } 44 | 45 | public int GetCommandArgs(int commandIndex) 46 | { 47 | return ReadSettingAsInt(commandIndex.ToString() + "_args", 0); 48 | } 49 | 50 | public int GetCount() 51 | { 52 | return ReadSettingAsInt("count", 1); 53 | } 54 | } 55 | 56 | } -------------------------------------------------------------------------------- /SecondBotEvents/Config/DataStoreConfig.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace SecondBotEvents.Config 6 | { 7 | public class DataStoreConfig(bool fromENV, string fromFolder = "") : Config(fromENV, fromFolder) 8 | { 9 | protected override void MakeSettings() 10 | { 11 | filename = "datastore"; 12 | settings.Add("AutoCleanAvatars"); 13 | settings.Add("AvatarsCleanAfterMins"); 14 | settings.Add("LocalChatHistoryLimit"); 15 | settings.Add("GroupChatHistoryLimitPerGroup"); 16 | settings.Add("ImChatHistoryLimit"); 17 | settings.Add("PrefetchGroupMembers"); 18 | settings.Add("PrefetchGroupRoles"); 19 | settings.Add("PrefetchEstateBanlist"); 20 | settings.Add("AutoCleanKeyValueStore"); 21 | settings.Add("CleanKeyValueStoreAfterMins"); 22 | settings.Add("CommandHistoryLimit"); 23 | settings.Add("HideStatusOutput"); 24 | } 25 | 26 | 27 | public int GetCommandHistoryLimit() 28 | { 29 | return ReadSettingAsInt("CommandHistoryLimit", 30); 30 | } 31 | 32 | 33 | public bool GetAutoCleanKeyValueStore() 34 | { 35 | return ReadSettingAsBool("AutoCleanKeyValueStore", true); 36 | } 37 | 38 | public int GetCleanKeyValueStoreAfterMins() 39 | { 40 | return ReadSettingAsInt("CleanKeyValueStoreAfterMins", 10); 41 | } 42 | 43 | public bool GetPrefetchEstateBanlist() 44 | { 45 | return ReadSettingAsBool("PrefetchEstateBanlist", true); 46 | } 47 | 48 | public bool GetPrefetchGroupRoles() 49 | { 50 | return ReadSettingAsBool("PrefetchGroupRoles", false); 51 | } 52 | 53 | public bool GetPrefetchGroupMembers() 54 | { 55 | return ReadSettingAsBool("PrefetchGroupMembers", true); 56 | } 57 | 58 | public bool GetAutoCleanAvatars() 59 | { 60 | return ReadSettingAsBool("AutoCleanAvatars", true); 61 | } 62 | 63 | public int GetAvatarsCleanAfterMins() 64 | { 65 | return ReadSettingAsInt("AvatarsCleanAfterMins", 10); 66 | } 67 | 68 | public int GetLocalChatHistoryLimit() 69 | { 70 | return ReadSettingAsInt("LocalChatHistoryLimit", 150); 71 | } 72 | 73 | public int GetGroupChatHistoryLimitPerGroup() 74 | { 75 | return ReadSettingAsInt("GroupChatHistoryLimitPerGroup", 50); 76 | } 77 | 78 | public int GetImChatHistoryLimit() 79 | { 80 | return ReadSettingAsInt("ImChatHistoryLimit", 50); 81 | } 82 | } 83 | } -------------------------------------------------------------------------------- /SecondBotEvents/Config/DialogRelayConfig.cs: -------------------------------------------------------------------------------- 1 | using OpenMetaverse; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace SecondBotEvents.Config 7 | { 8 | public class DialogRelayConfig(bool fromENV, string fromFolder = "") : Config(fromENV, fromFolder) 9 | { 10 | protected override void MakeSettings() 11 | { 12 | filename = "dialogrelay"; 13 | settings.Add("RelayChannel"); 14 | settings.Add("RelayAvatar"); 15 | settings.Add("RelayObjectOwnerOnly"); 16 | settings.Add("RelayHttpurl"); 17 | settings.Add("HideStatusOutput"); 18 | } 19 | 20 | public string GetRelayHttpurl() 21 | { 22 | return ReadSettingAsString("RelayHttpurl", "-"); 23 | } 24 | 25 | public int GetRelayChannel() 26 | { 27 | return ReadSettingAsInt("RelayChannel", -1); 28 | } 29 | 30 | public string GetRelayAvatar() 31 | { 32 | return ReadSettingAsString("RelayAvatar", UUID.Zero.ToString()); 33 | } 34 | 35 | public string RelayObjectOwnerOnly() 36 | { 37 | return ReadSettingAsString("RelayObjectOwnerOnly", UUID.Zero.ToString()); 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /SecondBotEvents/Config/DiscordConfig.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace SecondBotEvents.Config 6 | { 7 | public class DiscordConfig(bool fromENV, string fromFolder = "") : Config(fromENV, fromFolder) 8 | { 9 | protected override void MakeSettings() 10 | { 11 | filename = "discord"; 12 | settings.Add("Enabled"); 13 | settings.Add("ServerID"); 14 | settings.Add("ClientToken"); 15 | settings.Add("AllowDiscordCommands"); 16 | settings.Add("InteractionEnabled"); 17 | settings.Add("InteractionCommandName"); 18 | settings.Add("InteractionHttpTarget"); 19 | settings.Add("InteractionChannelNumber"); 20 | settings.Add("hideChatterName"); 21 | settings.Add("HideStatusOutput"); 22 | } 23 | 24 | public bool GetEnabled() 25 | { 26 | return ReadSettingAsBool("Enabled"); 27 | } 28 | 29 | public bool GethideChatterName() 30 | { 31 | return ReadSettingAsBool("hideChatterName", false); 32 | } 33 | 34 | public ulong GetServerID() 35 | { 36 | return ReadSettingAsUlong("ServerID", 0); 37 | } 38 | 39 | public string GetClientToken() 40 | { 41 | return ReadSettingAsString("ClientToken","tokenPlzKThanks"); 42 | } 43 | 44 | public bool GetAllowDiscordCommands() 45 | { 46 | return ReadSettingAsBool("AllowDiscordCommands"); 47 | } 48 | 49 | public bool GetInteractionEnabled() 50 | { 51 | return ReadSettingAsBool("InteractionEnabled"); 52 | } 53 | 54 | public string GetInteractionHttpTarget() 55 | { 56 | return ReadSettingAsString("InteractionHttpTarget", "https://localhost/interaction.php"); 57 | } 58 | 59 | public string GetInteractionCommandName() 60 | { 61 | return ReadSettingAsString("InteractionCommandName","Go"); 62 | } 63 | 64 | public string GetInteractionChannelNumber() 65 | { 66 | return ReadSettingAsString("InteractionChannelNumber", "-1"); 67 | } 68 | 69 | public void SetInteractionEnabled(bool enabled) 70 | { 71 | mysettings["InteractionEnabled"] = enabled.ToString(); 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /SecondBotEvents/Config/EventsConfig.cs: -------------------------------------------------------------------------------- 1 | using OpenMetaverse; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace SecondBotEvents.Config 7 | { 8 | public class EventsConfig(bool fromENV, string fromFolder = "") : Config(fromENV, fromFolder) 9 | { 10 | protected override void MakeSettings() 11 | { 12 | filename = "events"; 13 | settings.Add("Enabled"); 14 | settings.Add("GroupMemberJoins"); 15 | settings.Add("GroupMemberLeaves"); 16 | settings.Add("GroupMemberEventsGroupUUID"); 17 | 18 | settings.Add("GuestEntersArea"); 19 | settings.Add("GuestLeavesArea"); 20 | settings.Add("GuestTrackingSimname"); 21 | settings.Add("GuestTrackingParcelname"); 22 | 23 | 24 | settings.Add("SimAlertMessage"); 25 | settings.Add("StatusMessage"); 26 | settings.Add("MoneyEvent"); 27 | 28 | 29 | settings.Add("ChangeSim"); 30 | settings.Add("ChangeParcel"); 31 | 32 | settings.Add("OutputChannel"); 33 | settings.Add("OutputIMuuid"); 34 | settings.Add("OutputHttpURL"); 35 | settings.Add("OutputSecret"); 36 | settings.Add("HideStatusOutput"); 37 | } 38 | 39 | public string GetOutputSecret() 40 | { 41 | return ReadSettingAsString("OutputSecret", "donttellanyone"); 42 | } 43 | 44 | public string GetGuestTrackingSimname() 45 | { 46 | return ReadSettingAsString("GuestTrackingSimname", "example"); 47 | } 48 | 49 | public string GetGuestTrackingParcelname() 50 | { 51 | return ReadSettingAsString("GuestTrackingParcelname", "example"); 52 | } 53 | 54 | public string GetGroupMemberEventsGroupUUID() 55 | { 56 | return ReadSettingAsString("GroupMemberEventsGroupUUID", UUID.Zero.ToString()); 57 | } 58 | 59 | public string GetOutputHttpURL() 60 | { 61 | return ReadSettingAsString("OutputHttpURL", "n/a"); 62 | } 63 | 64 | public string GetOutputIMuuid() 65 | { 66 | return ReadSettingAsString("OutputIMuuid", UUID.Zero.ToString()); 67 | } 68 | 69 | public int GetOutputChannel() 70 | { 71 | return ReadSettingAsInt("OutputChannel", -1); 72 | } 73 | 74 | public bool GetGroupMemberJoins() 75 | { 76 | return ReadSettingAsBool("GroupMemberJoins", true); 77 | } 78 | 79 | public bool GetGroupMemberLeaves() 80 | { 81 | return ReadSettingAsBool("GroupMemberLeaves", true); 82 | } 83 | 84 | public bool GetGuestEntersArea() 85 | { 86 | return ReadSettingAsBool("GuestEntersArea", true); 87 | } 88 | 89 | public bool GetGuestLeavesArea() 90 | { 91 | return ReadSettingAsBool("GuestLeavesArea", true); 92 | } 93 | 94 | public bool GetChangeSim() 95 | { 96 | return ReadSettingAsBool("ChangeSim", true); 97 | } 98 | 99 | public bool GetChangeParcel() 100 | { 101 | return ReadSettingAsBool("ChangeParcel", true); 102 | } 103 | 104 | public bool GetSimAlertMessage() 105 | { 106 | return ReadSettingAsBool("SimAlertMessage", true); 107 | } 108 | 109 | public bool GetStatusMessage() 110 | { 111 | return ReadSettingAsBool("StatusMessage", true); 112 | } 113 | 114 | public bool GetMoneyEvent() 115 | { 116 | return ReadSettingAsBool("MoneyEvent", true); 117 | } 118 | 119 | public bool GetEnabled() 120 | { 121 | return ReadSettingAsBool("Enabled", false); 122 | } 123 | } 124 | 125 | } -------------------------------------------------------------------------------- /SecondBotEvents/Config/HomeboundConfig.cs: -------------------------------------------------------------------------------- 1 | using OpenMetaverse; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace SecondBotEvents.Config 7 | { 8 | public class HomeboundConfig(bool fromENV, string fromFolder = "") : Config(fromENV, fromFolder) 9 | { 10 | protected override void MakeSettings() 11 | { 12 | filename = "homebound"; 13 | settings.Add("Enabled"); 14 | settings.Add("HomeSimSlUrl"); 15 | settings.Add("BackupSimSLUrl"); 16 | settings.Add("ReturnToHomeSimAfterMins"); 17 | settings.Add("AtHomeSeekLocation"); 18 | settings.Add("AtBackupSeekLocation"); 19 | settings.Add("AtHomeAutoSitUuid"); 20 | settings.Add("HideStatusOutput"); 21 | } 22 | 23 | public string GetAtHomeAutoSitUuid() 24 | { 25 | return ReadSettingAsString("AtHomeAutoSitUuid", UUID.Zero.ToString()); 26 | } 27 | 28 | public int GetReturnToHomeSimAfterMins() 29 | { 30 | return ReadSettingAsInt("ReturnToHomeSimAfterMins", 1); 31 | } 32 | 33 | public bool GetAtHomeSeekLocation() 34 | { 35 | return ReadSettingAsBool("AtHomeSeekLocation", true); 36 | } 37 | 38 | public bool GetAtBackupSeekLocation() 39 | { 40 | return ReadSettingAsBool("AtBackupSeekLocation", false); 41 | } 42 | 43 | public string GetBackupSimSLUrl() 44 | { 45 | return ReadSettingAsString("BackupSimSLUrl", "Sandbox%20Decorus/128/128/27"); 46 | } 47 | 48 | public string GetHomeSimSlUrl() 49 | { 50 | return ReadSettingAsString("HomeSimSlUrl", "Viserion/46/163/23"); 51 | } 52 | 53 | public bool GetEnabled() 54 | { 55 | return ReadSettingAsBool("Enabled", false); 56 | } 57 | } 58 | 59 | } -------------------------------------------------------------------------------- /SecondBotEvents/Config/HttpConfig.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace SecondBotEvents.Config 6 | { 7 | public class HttpConfig(bool fromENV, string fromFolder = "") : Config(fromENV, fromFolder) 8 | { 9 | protected override void MakeSettings() 10 | { 11 | filename = "http"; 12 | settings.Add("Enabled"); 13 | settings.Add("HideStatusOutput"); 14 | } 15 | 16 | public bool GetEnabled() 17 | { 18 | return ReadSettingAsBool("Enabled", true); 19 | } 20 | } 21 | 22 | } -------------------------------------------------------------------------------- /SecondBotEvents/Config/InteractionConfig.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace SecondBotEvents.Config 6 | { 7 | public class InteractionConfig(bool fromENV, string fromFolder = "") : Config(fromENV, fromFolder) 8 | { 9 | protected override void MakeSettings() 10 | { 11 | filename = "interaction"; 12 | settings.Add("AcceptTeleports"); 13 | settings.Add("AcceptGroupInvites"); 14 | settings.Add("AcceptInventory"); 15 | settings.Add("EnableJsonOutputEvents"); 16 | settings.Add("JsonOutputEventsTarget"); 17 | settings.Add("AcceptFriendRequests"); 18 | settings.Add("FriendRequestLevel"); 19 | settings.Add("InventoryTransferLevel"); 20 | settings.Add("GroupInviteLevel"); 21 | settings.Add("TeleportRequestLevel"); 22 | settings.Add("Enabled"); 23 | settings.Add("HideStatusOutput"); 24 | settings.Add("EnableDebug"); 25 | } 26 | 27 | public bool GetEnableDebug() 28 | { 29 | return ReadSettingAsBool("EnableDebug", false); 30 | } 31 | 32 | public string GetFriendRequestLevel() 33 | { 34 | return ReadSettingAsString("FriendRequestLevel", "Owner"); 35 | } 36 | public string GetInventoryTransferLevel() 37 | { 38 | return ReadSettingAsString("InventoryTransferLevel", "Owner"); 39 | } 40 | public string GetGroupInviteLevel() 41 | { 42 | return ReadSettingAsString("GroupInviteLevel", "Owner"); 43 | } 44 | public string GetTeleportRequestLevel() 45 | { 46 | return ReadSettingAsString("TeleportRequestLevel", "Owner"); 47 | } 48 | 49 | public bool GetEnabled() 50 | { 51 | return ReadSettingAsBool("Enabled", true); 52 | } 53 | 54 | public bool GetAcceptTeleports() 55 | { 56 | return ReadSettingAsBool("AcceptTeleports", true); 57 | } 58 | 59 | public bool GetAcceptGroupInvites() 60 | { 61 | return ReadSettingAsBool("AcceptGroupInvites", true); 62 | } 63 | 64 | public bool GetAcceptInventory() 65 | { 66 | return ReadSettingAsBool("AcceptInventory", true); 67 | } 68 | 69 | public bool GetAcceptFriendRequests() 70 | { 71 | return ReadSettingAsBool("AcceptFriendRequests", true); 72 | } 73 | 74 | public string GetJsonOutputEventsTarget() 75 | { 76 | return ReadSettingAsString("JsonOutputEventsTarget", "none"); 77 | } 78 | 79 | public bool GetEnableJsonOutputEvents() 80 | { 81 | return ReadSettingAsBool("EnableJsonOutputEvents", false); 82 | } 83 | } 84 | 85 | } -------------------------------------------------------------------------------- /SecondBotEvents/Config/OnEventConfig.cs: -------------------------------------------------------------------------------- 1 | using OpenMetaverse; 2 | using SecondBotEvents.Services; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | 7 | namespace SecondBotEvents.Config 8 | { 9 | public class OnEventConfig(bool fromENV, string fromFolder = "") : Config(fromENV, fromFolder) 10 | { 11 | protected override void MakeSettings() 12 | { 13 | filename = "onevent"; 14 | settings.Add("Enabled"); 15 | settings.Add("Count"); 16 | settings.Add("WaitSecsToStart"); 17 | settings.Add("HideStatusOutput"); 18 | settings.Add("DebugMe"); 19 | } 20 | 21 | public int GetWaitSecsToStart() 22 | { 23 | return ReadSettingAsInt("WaitSecsToStart", 10); 24 | } 25 | 26 | public void unloadEvents() 27 | { 28 | int loop = 1; 29 | while (loop <= GetCount()) 30 | { 31 | if (GetEventEnabled(loop) == false) 32 | { 33 | loop++; 34 | continue; 35 | } 36 | RemoveSetting("Event" + loop.ToString() + "Enabled"); 37 | RemoveSetting("Event" + loop.ToString() + "Source"); 38 | RemoveSetting("Event" + loop.ToString() + "Monitor"); 39 | int loop2 = 1; 40 | while (loop2 <= GetWhereCount(loop)) 41 | { 42 | RemoveSetting("Event" + loop.ToString() + "Where" + loop2.ToString()); 43 | loop2++; 44 | } 45 | RemoveSetting("Event" + loop.ToString() + "WhereCount"); 46 | loop2 = 1; 47 | while (loop2 <= GetActionCount(loop)) 48 | { 49 | settings.Remove("Event" + loop.ToString() + "Action" + loop2.ToString()); 50 | loop2++; 51 | } 52 | RemoveSetting("Event" + loop.ToString() + "ActionCount"); 53 | loop++; 54 | } 55 | } 56 | 57 | protected void RemoveSetting(string name) 58 | { 59 | mysettings.Remove(name); 60 | settings.Remove(name); 61 | } 62 | 63 | public bool GetDebugMe() 64 | { 65 | return ReadSettingAsBool("DebugMe", false); 66 | } 67 | public bool GetEnabled() 68 | { 69 | return ReadSettingAsBool("Enabled", false); 70 | } 71 | 72 | public int GetCount() 73 | { 74 | return ReadSettingAsInt("Count", 0); 75 | } 76 | 77 | public int GetActionCount(int oneventid) 78 | { 79 | return ReadSettingAsInt("Event" + oneventid.ToString() + "ActionCount", 0); 80 | } 81 | 82 | public string GetActionStep(int oneventid, int stepid) 83 | { 84 | return ReadSettingAsString("Event" + oneventid.ToString() + "Action" + stepid.ToString(), ""); 85 | } 86 | 87 | public string GetWhereCheck(int oneventid, int checkid) 88 | { 89 | return ReadSettingAsString("Event" + oneventid.ToString() + "Where" + checkid.ToString(), ""); 90 | } 91 | 92 | public int GetWhereCount(int oneventid) 93 | { 94 | return ReadSettingAsInt("Event" + oneventid.ToString() + "WhereCount", 0); 95 | } 96 | 97 | public bool GetEventEnabled(int oneventid) 98 | { 99 | return ReadSettingAsBool("Event" + oneventid.ToString() + "Enabled", false); 100 | } 101 | 102 | public string GetSource(int oneventid) 103 | { 104 | return ReadSettingAsString("Event" + oneventid.ToString() + "Source", ""); 105 | } 106 | public string GetSourceMonitor(int oneventid) 107 | { 108 | return ReadSettingAsString("Event" + oneventid.ToString() + "Monitor", ""); 109 | } 110 | } 111 | } -------------------------------------------------------------------------------- /SecondBotEvents/Config/RlvConfig.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace SecondBotEvents.Config 6 | { 7 | public class RlvConfig(bool fromENV, string fromFolder = "") : Config(fromENV, fromFolder) 8 | { 9 | protected override void MakeSettings() 10 | { 11 | filename = "rlv"; 12 | settings.Add("Enabled"); 13 | settings.Add("HideStatusOutput"); 14 | } 15 | 16 | public bool GetEnabled() 17 | { 18 | return ReadSettingAsBool("Enabled", false); 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /SecondBotEvents/Config/SmtpConfig.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace SecondBotEvents.Config 6 | { 7 | public class SmtpConfig(bool fromENV, string fromFolder = "") : Config(fromENV, fromFolder) 8 | { 9 | protected override void MakeSettings() 10 | { 11 | filename = "smtp"; 12 | settings.Add("Enabled"); 13 | settings.Add("AllowEmailAsReplyTarget"); 14 | settings.Add("AllowCommandSendMail"); 15 | settings.Add("UseAllowedRecivers"); 16 | settings.Add("AllowedReciversCSV"); 17 | settings.Add("AllowSendAlertStatus"); 18 | settings.Add("AllowSendLoginNotice"); 19 | settings.Add("MailReplyAddress"); 20 | settings.Add("Port"); 21 | settings.Add("Host"); 22 | settings.Add("useSSL"); 23 | settings.Add("User"); 24 | settings.Add("Token"); 25 | settings.Add("SendAlertsAndLoginsTo"); 26 | settings.Add("HideStatusOutput"); 27 | 28 | } 29 | public bool GetUseAllowedRecivers() 30 | { 31 | return ReadSettingAsBool("UseAllowedRecivers", false); 32 | } 33 | public string[] GetAllowedRecivers() 34 | { 35 | return ReadSettingAsString("AllowedReciversCSV", "none").Split(','); 36 | } 37 | public bool GetUseSSL() 38 | { 39 | return ReadSettingAsBool("useSSL", false); 40 | } 41 | 42 | public string GetMailReplyAddress() 43 | { 44 | return ReadSettingAsString("MailReplyAddress", "me@myemail.tld"); 45 | } 46 | 47 | public string GetSendAlertsAndLoginsTo() 48 | { 49 | return ReadSettingAsString("SendAlertsAndLoginsTo", "me@somewhere.tld"); 50 | } 51 | public int GetPort() 52 | { 53 | return ReadSettingAsInt("Port", 587); 54 | } 55 | 56 | public string GetHost() 57 | { 58 | return ReadSettingAsString("Host", "smtp.mail.example"); 59 | } 60 | 61 | public string GetUser() 62 | { 63 | return ReadSettingAsString("User", "me@email.addr.tld"); 64 | } 65 | 66 | public string GetToken() 67 | { 68 | return ReadSettingAsString("Token", "none"); 69 | } 70 | 71 | public bool GetEnabled() 72 | { 73 | return ReadSettingAsBool("Enabled", false); 74 | } 75 | 76 | public bool GetAllowEmailAsReplyTarget() 77 | { 78 | return ReadSettingAsBool("AllowEmailAsReplyTarget", false); 79 | } 80 | 81 | public bool GetAllowCommandSendMail() 82 | { 83 | return ReadSettingAsBool("AllowCommandSendMail", false); 84 | } 85 | 86 | public bool GetAllowSendAlertStatus() 87 | { 88 | return ReadSettingAsBool("AllowSendAlertStatus", false); 89 | } 90 | 91 | public bool GetAllowSendLoginNotice() 92 | { 93 | return ReadSettingAsBool("AllowSendLoginNotice", false); 94 | } 95 | } 96 | } -------------------------------------------------------------------------------- /SecondBotEvents/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace SecondBotEvents.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SecondBotEvents.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /SecondBotEvents/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "SecondBotEvents": { 4 | "commandName": "Project" 5 | }, 6 | "Docker": { 7 | "commandName": "Docker" 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /SecondBotEvents/RLV/RLVAttachmentInfo.cs: -------------------------------------------------------------------------------- 1 | using OpenMetaverse; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace SecondBotEvents.RLV 9 | { 10 | public class AttachmentInfo 11 | { 12 | public Primitive Prim; 13 | public InventoryItem Item; 14 | public UUID InventoryID; 15 | public UUID PrimID; 16 | public bool MarkedAttached; 17 | public AttachmentPoint Point => Prim != null ? Prim.PrimData.AttachmentPoint : AttachmentPoint.Default; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /SecondBotEvents/RLV/RLVEventArgs.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Radegast Metaverse Client 3 | * Copyright(c) 2009-2014, Radegast Development Team 4 | * Copyright(c) 2016-2020, Sjofn, LLC 5 | * All rights reserved. 6 | * 7 | * Radegast is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU Lesser General Public License as published 9 | * by the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with this program.If not, see. 19 | */ 20 | 21 | using System; 22 | 23 | namespace SecondBotEvents.RLV 24 | { 25 | public class RLVEventArgs(RLVRule rule) : EventArgs 26 | { 27 | public RLVRule Rule { set; get; } = rule; 28 | } 29 | } -------------------------------------------------------------------------------- /SecondBotEvents/RLV/RLVRule.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Radegast Metaverse Client 3 | * Copyright(c) 2009-2014, Radegast Development Team 4 | * Copyright(c) 2016-2020, Sjofn, LLC 5 | * All rights reserved. 6 | * 7 | * Radegast is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU Lesser General Public License as published 9 | * by the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with this program.If not, see. 19 | */ 20 | 21 | using OpenMetaverse; 22 | 23 | namespace SecondBotEvents.RLV 24 | { 25 | public class RLVRule 26 | { 27 | public string Behaviour { set; get; } 28 | public string Option { set; get; } 29 | public string Param { set; get; } 30 | public UUID Sender { set; get; } 31 | public string SenderName { set; get; } 32 | 33 | public override string ToString() 34 | { 35 | return string.Format("{0}: {1}:{2}={3} [{4}]", SenderName, Behaviour, Option, Param, Sender); 36 | } 37 | } 38 | } 39 | 40 | -------------------------------------------------------------------------------- /SecondBotEvents/SecondBotEvents.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Exe 4 | net9.0 5 | SecondBotEvents.Startup 6 | git rev-parse --short HEAD 7 | False 8 | False 9 | Linux 10 | settings.env 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | all 23 | runtime; build; native; contentfiles; analyzers; buildtransitive 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | True 35 | True 36 | Resources.resx 37 | 38 | 39 | 40 | 41 | ResXFileCodeGenerator 42 | Resources.Designer.cs 43 | 44 | 45 | 46 | 47 | Always 48 | 49 | 50 | -------------------------------------------------------------------------------- /SecondBotEvents/Services/RecoveryService.cs: -------------------------------------------------------------------------------- 1 | using OpenMetaverse; 2 | using SecondBotEvents.Config; 3 | using System.Threading; 4 | using Timer = System.Timers.Timer; 5 | namespace SecondBotEvents.Services 6 | { 7 | public class RecoveryService(EventsSecondBot setMaster) : BotServices(setMaster) 8 | { 9 | protected Timer AutoRestartLoginTimer; 10 | protected new BasicConfig myConfig = new BasicConfig(false); 11 | 12 | public override string Status() 13 | { 14 | return ""; 15 | } 16 | 17 | protected void BotClientRestart(object o, BotClientNotice e) 18 | { 19 | if(e.isStart == true) 20 | { 21 | LogFormater.Info("RecoveryService [Attached to new client]"); 22 | } 23 | else if(e.isDC == true) 24 | { 25 | TriggerRecovery(); 26 | } 27 | 28 | } 29 | public void TriggerRecovery() 30 | { 31 | LogFormater.Info("RecoveryService [Triggered]"); 32 | if(master.BotClient != null) 33 | { 34 | if(master.BotClient.client != null) 35 | { 36 | if(master.BotClient.client.Network != null) 37 | { 38 | master.BotClient.client.Network.BeginLogout(); // attempt to flag logout 39 | } 40 | } 41 | } 42 | if (master.BotClient != null) 43 | { 44 | master.BotClient.flagLogoutExpected(); 45 | } 46 | master.StopServices("RecoveryService"); // stop everything but recovery and the core bot service 47 | Thread.Sleep(2 * 1000); // give it 2 secs 48 | master.StopService("BotClientService"); 49 | Thread.Sleep(75 * 1000); // wait 75 secs 50 | master.StartServices(); 51 | } 52 | 53 | public override void Start(bool updateEnabled = false, bool setEnabledTo = false) 54 | { 55 | if (updateEnabled) 56 | { 57 | myConfig.setEnabled(setEnabledTo); 58 | } 59 | Stop(); 60 | master.BotClientNoticeEvent += BotClientRestart; 61 | LogFormater.Info("Relay Service [Starting]"); 62 | } 63 | 64 | public override void Stop() 65 | { 66 | if (running == true) 67 | { 68 | LogFormater.Info("Relay Service [Stopping]"); 69 | } 70 | 71 | } 72 | } 73 | } 74 | 75 | -------------------------------------------------------------------------------- /SecondBotEvents/Services/Services.cs: -------------------------------------------------------------------------------- 1 | using OpenMetaverse; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | using SecondBotEvents.Config; 6 | 7 | namespace SecondBotEvents.Services 8 | { 9 | public abstract class BotServices(EventsSecondBot setMaster) 10 | { 11 | public EventsSecondBot master = setMaster; 12 | protected Config.Config myConfig; 13 | protected bool running = false; 14 | 15 | public void enableAndStart() 16 | { 17 | Restart(true, true); 18 | } 19 | 20 | public void changeConfig(string configKey, string configValue) 21 | { 22 | myConfig.updateKey(configKey, configValue); 23 | } 24 | 25 | public bool isRunning() { return running; } 26 | 27 | public GridClient GetClient() 28 | { 29 | if(master == null) 30 | { 31 | return null; 32 | } 33 | else if(master.BotClient == null) 34 | { 35 | return null; 36 | } 37 | return master.BotClient.client; 38 | } 39 | public virtual string Status() 40 | { 41 | return ""; 42 | } 43 | 44 | public virtual void Start(bool updateEnabled = false, bool setEnabledTo = false) 45 | { 46 | running = true; 47 | } 48 | public virtual void Stop() 49 | { 50 | running = false; 51 | } 52 | public void Restart(bool updateEnabled=false, bool setEnabledTo=false) 53 | { 54 | if (running == true) 55 | { 56 | Stop(); 57 | } 58 | Start(updateEnabled, setEnabledTo); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /SecondBotEvents/Static/LogFormater.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | 4 | namespace SecondBotEvents 5 | { 6 | public enum ConsoleLogLogLevel 7 | { 8 | Status, 9 | Info, 10 | Crit, 11 | Warn, 12 | Debug, 13 | }; 14 | public static class LogFormater 15 | { 16 | public static string Warn(string message,bool send_to_console) 17 | { 18 | return Add(message, ConsoleLogLogLevel.Warn, send_to_console); 19 | } 20 | public static string Crit(string message, bool send_to_console) 21 | { 22 | return Add(message, ConsoleLogLogLevel.Crit, send_to_console); 23 | } 24 | public static string Info(string message, bool send_to_console) 25 | { 26 | return Add(message, ConsoleLogLogLevel.Info, send_to_console); 27 | } 28 | public static string Status(string message, bool send_to_console) 29 | { 30 | return Add(message, ConsoleLogLogLevel.Status, send_to_console); 31 | } 32 | public static string Debug(string message, bool send_to_console) 33 | { 34 | return Add(message, ConsoleLogLogLevel.Debug, send_to_console); 35 | } 36 | public static string Warn(string message) 37 | { 38 | return Warn(message, true); 39 | } 40 | public static string Crit(string message) 41 | { 42 | return Crit(message, true); 43 | } 44 | public static string Info(string message) 45 | { 46 | return Info(message, true); 47 | } 48 | public static string Status(string message) 49 | { 50 | return Status(message, true); 51 | } 52 | public static string Debug(string message) 53 | { 54 | return Debug(message, true); 55 | } 56 | 57 | public static string GetClockStamp() 58 | { 59 | var date = DateTime.Now; 60 | StringBuilder n = new(); 61 | n.Append("["); 62 | if (date.Hour < 10) 63 | { 64 | n.Append("0"); 65 | } 66 | n.Append(date.Hour.ToString()); 67 | n.Append(":"); 68 | if (date.Minute < 10) 69 | { 70 | n.Append("0"); 71 | } 72 | n.Append(date.Minute.ToString()); 73 | n.Append("] "); 74 | return n.ToString(); 75 | } 76 | 77 | private static string Add(string message, ConsoleLogLogLevel Level, bool send_to_console = true) 78 | { 79 | 80 | StringBuilder n = new(); 81 | n.Append(GetClockStamp()); 82 | switch (Level) 83 | { 84 | #if DEBUG 85 | case ConsoleLogLogLevel.Debug: 86 | { 87 | n.Append("Debug - "); 88 | break; 89 | } 90 | case ConsoleLogLogLevel.Info: 91 | { 92 | n.Append("Info - "); 93 | break; 94 | } 95 | #endif 96 | case ConsoleLogLogLevel.Status: 97 | { 98 | n.Append("Status - "); 99 | break; 100 | } 101 | case ConsoleLogLogLevel.Warn: 102 | { 103 | n.Append("Warn - "); 104 | break; 105 | } 106 | case ConsoleLogLogLevel.Crit: 107 | { 108 | n.Append("Crit - "); 109 | break; 110 | } 111 | default: 112 | { 113 | n.Append("Log - "); 114 | break; 115 | } 116 | } 117 | n.Append(message); 118 | if(send_to_console == true) 119 | { 120 | Console.WriteLine(n.ToString()); 121 | } 122 | return n.ToString(); 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /SecondBotEvents/Static/SimpleIO.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.IO; 5 | 6 | namespace SecondBotEvents 7 | { 8 | public class SimpleIO 9 | { 10 | protected string root_folder = ""; 11 | public void ChangeRoot(string A) 12 | { 13 | root_folder = A; 14 | if (root_folder != "") 15 | { 16 | if (DirExists(root_folder) == false) 17 | { 18 | System.IO.Directory.CreateDirectory(root_folder); 19 | } 20 | } 21 | } 22 | public static bool DirExists(string target_folder) 23 | { 24 | return System.IO.Directory.Exists(target_folder); 25 | } 26 | public void Delete(string filename) 27 | { 28 | System.IO.File.Delete(root_folder+"/"+filename); 29 | } 30 | public void WriteFile(string filename,string content) 31 | { 32 | if(Exists(filename) == true) 33 | { 34 | Delete(filename); 35 | } 36 | System.IO.File.WriteAllText(@""+root_folder + "/" + filename, content); 37 | } 38 | 39 | public void MarkOld(string targetfile) 40 | { 41 | System.IO.File.Move(@""+root_folder + "/" + targetfile, @"" + root_folder + "/" + targetfile+".old"); 42 | } 43 | public bool Exists(string targetfile) 44 | { 45 | return File.Exists(@""+root_folder+"/" + targetfile); 46 | } 47 | public static bool FileType(string targetfile, string matchtype) 48 | { 49 | string[] bits = targetfile.Split('.'); 50 | if (bits[^1] == matchtype) 51 | { 52 | return true; 53 | } 54 | return false; 55 | } 56 | public string ReadFile(string targetfile) 57 | { 58 | if (Exists(targetfile) == true) 59 | { 60 | string return_text = ""; 61 | using (var Stream = new FileStream(@"" + root_folder + "/" + targetfile, FileMode.Open, FileAccess.Read)) 62 | using (var StreamReader = new StreamReader(Stream)) 63 | { 64 | return_text = StreamReader.ReadToEnd(); 65 | } 66 | return return_text; 67 | } 68 | return ""; 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /SecondBotEvents/Static/http_commands_helper.cs: -------------------------------------------------------------------------------- 1 | using SecondBotEvents.Commands; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace SecondBotEvents 7 | { 8 | public static class http_commands_helper 9 | { 10 | public static Dictionary getCommandModules() 11 | { 12 | Dictionary reply = new() 13 | { 14 | { "animation", typeof(AnimationCommands) }, 15 | { "avatars", typeof(Avatars) }, 16 | { "chat", typeof(Chat) }, 17 | { "core", typeof(Core) }, 18 | { "dialogs", typeof(Dialogs) }, 19 | { "discord", typeof(DiscordCommands) }, 20 | { "estate", typeof(Estate) }, 21 | { "friends", typeof(Friends) }, 22 | { "funds", typeof(Funds) }, 23 | { "group", typeof(GroupCommands) }, 24 | { "info", typeof(Info) }, 25 | { "inventory", typeof(InventoryCommands) }, 26 | { "movement", typeof(Movement) }, 27 | { "notecard", typeof(Notecard) }, 28 | { "parcel", typeof(ParcelCommands) }, 29 | { "self", typeof(Self) }, 30 | { "streamadmin", typeof(StreamAdmin) }, 31 | { "services", typeof(SecondBotEvents.Commands.Services) } 32 | }; 33 | return reply; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /SecondBotEvents/Static/parcel.cs: -------------------------------------------------------------------------------- 1 | using OpenMetaverse; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace SecondBotEvents 7 | { 8 | public static class ParcelStatic 9 | { 10 | public static bool SetParcelMusic(GridClient bot, Parcel p, string url) 11 | { 12 | if (p.MusicURL != url) 13 | { 14 | p.MusicURL = url; 15 | p.Update(bot); 16 | } 17 | return true; 18 | } 19 | public static void ParcelSetFlag(ParcelFlags F, Parcel p, bool set) 20 | { 21 | if (p.Flags.HasFlag(F)) 22 | { 23 | p.Flags -= F; 24 | } 25 | if (set == true) 26 | { 27 | p.Flags |= F; 28 | } 29 | } 30 | public static bool HasParcelPerm(Parcel P, GridClient bot) 31 | { 32 | bool has_perm = true; 33 | if (P.OwnerID != bot.Self.AgentID) 34 | { 35 | if (P.IsGroupOwned) 36 | { 37 | if (bot.Groups.GroupName2KeyCache.ContainsKey(P.GroupID) == true) 38 | { 39 | bot.Groups.ActivateGroup(P.GroupID); 40 | } 41 | else 42 | { 43 | has_perm = false; 44 | } 45 | } 46 | else 47 | { 48 | if(bot.Network.CurrentSim.IsEstateManager == false) 49 | { 50 | has_perm = false; 51 | } 52 | } 53 | } 54 | return has_perm; 55 | 56 | } 57 | public static string[] GetFlagNames() 58 | { 59 | System.Type enumType = typeof(ParcelFlags); 60 | List flagnames = new(System.Enum.GetNames(enumType)); 61 | flagnames.Remove("None"); 62 | return [.. flagnames]; 63 | } 64 | 65 | public static Dictionary GetMediaList() 66 | { 67 | Dictionary flags = new() 68 | { 69 | { "MediaAutoScale", "Bool (True|False)" }, 70 | { "MediaLoop", "Bool (True|False)" }, 71 | { "MediaID", "UUID (Texture)" }, 72 | { "MediaURL", "String" }, 73 | { "MediaDesc", "String" }, 74 | { "MediaHeight", "Int (256 to 1024)" }, 75 | { "MediaWidth", "Int (256 to 1024)" }, 76 | { "MediaType", "String [\"IMG-PNG\",\"IMG-JPG\",\"VID-MP4\",\"VID-AVI\" or \"Custom-MIME_TYPE_CODE\"]" } 77 | }; 78 | return flags; 79 | } 80 | public static Dictionary GetFlagsList() 81 | { 82 | Dictionary flags = []; 83 | Type enumType = typeof(ParcelFlags); 84 | Array enumValues = Enum.GetValues(enumType); 85 | Array enumNames = Enum.GetNames(enumType); 86 | for (int i = 0; i < enumValues.Length; i++) 87 | { 88 | object value = enumValues.GetValue(i); 89 | ParcelFlags realValue = (ParcelFlags)value; 90 | if (realValue != 0) 91 | { 92 | string name = (string)enumNames.GetValue(i); 93 | flags.Add(name, realValue); 94 | } 95 | } 96 | return flags; 97 | } 98 | 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /SecondBotEvents/Static/template.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | [[PAGETITLE]] 7 | 8 | 20 | 21 | 22 |
23 | 48 |
49 | [[CONTENT]] 50 |
51 |
52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /SecondBotEvents/settings.env: -------------------------------------------------------------------------------- 1 | basic_Username=SecondbotR5 2 | basic_Password= --------------------------------------------------------------------------------