├── .gitattributes ├── .github └── workflows │ └── CI.yml ├── .gitignore ├── .moonwave └── static │ └── CNAME ├── .vscode └── settings.json ├── DEVELOPMENT.md ├── LICENSE ├── README.md ├── aftman.toml ├── default.project.json ├── dev.bat ├── dev.project.json ├── dev └── client │ └── ClientLoader.client.luau ├── docs ├── assets │ ├── axislimitcape.gif │ └── flowchart.png ├── bone.md ├── intro.md ├── optimization.md ├── smartbone.md ├── smartcollider.md └── smartweld.md ├── moonwave.toml ├── scripts ├── darkluaconfig.luau └── start-dev.luau ├── selene.toml ├── sourcemap.json ├── src-build ├── Components │ ├── Bone.luau │ ├── BoneTree.luau │ ├── Collision │ │ ├── Collider.luau │ │ ├── ColliderObject.luau │ │ └── Colliders │ │ │ ├── Box.luau │ │ │ ├── Capsule.luau │ │ │ ├── Cylinder.luau │ │ │ ├── Sphere.luau │ │ │ └── Triangle.luau │ └── Constraints │ │ ├── AxisConstraint.luau │ │ ├── AxisConstraint.spec.luau │ │ ├── CollisionConstraint.luau │ │ ├── DistanceConstraint.luau │ │ ├── DistanceContraint.spec.luau │ │ ├── FrictionConstraint.luau │ │ ├── RopeConstraint.luau │ │ ├── RopeConstraint.spec.luau │ │ ├── RotationConstraint.luau │ │ └── SpringConstraint.luau ├── Dependencies │ ├── Config.luau │ ├── Debug │ │ ├── DebugUi.luau │ │ ├── Gizmo │ │ │ ├── Gizmo.luau │ │ │ ├── Gizmos │ │ │ │ ├── Arrow.luau │ │ │ │ ├── Box.luau │ │ │ │ ├── Capsule.luau │ │ │ │ ├── Circle.luau │ │ │ │ ├── Cone.luau │ │ │ │ ├── Cylinder.luau │ │ │ │ ├── Line.luau │ │ │ │ ├── Mesh.luau │ │ │ │ ├── Plane.luau │ │ │ │ ├── Ray.luau │ │ │ │ ├── Sphere.luau │ │ │ │ ├── Text.luau │ │ │ │ ├── VolumeArrow.luau │ │ │ │ ├── VolumeBox.luau │ │ │ │ ├── VolumeCone.luau │ │ │ │ ├── VolumeCylinder.luau │ │ │ │ ├── VolumeSphere.luau │ │ │ │ └── Wedge.luau │ │ │ └── init.luau │ │ └── ImOverlay │ │ │ ├── CeiveImOverlay.luau │ │ │ └── init.luau │ ├── DefaultObjectSettings.luau │ ├── Frustum.luau │ ├── Frustum.spec.luau │ ├── Iris │ │ ├── API.luau │ │ ├── Internal.luau │ │ ├── Types.luau │ │ ├── config.luau │ │ ├── demoWindow.luau │ │ ├── init.luau │ │ └── widgets │ │ │ ├── Button.luau │ │ │ ├── Checkbox.luau │ │ │ ├── Combo.luau │ │ │ ├── Format.luau │ │ │ ├── Input.luau │ │ │ ├── Menu.luau │ │ │ ├── RadioButton.luau │ │ │ ├── Root.luau │ │ │ ├── Table.luau │ │ │ ├── Text.luau │ │ │ ├── Tree.luau │ │ │ ├── Window.luau │ │ │ └── init.luau │ ├── Runtime.client.luau │ └── Utilities.luau └── init.luau ├── src.project.json ├── src ├── Components │ ├── Bone.luau │ ├── BoneTree.luau │ ├── Collision │ │ ├── Collider.luau │ │ ├── ColliderObject.luau │ │ └── Colliders │ │ │ ├── Box.luau │ │ │ ├── Capsule.luau │ │ │ ├── Cylinder.luau │ │ │ ├── Sphere.luau │ │ │ └── Triangle.luau │ └── Constraints │ │ ├── AxisConstraint.luau │ │ ├── AxisConstraint.spec.luau │ │ ├── CollisionConstraint.luau │ │ ├── DistanceConstraint.luau │ │ ├── DistanceContraint.spec.luau │ │ ├── FrictionConstraint.luau │ │ ├── RopeConstraint.luau │ │ ├── RopeConstraint.spec.luau │ │ ├── RotationConstraint.luau │ │ └── SpringConstraint.luau ├── Dependencies │ ├── Config.luau │ ├── Debug │ │ ├── DebugUi.luau │ │ ├── Gizmo │ │ │ ├── Gizmo.luau │ │ │ ├── Gizmos │ │ │ │ ├── Arrow.luau │ │ │ │ ├── Box.luau │ │ │ │ ├── Capsule.luau │ │ │ │ ├── Circle.luau │ │ │ │ ├── Cone.luau │ │ │ │ ├── Cylinder.luau │ │ │ │ ├── Line.luau │ │ │ │ ├── Mesh.luau │ │ │ │ ├── Plane.luau │ │ │ │ ├── Ray.luau │ │ │ │ ├── Sphere.luau │ │ │ │ ├── Text.luau │ │ │ │ ├── VolumeArrow.luau │ │ │ │ ├── VolumeBox.luau │ │ │ │ ├── VolumeCone.luau │ │ │ │ ├── VolumeCylinder.luau │ │ │ │ ├── VolumeSphere.luau │ │ │ │ └── Wedge.luau │ │ │ └── init.luau │ │ └── ImOverlay │ │ │ ├── CeiveImOverlay.luau │ │ │ └── init.luau │ ├── DefaultObjectSettings.luau │ ├── Frustum.luau │ ├── Frustum.spec.luau │ ├── Iris │ │ ├── API.luau │ │ ├── Internal.luau │ │ ├── Types.luau │ │ ├── config.luau │ │ ├── demoWindow.luau │ │ ├── init.luau │ │ └── widgets │ │ │ ├── Button.luau │ │ │ ├── Checkbox.luau │ │ │ ├── Combo.luau │ │ │ ├── Format.luau │ │ │ ├── Input.luau │ │ │ ├── Menu.luau │ │ │ ├── RadioButton.luau │ │ │ ├── Root.luau │ │ │ ├── Table.luau │ │ │ ├── Text.luau │ │ │ ├── Tree.luau │ │ │ ├── Window.luau │ │ │ └── init.luau │ ├── Runtime.client.luau │ └── Utilities.luau └── init.luau ├── stylua.toml ├── testez-companion.toml └── wally.toml /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.github/workflows/CI.yml: -------------------------------------------------------------------------------- 1 | name: Publish To Wally 2 | 3 | on: 4 | release: 5 | types: [published] 6 | 7 | jobs: 8 | 9 | deploy: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - name: Checkout Main 14 | uses: actions/checkout@v3 15 | 16 | - name: Setup Aftman 17 | uses: ok-nick/setup-aftman@v0.4.2 18 | with: 19 | token: ${{ github.token }} 20 | 21 | - name: Install Aftman Toolchains 22 | run: aftman install 23 | 24 | - name: Install Dependencies 25 | run: wally install 26 | 27 | - name: Log in to wally 28 | env: 29 | WALLY_AUTH: ${{ secrets.WALLY_AUTH_TOKEN }} 30 | run: | 31 | mkdir ~/.wally 32 | printenv WALLY_AUTH > ~/.wally/auth.toml 33 | 34 | - name: Push update to wally 35 | run: wally publish 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/* 2 | build 3 | .VSCodeCounter 4 | node_modules 5 | sourcemap.json 6 | package-lock.json 7 | package.json 8 | .darklua.json 9 | -------------------------------------------------------------------------------- /.moonwave/static/CNAME: -------------------------------------------------------------------------------- 1 | smartbone.org 2 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "[lua]": { 3 | "editor.defaultFormatter": "JohnnyMorganz.stylua", 4 | "editor.formatOnSave": true 5 | }, 6 | "[luau]": { 7 | "editor.defaultFormatter": "JohnnyMorganz.stylua", 8 | "editor.formatOnSave": true 9 | }, 10 | "luau-lsp.sourcemap.rojoProjectFile": "src.project.json" 11 | } 12 | -------------------------------------------------------------------------------- /DEVELOPMENT.md: -------------------------------------------------------------------------------- 1 | # SmartBone2 Development 2 | 3 | ## Installing 4 | 5 | If you don't have aftman or npm / nodejs go to these links: 6 | https://github.com/LPGhatguy/aftman/releases/latest 7 | https://nodejs.org/en/download/prebuilt-installer 8 | 9 | Install aftman packages: 10 | `aftman install` 11 | 12 | Install nodemon: 13 | `npm install nodemon` 14 | 15 | ## Building 16 | 17 | Build the darklua config via this: 18 | `lune run build-darkluaconfig` 19 | 20 | You can edit the darklua rules via the `build-darkluaconfig.luau` file. 21 | 22 | Run `dev.bat` and close the terminal when your finished developing. 23 | 24 | You should serve dev.project.json not default.project.json 25 | 26 | If you need debug profiling then change the `DEBUG_PROFILING` variable 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 SmartBone 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SmartBone 2 2 | 3 | ### [Community Server](https://discord.gg/MQEVR6vEwU) 4 | 5 | You can find out more info in the [documentation](https://smartbone.org/docs/intro) 6 | 7 | The wally package can be found [here](https://wally.run/package/jakeywastaken/smartbone-2) 8 | 9 | **Current Features** 10 | 11 | * Support for animating bones 12 | * A more realistic and customizable wind solution 13 | * Support for global wind (MatchWorkspaceWind Attribute) 14 | * A faster, dynamic and more accurate frustum culling solution (The bounding box of all bones is now checked) 15 | * Detailed documentation and API 16 | * Runtime debug ui (Debug Attribute) 17 | * Cleaner code base 18 | * Collision support 19 | * Rotational constraint to limit the rotation between a bone and its parent 20 | * More constraints (Distance, Rope and Spring) 21 | 22 | There is a [demo place](https://www.roblox.com/games/14405998010/Smartbone-2) which has colliders and over 170 SmartBone objects setup. 23 | 24 | If you wish to take the source code directly from the repository then take it from `src-build` as this is the optimized build. 25 | 26 | You can find the plugins here:
27 | [Collider Creator](https://create.roblox.com/marketplace/asset/15539103407/Collider-Creator%3Fkeyword=&pageNumber=&pagePosition=)
28 | [SmartBone Editor](https://create.roblox.com/marketplace/asset/15539148341/SmartBone-Editor%3Fkeyword=&pageNumber=&pagePosition=)
29 | 30 | ## Contributing 31 | 32 | Preferably you follow this [Commit Convention](https://www.conventionalcommits.org/en/v1.0.0/) 33 | And detail your thought process and reasoning in pr's. 34 | You can also find out what is being worked on in the [trello](https://trello.com/b/BN2jeG8L/smartbone-v2) 35 | 36 | ## Issues 37 | 38 | When creating an issue if you can provide a reproduction file or reproduction steps it would be greatly appreciated. 39 | Feature requests via issues are also helpful, a good example of a well structured feature request is [this](https://github.com/smartbone-org/SmartBone-2/issues/16) 40 | -------------------------------------------------------------------------------- /aftman.toml: -------------------------------------------------------------------------------- 1 | # This file lists tools managed by Aftman, a cross-platform toolchain manager. 2 | # For more information, see https://github.com/LPGhatguy/aftman 3 | 4 | # To add a new tool, add an entry to this table. 5 | [tools] 6 | rojo = "rojo-rbx/rojo@7.3.0" 7 | wally = "UpliftGames/wally@0.3.2" 8 | darklua = "seaofvoices/darklua@0.13.0" 9 | lune = "lune-org/lune@0.8.4" 10 | # rojo = "rojo-rbx/rojo@6.2.0" 11 | -------------------------------------------------------------------------------- /default.project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "smartbone-2", 3 | "tree": { 4 | "$path": "src-build" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /dev.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | start /b npx nodemon --watch src -d 1 -e lua,luau --exec "rojo sourcemap src.project.json --output sourcemap.json" 4 | start /b npx nodemon --watch src -e lua,luau --exec "darklua process src/ src-build/" 5 | -------------------------------------------------------------------------------- /dev.project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "SmartBone2", 3 | "tree": { 4 | "$className": "DataModel", 5 | 6 | "ReplicatedStorage": { 7 | "SmartBone": { 8 | "$path": "src-build" 9 | } 10 | }, 11 | 12 | "StarterPlayer": { 13 | "StarterPlayerScripts": { 14 | "$path": "dev/client" 15 | } 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /dev/client/ClientLoader.client.luau: -------------------------------------------------------------------------------- 1 | local ReplicatedStorage = game:GetService("ReplicatedStorage") 2 | local BonePhysics = require(ReplicatedStorage:WaitForChild("SmartBone")) 3 | 4 | BonePhysics.Start() 5 | -------------------------------------------------------------------------------- /docs/assets/axislimitcape.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smartbone-org/SmartBone-2/1ae36f5673cf593bd10ee6701f95b4ea6a6e4f7b/docs/assets/axislimitcape.gif -------------------------------------------------------------------------------- /docs/assets/flowchart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smartbone-org/SmartBone-2/1ae36f5673cf593bd10ee6701f95b4ea6a6e4f7b/docs/assets/flowchart.png -------------------------------------------------------------------------------- /docs/bone.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 5 3 | --- 4 | # Bone 5 | 6 | ### Attributes 7 | 8 | **Attributes which can be set per bone, these aren't required.** 9 | 10 | - \[*Boolean*\] XAxisLocked - If this is true then the bone cannot move on the x axis relative to the root part. 11 | 12 | - \[*Boolean*\] YAxisLocked - If this is true then the bone cannot move on the y axis relative to the root part. 13 | 14 | - \[*Boolean*\] ZAxisLocked - If this is true then the bone cannot move on the z axis relative to the root part. 15 | 16 | - \[*NumberRange*\] XAxisLimits - The limit on which the bone can travel on the x axis relative to the root part, default is -inf, inf. 17 | 18 | - \[*NumberRange*\] YAxisLimits - The limit on which the bone can travel on the y axis relative to the root part, default is -inf, inf. 19 | 20 | - \[*NumberRange*\] ZAxisLimits - The limit on which the bone can travel on the z axis relative to the root part, default is -inf, inf. 21 | 22 | - \[*Number*\] Radius - The radius of the bone, default is 0.25. 23 | 24 | - \[*Number*\] RotationLimit - The maximum rotated offset a bone can be from its parent, default is 180°. 25 | 26 | - \[*Vector3*\] Force - Overrides the force attribute on the root object 27 | 28 | - \[*Vector3*\] Gravity - Overrides the gravity attribute on the root object 29 | -------------------------------------------------------------------------------- /docs/intro.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 1 3 | --- 4 | 5 | # Intro 6 | 7 | ## SmartBone 2 Crash Course 8 | 9 | ***(From now on I'll refer to SmartBone 2 as SmartBone)*** 10 | 11 | There are multiple ways to work with SmartBone, here I will cover the basic side of setting up attributes and using the runtime. 12 | 13 | First of all you need to setup SmartBone! You can find the latest release with a rbxm, rbxl and source code zip [here](https://github.com/CelnakRBLX/SmartBone-2/releases) 14 | 15 | If your using wally you can install via: 16 | `smartbone-2 = "jakeywastaken/smartbone-2@^0.3.0"` 17 | 18 | If you're working in studio you will want to download the rbxm and drag it into your game. If you just want to play around with a demo then open the rbxl file. If you're using rojo or something similar then you can use the source code (.zip) 19 | 20 | ### Basic Setup 21 | 22 | Take the SmartBone module and move it into ReplicatedStorage, and script in StarterPlayerScripts with this as the source: 23 | 24 | ```lua 25 | local SmartBone = require(game:GetService("ReplicatedStorage"):WaitForChild("SmartBone")) 26 | 27 | SmartBone.Start() -- Start the runtime 28 | 29 | --[[ 30 | 31 | You can also do something like this: 32 | 33 | local SmartBoneInstance = SmartBone.Start() 34 | SmartBoneInstance.Stop() -- Removes all actors and resets bones back to rest position. 35 | 36 | ]] 37 | ``` 38 | 39 | This is all you have to do for coding, now we just setup your mesh with the tags and attributes. 40 | 41 | - Select any [MeshPart](https://create.roblox.com/docs/reference/engine/classes/MeshPart) with Bones under it 42 | 43 | - Add the tag “SmartBone” to the [MeshPart](https://create.roblox.com/docs/reference/engine/classes/MeshPart). 44 | 45 | - Add a string attribute called “Roots” to the [MeshPart](https://create.roblox.com/docs/reference/engine/classes/MeshPart) and fill it with the name(s) of the bone(s) you want to be root(s). 46 | 47 | - Separate each [Bone](https://create.roblox.com/docs/reference/engine/classes/MeshPart) name with “,” and the Module will automatically sort your bone(s) into a list. 48 | 49 | - An example of a SmartBone object with multiple roots would have a Roots attribute that looks like this: “Root1,Root2,Root3” 50 | 51 | - Make sure you don’t add any spaces or characters unless they are part of the name of the bone(s) you want to be included 52 | 53 | If you press play your mesh should start simulating, you can change other attributes found [here](smartbone.md). 54 | 55 | ### Axis Limits 56 | 57 | Let's say you've got a cape and you don't want that cape to clip into the character, you can fix that using axis limits! 58 | 59 | Axis limits are a powerful tool useful where setting up colliders would be overkill and a waste of performance. 60 | 61 | You can limit a bone to moving between 0 studs and 5 studs on the x axis relative to the root part using an attribute called "XAxisLimits" of type NumberRange. 62 | 63 | ![](assets/axislimitcape.gif) 64 | (This was running at 60fps but gif compression reduced it to 10fps) 65 | 66 | ### Colliders 67 | 68 | **Note:** If you can use axis limits to achieve the same result, do not use a collider. It would be both a waste of performance and a waste of time to setup! 69 | 70 | Colliders can be setup via a tag with the name "SmartCollider", you can optimize colliders using a collider key, create a string attribute called "ColliderKey" on your root part and your collider. Now only colliders with that collider key can collide with your object. 71 | 72 | You can also manually change the shape of a collider using a string attribute called "ColliderShape" with an option of "Box", "Capsule", "Cylinder" and "Sphere". 73 | 74 | ### Plugins 75 | 76 | The plugins streamline a lot of this process they can be found here: 77 | 78 | - [Collider Creator](https://create.roblox.com/store/asset/15539103407/Collider-Creator) \[Free\] 79 | - [Smartbone Editor](https://create.roblox.com/store/asset/15539148341/SmartBone-Editor) \[150 Robux\] 80 | 81 | ## Update Flow Chart 82 | ![](assets/flowchart.png) 83 | 84 | ## Related Documentation 85 | 86 | [API](/api/) 87 | 88 | [SmartBone Attributes](smartbone.md) 89 | 90 | [SmartCollider Attributes](smartcollider.md) 91 | 92 | [Bone Attributes](bone.md) 93 | -------------------------------------------------------------------------------- /docs/optimization.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 6 3 | --- 4 | # Optimization 5 | 6 | Don't forget you can always use the Debug attribute to open a runtime editor where you can see details on certain things! (Only in studio) 7 | 8 | I think this goes without saying but just because the system is optimized that doesn't mean you can throw in hundreds of objects in close proximity, a lot has been done to try make everything run as fast as possible but it's sadly not black magic. 9 | 10 | ## Root Objects 11 | SmartBone attempts to optimize using root objects with 2 methods, checking if the object is on screen and throttling the update rate. You will want to make sure your root object is the correct size for your mesh if its too small or too big then SmartBone will incorrectly assume its off screen or on screen, throttling update rate is controlled via the attributes: ActivationDistance and ThrottleDistance on the root object. 12 | 13 | ## Bones 14 | You will want to use the minimum amount of bones you can to achieve a pleasing effect, the more bones the longer it will take for SmartBone to update. 15 | 16 | ## Colliders 17 | The time complexity for colliders in the worst case is **O(nm)** where n is the number of active colliders and m is the number of global bones, a few notes: Colliders which aren't a descendant of workspace are not calculated and colliders are only calculated by objects within their sphere of influence. The collider type also contributes, spheres are by far the easiest shape to calculate then box, capsule and cylinder. I doubt it will be a noticeable hit but if your seeing a big performance hit with these then try and optimize your collider use. Don't forget to use collider keys if you have a lot of colliders! 18 | 19 | ## Constraints 20 | Smartbone 2 offers a choice between a Spring, Distance and Rope constraint because of this if you are really short for performance then you can switch to a Distance constraint its calculation is fewer operations compared to the Spring constraint which takes longer to compute (Not that much longer but if you really want to get those microseconds out then go ahead). If you can, then try and use AxisConstraints instead of colliders, since they're local to the bone their time complexity is **O(n)** where n is the number of axis limits maximum of 6. 21 | 22 | ## Wind 23 | If you want an object to have no wind influence, instead of just setting WindInfluence to 0 set the WindType attribute to an empty string, this will bypass all of the wind calculations and could possibly shave off a few ms. 24 | 25 | ## Roblox Issues 26 | If Roblox allowed us to read TransformedWorldCFrame in parallel I'm guessing there could be a performance increase of about 1.5x, if Roblox also added something for BulkPropertySet where you could set any property without firing signals that would also be amazingly beneficial. 27 | -------------------------------------------------------------------------------- /docs/smartbone.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 2 3 | --- 4 | # SmartBone 5 | 6 | ### Setup 7 | 8 | - Select any MeshPart with Bones under it 9 | 10 | - Add the tag “SmartBone” to the MeshPart. 11 | 12 | - Add a string attribute called “Roots” to the MeshPart and fill it with the name(s) of the bone(s) you want to be root(s). 13 | 14 | - Separate each bone name with “,” and the Module will automatically sort your bone(s) into a list. 15 | 16 | - An example of a SmartBone object with multiple roots would have a Roots attribute that looks like this: “Root1,Root2,Root3” 17 | 18 | - Make sure you don’t add any spaces or characters unless they are part of the name of the bone(s) you want to be included 19 | 20 | Note: Re parenting a SmartBone object might cause a lag spike and if you parent to nil and then re-parent the object will no longer have SmartBone acting on it. 21 | This is due to Roblox not adding a .Destroying signal or something similar, if you'd like for the object to continue simulating you would have to remove the SmartBone tag and add it again. 22 | 23 | ### Friction 24 | 25 | Friction is controlled by the root part and the colliding objects physical properties. 26 | 27 | ### Constraints 28 | 29 | Each constraint has it's own purpose, 30 | 31 | - Spring will return the bone to its rest position sort of like jelly 32 | 33 | - Distance will keep the bones at a fixed distance from each other and is always pulled downwards 34 | 35 | - Rope will keep the bones distance between 0 and their rest length and is always pulled downwards 36 | 37 | - Rotation, details can be found [here](bone.md) 38 | 39 | ### Wind 40 | 41 | Wind can be controlled via GlobalWind (MatchWorkspaceWind must be true) or through attributes in Lighting. 42 | 43 | - \[*Number*\] WindStrength - The "density" of the air, this is used regardless of MatchWorkspaceWind. 44 | 45 | - \[*Number*\] WindSpeed - The speed which wind travels at, only important if MatchWorkspaceWind is false. 46 | 47 | - \[*Vector3*\] WindDirection - The direction in which the wind travels, only important if MatchWorkspaceWind is false. 48 | 49 | WindStrength controls the frequency of the wind, 50 | WindSpeed controls the amplitude of the wind, 51 | 52 | For example if you wanted more flowy wind you would have a medium wind speed with a lower wind strength. 53 | 54 | --- 55 | ### Attributes 56 | 57 | **All attributes listed here are optional and not required to get a SmartBone object working.** 58 | 59 | - \[*Any*\] Debug - If this attribute exists in a SmartBone object then the SmartBone Runtime Editor will appear allowing you to change attributes and visualise certain things in real time. 60 | 61 | - \[*Number*\] Damping – How slowed down the calculated motion of the SmartBone(s) will be. 62 | 63 | - \[*Number*\] Stiffness – How much of the bone(s) original CFrame is preserved. 64 | 65 | - \[*Number*\] Inertia – How much the of the movement of the object is ignored. 66 | 67 | - \[*Number*\] Elasticity – How much force is applied to return each bone to its original CFrame. 68 | 69 | - \[*Vector3*\] Gravity – Direction and Magnitude of Gravity in World Space. 70 | 71 | - \[*Vector3*\] Force – Additional Force applied to Bones in World Space. Supplementary to Gravity. 72 | 73 | - \[*String*\] Constraint - Option between Spring, Distance and Rope. 74 | 75 | - \[*String*\] WindType - Option between Sine, Noise and Hybrid. 76 | 77 | - \[*Boolean*\] MatchWorkspaceWind - If true then wind is dependent on workspace.GlobalWind. 78 | 79 | - \[*Number*\] WindInfluence – How much influence wind has on the SmartBone object. 80 | 81 | - \[*String*\] ColliderKey - If this attribute is set then the object will only collide with colliders that have the same collider key. 82 | 83 | - \[*Number*\] AnchorDepth – This will determine how far down in hierarchy from the Root that bones will be Anchored. 84 | 85 | - \[*Boolean*\] AnchorsRotate – If true, the root bone(s) will rotate along with the rest of the bone(s), but remain in static position. If false, the root bone(s) will remain completely static in both Position and Orientation. 86 | 87 | - \[*Number*\] UpdateRate – The rate in frames-per-second at which SmartBone will simulate. 88 | 89 | - \[*Number*\] ActivationDistance – The distance in studs at which the SmartBone stops simulation. 90 | 91 | - \[*Number*\] ThrottleDistance – The distance in studs at which the SmartBone begins to throttle simulation rates based on distance. Scales based on UpdateRate. 92 | -------------------------------------------------------------------------------- /docs/smartcollider.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 3 3 | --- 4 | # SmartCollider 5 | 6 | ### Setup 7 | 8 | - Add the tag "SmartCollider" to any objects that you want to collide with SmartBone objects. 9 | 10 | --- 11 | 12 | **All the attributes here are not required to have a working collider.** 13 | 14 | - \[*String*\] ColliderKey – Used to filter the objects that can collide with this collider, even if this is set any objects which don't have a collider key can collide with this collider as well. 15 | 16 | - \[*String*\] ColliderShape – Defines the shape of the collider, this is done automatically but can be manually specified. Option between Box, Capsule, Cylinder and Sphere 17 | -------------------------------------------------------------------------------- /docs/smartweld.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 4 3 | --- 4 | # SmartWeld 5 | 6 | ### Setup 7 | 8 | - Under any bone create an [ObjectValue](https://create.roblox.com/docs/reference/engine/classes/ObjectValue) called "SmartWeld", set its value to one of the following: [Attachment](https://create.roblox.com/docs/reference/engine/classes/Attachment), [Bone](https://create.roblox.com/docs/reference/engine/classes/Bone) or a [BasePart](https://create.roblox.com/docs/reference/engine/classes/BasePart) 9 | 10 | --- 11 | 12 | **Optional Attributes** 13 | 14 | - \[*Boolean*\] Rigid - If false a spring will be used, if true then the bone will be moved in the direction of the weld point with no smoothing 15 | -------------------------------------------------------------------------------- /moonwave.toml: -------------------------------------------------------------------------------- 1 | gitSourceBranch = "main" # This means we will have to commit and push before building docs 2 | 3 | classOrder = [ 4 | "SmartBone", 5 | "BoneTree", 6 | "Bone", 7 | "ColliderObject", 8 | "Collider" 9 | ] 10 | 11 | [docusaurus] 12 | url = "https://smartbone.org" 13 | baseUrl = "/" 14 | -------------------------------------------------------------------------------- /scripts/darkluaconfig.luau: -------------------------------------------------------------------------------- 1 | --[[ 2 | 3 | Builds .darklua.json run via lune. If you wish to build this into a different json location specify that as a command line arg 4 | 5 | e.g. lune run build-darkluaconfig 6 | e.g. lune run build-darkluaconfig otherconfig.json 7 | 8 | ]] 9 | 10 | -- Globals injected into _G 11 | local DEBUG_PROFILING = false 12 | local MACROS = {} 13 | 14 | local RULES = { 15 | "compute_expression", 16 | "remove_unused_if_branch", 17 | "remove_unused_while", 18 | "remove_nil_declaration", 19 | "filter_after_early_return", 20 | } 21 | 22 | if not DEBUG_PROFILING then 23 | table.insert(RULES, "remove_debug_profiling") 24 | end 25 | 26 | table.insert(RULES, "remove_empty_do") 27 | 28 | local REQUIRE_ALIASES = {} 29 | 30 | -- !! DO NOT EDIT BELOW THIS LINE !! 31 | 32 | local REQUIRE_RULE = 33 | '{"rule": "convert_require", "current": {"name": "path", "sources": {%s}}, "target": {"name": "roblox", "rojo_sourcemap": "sourcemap.json", "indexing_style": "wait_for_child"}}' 34 | local MACRO_RULE = '{"rule": "inject_global_value", "identifier": "%s","value": %s}' 35 | local COMMENT_RULE = "" 36 | 37 | local fs = require("@lune/fs") 38 | local process = require("@lune/process") 39 | 40 | local function Build() 41 | local tout = {} 42 | -- Generate Macros 43 | for MacroName, MacroValue in MACROS do 44 | if type(MacroValue) == "string" then 45 | MacroValue = `"{MacroValue}"` 46 | else 47 | MacroValue = tostring(MacroValue) 48 | end 49 | 50 | table.insert(tout, MACRO_RULE:format(MacroName, MacroValue)) 51 | end 52 | 53 | -- Add in general rules 54 | for _, Rule in RULES do 55 | table.insert(tout, `"{Rule}"`) 56 | end 57 | 58 | -- Add in require rule 59 | local aliases = {} 60 | for alias, location in REQUIRE_ALIASES do 61 | table.insert(aliases, `"{alias}": "{location}"`) 62 | end 63 | 64 | -- Extra rules 65 | table.insert(tout, REQUIRE_RULE:format(table.concat(aliases, ", "))) 66 | table.insert(tout, COMMENT_RULE) 67 | 68 | return `\{"rules": [{table.concat(tout, ", ")}]\}` 69 | end 70 | 71 | local Result = Build() 72 | local WriteTo = process.args[1] or ".darklua.json" 73 | fs.writeFile(WriteTo, Result) 74 | 75 | print(`Successfully build darklua config at "{WriteTo}"`) 76 | -------------------------------------------------------------------------------- /scripts/start-dev.luau: -------------------------------------------------------------------------------- 1 | local fs = require("@lune/fs") 2 | local process = require("@lune/process") 3 | local task = require("@lune/task") 4 | 5 | print("Installing packages") 6 | 7 | process.spawn("rokit", { "install" }, { stdio = "forward" }) 8 | 9 | print("Clearing old build") 10 | 11 | if fs.isDir("./src-build") then 12 | fs.removeDir("./src-build") 13 | end 14 | 15 | print("Building darklua config") 16 | 17 | process.spawn("lune", { "run", "scripts/darkluaconfig" }, { stdio = "forward" }) 18 | 19 | print("Starting darklua watch") 20 | 21 | task.spawn(process.spawn, "./dev.bat", {}, { stdio = "forward" }) 22 | 23 | print("Starting server") 24 | 25 | repeat 26 | task.wait() 27 | until fs.isDir("./src-build") 28 | 29 | task.wait() 30 | 31 | print("Starting rojo") 32 | 33 | process.spawn("rojo", { 34 | "serve", 35 | "dev.project.json", 36 | }, { stdio = "forward" }) 37 | -------------------------------------------------------------------------------- /selene.toml: -------------------------------------------------------------------------------- 1 | std = "roblox+testez" 2 | -------------------------------------------------------------------------------- /src-build/Components/Collision/Colliders/Box.luau: -------------------------------------------------------------------------------- 1 | local function SafeUnit(v3) 2 | if v3.Magnitude == 0 then 3 | return Vector3.zero 4 | end 5 | 6 | return v3.Unit 7 | end 8 | 9 | local function ClosestPointFunc(cframe, size, point) 10 | local rel = cframe:pointToObjectSpace(point) 11 | local sx, sy, sz = size.x, size.y, size.z 12 | local rx, ry, rz = rel.x, rel.y, rel.z 13 | 14 | -- constrain to within the box 15 | local cx = math.clamp(rx, -sx * 0.5, sx * 0.5) 16 | local cy = math.clamp(ry, -sy * 0.5, sy * 0.5) 17 | local cz = math.clamp(rz, -sz * 0.5, sz * 0.5) 18 | 19 | if not (cx == rx and cy == ry and cz == rz) then 20 | local closestPoint = cframe * Vector3.new(cx, cy, cz) 21 | local normal = SafeUnit(point - closestPoint) 22 | return false, closestPoint, normal 23 | end 24 | 25 | -- else, they are intersecting, find the surface the point is closest to 26 | 27 | local posX = rx - sx * 0.5 28 | local posY = ry - sy * 0.5 29 | local posZ = rz - sz * 0.5 30 | local negX = -rx - sx * 0.5 31 | local negY = -ry - sy * 0.5 32 | local negZ = -rz - sz * 0.5 33 | 34 | local max = math.max(posX, posY, posZ, negX, negY, negZ) 35 | if max == posX then 36 | local closestPoint = cframe * Vector3.new(sx * 0.5, ry, rz) 37 | return true, closestPoint, cframe.XVector 38 | elseif max == posY then 39 | local closestPoint = cframe * Vector3.new(rx, sy * 0.5, rz) 40 | return true, closestPoint, cframe.YVector 41 | elseif max == posZ then 42 | local closestPoint = cframe * Vector3.new(rx, ry, sz * 0.5) 43 | return true, closestPoint, cframe.ZVector 44 | elseif max == negX then 45 | local closestPoint = cframe * Vector3.new(-sx * 0.5, ry, rz) 46 | return true, closestPoint, -cframe.XVector 47 | elseif max == negY then 48 | local closestPoint = cframe * Vector3.new(rx, -sy * 0.5, rz) 49 | return true, closestPoint, -cframe.YVector 50 | elseif max == negZ then 51 | local closestPoint = cframe * Vector3.new(rx, ry, -sz * 0.5) 52 | return true, closestPoint, -cframe.ZVector 53 | end 54 | 55 | -- Shouldnt reach 56 | warn("CLOSEST POINT ON BOX FAIL") 57 | return false, cframe.Position, Vector3.zero 58 | end 59 | 60 | return function(BoxCFrame, BoxSize, Point, Radius) -- Sphere vs Box 61 | 62 | local IsInside, ClosestPoint, Normal = ClosestPointFunc(BoxCFrame, BoxSize, Point) 63 | 64 | if IsInside then 65 | return IsInside, ClosestPoint, Normal 66 | end 67 | 68 | local DistanceToCp = (ClosestPoint - Point).Magnitude 69 | 70 | IsInside = (DistanceToCp < Radius) 71 | 72 | return IsInside, ClosestPoint, Normal 73 | end 74 | -------------------------------------------------------------------------------- /src-build/Components/Collision/Colliders/Capsule.luau: -------------------------------------------------------------------------------- 1 | --!native 2 | local function SafeUnit(v3) 3 | if v3.Magnitude == 0 then 4 | return Vector3.zero 5 | end 6 | 7 | return v3.Unit 8 | end 9 | 10 | local function solve(p0, d0, len, p1) 11 | local v = p1 - p0 12 | local k = v:Dot(d0) 13 | k = math.clamp(k, -len, len) 14 | return p0 + d0 * k 15 | end 16 | 17 | local function ClosestPointFunc(cframe, length, radius, point) 18 | local l0 = solve(cframe.Position, cframe.UpVector, length * 0.5, point) 19 | 20 | local distance = (l0 - point).Magnitude 21 | local normal = SafeUnit(point - l0) 22 | local is_inside = (distance <= radius) 23 | 24 | return is_inside, l0 + (normal * radius), normal 25 | end 26 | 27 | return function(CapsuleCFrame, CapsuleSize, Point, Radius) 28 | 29 | local CapsuleRadius = (CapsuleSize.Y < CapsuleSize.Z and CapsuleSize.Y or CapsuleSize.Z) * 0.5 30 | local CapsuleLength = CapsuleSize.X 31 | 32 | CapsuleCFrame *= CFrame.Angles(math.rad(90), -math.rad(90), 0) -- Optomize 33 | 34 | local IsInside, ClosestPoint, Normal = ClosestPointFunc(CapsuleCFrame, CapsuleLength, CapsuleRadius, Point) 35 | 36 | if IsInside then 37 | return IsInside, ClosestPoint, Normal 38 | end 39 | 40 | local DistanceToCp = (ClosestPoint - Point).Magnitude 41 | 42 | IsInside = (DistanceToCp < Radius) 43 | 44 | return IsInside, ClosestPoint, Normal 45 | end 46 | -------------------------------------------------------------------------------- /src-build/Components/Collision/Colliders/Cylinder.luau: -------------------------------------------------------------------------------- 1 | --!native 2 | local function SafeUnit(v3) 3 | if v3.Magnitude == 0 then 4 | return Vector3.zero 5 | end 6 | 7 | return v3.Unit 8 | end 9 | 10 | local function solve(p0, d0, len, p1) 11 | local v = p1 - p0 12 | local k = v:Dot(d0) 13 | k = math.clamp(k, -len, len) 14 | return p0 + d0 * k, k 15 | end 16 | 17 | local function ProjectOnPlane(pos, normal, point) 18 | local d = point - pos 19 | local v_dot = d:Dot(normal) 20 | local v = point - v_dot * normal 21 | 22 | return v 23 | end 24 | 25 | local function ClosestPointFunc(cframe, size, point) 26 | local radius = (size.Y < size.Z and size.Y or size.Z) * 0.5 27 | local length = size.X * 0.5 28 | local l0, k = solve(cframe.Position, cframe.RightVector, length, point) 29 | 30 | local endPlane = cframe.Position + -cframe.RightVector * length 31 | local topPlane = cframe.Position + cframe.RightVector * length 32 | 33 | local endPlaneN = -cframe.RightVector 34 | local topPlaneN = cframe.RightVector 35 | 36 | local projEnd = ProjectOnPlane(endPlane, endPlaneN, point) 37 | local projTop = ProjectOnPlane(topPlane, topPlaneN, point) 38 | 39 | local function GetFinalProj(proj, o) 40 | local projDir = SafeUnit(proj - o) 41 | local projDistance = (proj - o).Magnitude 42 | return o + projDir * (projDistance < radius and projDistance or radius) 43 | end 44 | 45 | projEnd = GetFinalProj(projEnd, endPlane) 46 | projTop = GetFinalProj(projTop, topPlane) 47 | 48 | local radiusDistance = (l0 - point).Magnitude 49 | local radiusNormal = SafeUnit(point - l0) 50 | local radiusInside = (radiusDistance <= radius) 51 | local radiusPosition = l0 + (radiusNormal * radius) 52 | 53 | local d0 = (projTop - point).Magnitude 54 | local d1 = (projEnd - point).Magnitude 55 | local d2 = (radiusPosition - point).Magnitude 56 | 57 | local d = math.min(d0, d1, d2) 58 | 59 | if k == length or d == d0 then 60 | local dot = SafeUnit(point - projTop):Dot(topPlaneN) 61 | return dot < 0, projTop, topPlaneN 62 | elseif k == -length or d == d1 then 63 | local dot = SafeUnit(point - projEnd):Dot(endPlaneN) 64 | return dot < 0, projEnd, endPlaneN 65 | end 66 | 67 | return radiusInside, radiusPosition, radiusNormal 68 | end 69 | 70 | return function(CylinderCFrame, CylinderSize, Point, Radius) -- IsInside, PushPosition, PushNormal 71 | 72 | local IsInside, PushPosition, PushNormal = ClosestPointFunc(CylinderCFrame, CylinderSize, Point) 73 | 74 | if IsInside then 75 | return IsInside, PushPosition, PushNormal 76 | end 77 | 78 | local PointDistance = (PushPosition - Point).Magnitude 79 | 80 | IsInside = PointDistance < Radius 81 | 82 | return IsInside, PushPosition, PushNormal 83 | end 84 | -------------------------------------------------------------------------------- /src-build/Components/Collision/Colliders/Sphere.luau: -------------------------------------------------------------------------------- 1 | --!native 2 | local function SafeUnit(v3) 3 | if v3.Magnitude == 0 then 4 | return Vector3.zero 5 | end 6 | 7 | return v3.Unit 8 | end 9 | 10 | local function ClosestPointFunc(position, radius, point) 11 | local distance = (position - point).Magnitude 12 | local normal = SafeUnit(point - position) 13 | local is_inside = (distance <= radius) 14 | 15 | return is_inside, position + (normal * radius), normal 16 | end 17 | 18 | return function(Sphere0Point, Sphere0Radius, Sphere1Point, Sphere1Radius) 19 | 20 | Sphere0Point = Sphere0Point.Position 21 | Sphere0Radius = math.min(Sphere0Radius.X, Sphere0Radius.Y, Sphere0Radius.Z) * 0.5 22 | 23 | local IsInside, ClosestPoint, Normal = ClosestPointFunc(Sphere0Point, Sphere0Radius, Sphere1Point) 24 | 25 | if IsInside then 26 | return IsInside, ClosestPoint, Normal 27 | end 28 | 29 | local DistanceToCp = (ClosestPoint - Sphere1Point).Magnitude 30 | 31 | IsInside = (DistanceToCp < Sphere1Radius) 32 | 33 | return IsInside, ClosestPoint, Normal 34 | end 35 | -------------------------------------------------------------------------------- /src-build/Components/Collision/Colliders/Triangle.luau: -------------------------------------------------------------------------------- 1 | --[[ 2 | 3 | !! THIS IS NOT MEANT TO BE USED AS A COLLIDER SOLVER, ITS MEANT TO BE USED IN OTHER COLLIDER SOLVERS !! 4 | 5 | ]] 6 | 7 | --!native 8 | local dot = Vector3.new().Dot 9 | local cross = Vector3.new().Cross 10 | local clamp = math.clamp 11 | 12 | local function SafeUnit(v3) 13 | if v3.Magnitude == 0 then 14 | return Vector3.zero 15 | end 16 | 17 | return v3.Unit 18 | end 19 | 20 | local function ClosestPointOnLineSegment(A, B, P) 21 | local AB = B - A 22 | local t = dot(P - A, AB) / dot(AB, AB) 23 | return A + clamp(t, 0, 1) * AB 24 | end 25 | 26 | local function ProjectOnPlane(pos, normal, point) 27 | local d = point - pos 28 | local v_dot = d:Dot(normal) 29 | local v = point - v_dot * normal 30 | 31 | return v 32 | end 33 | 34 | local function SameSide(p1, p2, a, b) 35 | local cp1 = cross(b - a, p1 - a) 36 | local cp2 = cross(b - a, p2 - a) 37 | if dot(cp1, cp2) >= 0 then 38 | return true 39 | else 40 | return false 41 | end 42 | end 43 | 44 | local function PointInTriangle(p, a, b, c) 45 | if SameSide(p, a, b, c) and SameSide(p, b, a, c) and SameSide(p, c, a, b) then 46 | return true 47 | end 48 | 49 | return false 50 | end 51 | 52 | local function ClosestPointOnTri(v0, v1, v2, point) -- ClosestPoint, Normal 53 | 54 | local Edge0 = ClosestPointOnLineSegment(v0, v1, point) 55 | local Edge1 = ClosestPointOnLineSegment(v1, v2, point) 56 | local Edge2 = ClosestPointOnLineSegment(v2, v0, point) 57 | 58 | local Normal = SafeUnit(cross(v1 - v0, v2 - v0)) 59 | local Center = (v0 + v1 + v2) * 0.3333 60 | local Projected = ProjectOnPlane(Center, Normal, point) 61 | 62 | if PointInTriangle(point, v0, v1, v2) then 63 | 64 | return Projected, Normal 65 | end 66 | 67 | local d0 = (Edge0 - point).Magnitude 68 | local d1 = (Edge1 - point).Magnitude 69 | local d2 = (Edge2 - point).Magnitude 70 | 71 | local d = math.min(d0, d1, d2) 72 | 73 | if d == d0 then 74 | 75 | return Edge0, Normal 76 | elseif d == d1 then 77 | 78 | return Edge1, Normal 79 | elseif d == d2 then 80 | 81 | return Edge2, Normal 82 | end 83 | 84 | 85 | return point, Normal 86 | end 87 | 88 | return ClosestPointOnTri 89 | -------------------------------------------------------------------------------- /src-build/Components/Constraints/AxisConstraint.luau: -------------------------------------------------------------------------------- 1 | local function SafeUnit(v3) 2 | if v3.Magnitude == 0 then 3 | return Vector3.zero 4 | end 5 | 6 | return v3.Unit 7 | end 8 | 9 | local inf = math.huge 10 | 11 | return function(self, Position, LastPosition, RootCFrame) 12 | 13 | local RootOffset = RootCFrame:Inverse() * Position 14 | 15 | local X = RootOffset.X 16 | local Y = RootOffset.Y 17 | local Z = RootOffset.Z 18 | 19 | local XLimit = self.XAxisLimits 20 | local YLimit = self.YAxisLimits 21 | local ZLimit = self.ZAxisLimits 22 | 23 | local XLock = self.AxisLocked[1] and 0 or 1 24 | local YLock = self.AxisLocked[2] and 0 or 1 25 | local ZLock = self.AxisLocked[3] and 0 or 1 26 | 27 | -- Most bones probably wont have an axis limit, this allows us to skip all the other stuff 28 | if XLimit.Min == -inf and XLimit.Max == inf and YLimit.Min == -inf and YLimit.Max == inf and ZLimit.Min == -inf and ZLimit.Max == inf then 29 | if XLock == 1 and YLock == 1 and ZLock == 1 then 30 | 31 | return Position 32 | else 33 | return RootCFrame * Vector3.new(X * XLock, Y * YLock, Z * ZLock) 34 | end 35 | end 36 | 37 | -- If our radius is > than the diff between min and max 38 | -- We do this because its faster than math.min() ¯\_(ツ)_/¯ 39 | local XMin = XLimit.Min + self.Radius 40 | local XMax = XMin <= (XLimit.Max - self.Radius) and XLimit.Max - self.Radius or XMin 41 | 42 | local YMin = YLimit.Min + self.Radius 43 | local YMax = YMin <= (YLimit.Max - self.Radius) and YLimit.Max - self.Radius or YMin 44 | 45 | local ZMin = ZLimit.Min + self.Radius 46 | local ZMax = ZMin <= (ZLimit.Max - self.Radius) and ZLimit.Max - self.Radius or ZMin 47 | 48 | X = X < XMin and XMin or (X > XMax and XMax or X) 49 | Y = Y < YMin and YMin or (Y > YMax and YMax or Y) 50 | Z = Z < ZMin and ZMin or (Z > ZMax and ZMax or Z) 51 | 52 | X *= XLock 53 | Y *= YLock 54 | Z *= ZLock 55 | 56 | local WorldSpace = RootCFrame * Vector3.new(X, Y, Z) 57 | 58 | Position = WorldSpace 59 | 60 | local XAxis = RootCFrame.RightVector 61 | local YAxis = RootCFrame.UpVector 62 | local ZAxis = RootCFrame.LookVector 63 | 64 | local DifferenceDirection = SafeUnit(Position - LastPosition) 65 | 66 | -- Remove our velocity on the vectors we collided with, stops any weird jittering. 67 | if X ~= RootOffset.X then 68 | local Normal = XAxis:Dot(DifferenceDirection) < 0 and -XAxis or XAxis 69 | self:ClipVelocity(Position, Normal) 70 | end 71 | 72 | if Y ~= RootOffset.Y then 73 | local Normal = YAxis:Dot(DifferenceDirection) < 0 and -YAxis or YAxis 74 | self:ClipVelocity(Position, Normal) 75 | end 76 | 77 | if Z ~= RootOffset.Z then 78 | local Normal = ZAxis:Dot(DifferenceDirection) > 0 and -ZAxis or ZAxis 79 | self:ClipVelocity(Position, Normal) 80 | end 81 | 82 | 83 | return Position 84 | end 85 | -------------------------------------------------------------------------------- /src-build/Components/Constraints/AxisConstraint.spec.luau: -------------------------------------------------------------------------------- 1 | local AxisConstraint = require(script.Parent:WaitForChild("AxisConstraint")) 2 | 3 | return function() 4 | local Bone = { 5 | Radius = 0, 6 | XAxisLimits = NumberRange.new(-math.huge, math.huge), 7 | YAxisLimits = NumberRange.new(-math.huge, math.huge), 8 | ZAxisLimits = NumberRange.new(-math.huge, math.huge), 9 | AxisLocked = { false, false, false }, 10 | ClipVelocity = function() end, 11 | } 12 | 13 | afterEach(function() 14 | Bone.AxisLocked = { false, false, false } 15 | end) 16 | 17 | describe("Axis Lock", function() 18 | it("Should lock X Axis", function() 19 | Bone.AxisLocked = { true, false, false } 20 | 21 | local Result = AxisConstraint(Bone, Vector3.new(-10, 0, 0), Vector3.zero, CFrame.identity) 22 | 23 | expect(Result.X).to.equal(0) 24 | end) 25 | 26 | it("Should lock Y Axis", function() 27 | Bone.AxisLocked = { false, true, false } 28 | 29 | local Result = AxisConstraint(Bone, Vector3.new(0, -10, 0), Vector3.zero, CFrame.identity) 30 | 31 | expect(Result.Y).to.equal(0) 32 | end) 33 | 34 | it("Should lock Z Axis", function() 35 | Bone.AxisLocked = { false, false, true } 36 | 37 | local Result = AxisConstraint(Bone, Vector3.new(0, 0, -10), Vector3.zero, CFrame.identity) 38 | 39 | expect(Result.Z).to.equal(0) 40 | end) 41 | end) 42 | 43 | describe("Axis Limit", function() 44 | describe("Should limit X Axis", function() 45 | it("Min Limit", function() 46 | Bone.XAxisLimits = NumberRange.new(-5, math.huge) 47 | 48 | local Result = AxisConstraint(Bone, Vector3.new(-10, 0, 0), Vector3.zero, CFrame.identity) 49 | 50 | expect(Result.X).to.equal(-5) 51 | end) 52 | 53 | it("Max Limit", function() 54 | Bone.XAxisLimits = NumberRange.new(-math.huge, 5) 55 | 56 | local Result = AxisConstraint(Bone, Vector3.new(10, 0, 0), Vector3.zero, CFrame.identity) 57 | 58 | expect(Result.X).to.equal(5) 59 | end) 60 | end) 61 | 62 | describe("Should limit Y Axis", function() 63 | it("Min Limit", function() 64 | Bone.YAxisLimits = NumberRange.new(-5, math.huge) 65 | 66 | local Result = AxisConstraint(Bone, Vector3.new(0, -10, 0), Vector3.zero, CFrame.identity) 67 | 68 | expect(Result.Y).to.equal(-5) 69 | end) 70 | 71 | it("Max Limit", function() 72 | Bone.YAxisLimits = NumberRange.new(-math.huge, 5) 73 | 74 | local Result = AxisConstraint(Bone, Vector3.new(0, 10, 0), Vector3.zero, CFrame.identity) 75 | 76 | expect(Result.Y).to.equal(5) 77 | end) 78 | end) 79 | 80 | describe("Should limit Z Axis", function() 81 | it("Min Limit", function() 82 | Bone.ZAxisLimits = NumberRange.new(-5, math.huge) 83 | 84 | local Result = AxisConstraint(Bone, Vector3.new(0, 0, -10), Vector3.zero, CFrame.identity) 85 | 86 | expect(Result.Z).to.equal(-5) 87 | end) 88 | 89 | it("Max Limit", function() 90 | Bone.ZAxisLimits = NumberRange.new(-math.huge, 5) 91 | 92 | local Result = AxisConstraint(Bone, Vector3.new(0, 0, 10), Vector3.zero, CFrame.identity) 93 | 94 | expect(Result.Z).to.equal(5) 95 | end) 96 | end) 97 | end) 98 | end 99 | -------------------------------------------------------------------------------- /src-build/Components/Constraints/CollisionConstraint.luau: -------------------------------------------------------------------------------- 1 | return function(self, Position, Colliders) 2 | 3 | local Collisions = {} 4 | local HitParts = {} 5 | 6 | for _, Collider in Colliders do 7 | local ColliderCollisions = Collider:GetCollisions(Position, self.Radius) 8 | 9 | if #ColliderCollisions > 0 then 10 | table.insert(HitParts, Collider:GetObject()) 11 | end 12 | 13 | for _, Collision in ColliderCollisions do 14 | table.insert(Collisions, Collision) 15 | end 16 | end 17 | 18 | for _, Collision in Collisions do 19 | Position = Collision.ClosestPoint + (Collision.Normal * self.Radius) 20 | -- self:ClipVelocity(Position, Collision.Normal) -- This causes some weird glitching issues, not sure why tbh 21 | end 22 | 23 | self.CollisionsData = Collisions 24 | self.CollisionHits = HitParts 25 | 26 | 27 | return Position 28 | end 29 | -------------------------------------------------------------------------------- /src-build/Components/Constraints/DistanceConstraint.luau: -------------------------------------------------------------------------------- 1 | local function SafeUnit(v3) 2 | if v3.Magnitude == 0 then 3 | return Vector3.zero 4 | end 5 | 6 | return v3.Unit 7 | end 8 | 9 | return function(self, Position, BoneTree) 10 | 11 | local ParentBone = BoneTree.Bones[self.ParentIndex] 12 | 13 | if ParentBone then 14 | local RestLength = self.FreeLength 15 | local BoneDirection = SafeUnit(Position - ParentBone.Position) 16 | 17 | local RestPosition = ParentBone.Position + (BoneDirection * RestLength) 18 | 19 | 20 | return RestPosition 21 | end 22 | 23 | 24 | return 25 | end 26 | -------------------------------------------------------------------------------- /src-build/Components/Constraints/DistanceContraint.spec.luau: -------------------------------------------------------------------------------- 1 | local DistanceConstraint = require(script.Parent:WaitForChild("DistanceConstraint")) 2 | 3 | local function CreateBone(Position, FreeLength, Parent) 4 | return { 5 | Position = Position, 6 | FreeLength = FreeLength, 7 | ParentIndex = Parent, 8 | } 9 | end 10 | 11 | return function() 12 | local BoneTree = { 13 | Bones = { 14 | CreateBone(Vector3.zero, 3, 0), 15 | CreateBone(Vector3.yAxis, 3, 1), 16 | }, 17 | } 18 | 19 | describe("Distance Constraint", function() 20 | local Bone = BoneTree.Bones[2] 21 | 22 | local function Callback() 23 | local NewPosition = DistanceConstraint(Bone, Bone.Position, BoneTree) 24 | 25 | expect(NewPosition.Magnitude).to.equal(Bone.FreeLength) 26 | 27 | Bone.Position = NewPosition 28 | end 29 | 30 | for i = 1, 10 do 31 | it(`Should limit to {Bone.FreeLength} studs #{i}`, Callback) 32 | Bone.FreeLength = math.random(1, 20) 33 | end 34 | end) 35 | end 36 | -------------------------------------------------------------------------------- /src-build/Components/Constraints/FrictionConstraint.luau: -------------------------------------------------------------------------------- 1 | return function(self, Position, LastPosition) 2 | local Alpha = 1 - self.Friction 3 | 4 | return LastPosition:Lerp(Position, Alpha) 5 | end 6 | -------------------------------------------------------------------------------- /src-build/Components/Constraints/RopeConstraint.luau: -------------------------------------------------------------------------------- 1 | local function SafeUnit(v3) 2 | if v3.Magnitude == 0 then 3 | return Vector3.zero 4 | end 5 | 6 | return v3.Unit 7 | end 8 | 9 | return function(self, Position, BoneTree) 10 | 11 | local ParentBone = BoneTree.Bones[self.ParentIndex] 12 | 13 | if ParentBone then 14 | local RestLength = self.FreeLength 15 | local BoneSub = (Position - ParentBone.Position) 16 | local BoneDirection = SafeUnit(BoneSub) 17 | local BoneDistance = BoneSub.Magnitude < RestLength and BoneSub.Magnitude or RestLength 18 | 19 | local RestPosition = ParentBone.Position + (BoneDirection * BoneDistance) 20 | 21 | 22 | return RestPosition 23 | end 24 | 25 | 26 | return 27 | end 28 | -------------------------------------------------------------------------------- /src-build/Components/Constraints/RopeConstraint.spec.luau: -------------------------------------------------------------------------------- 1 | local RopeConstraint = require(script.Parent:WaitForChild("RopeConstraint")) 2 | 3 | local function CreateBone(Position, FreeLength, Parent) 4 | return { 5 | Position = Position, 6 | FreeLength = FreeLength, 7 | ParentIndex = Parent, 8 | } 9 | end 10 | 11 | return function() 12 | local BoneTree = { 13 | Bones = { 14 | CreateBone(Vector3.zero, 3, 0), 15 | CreateBone(Vector3.yAxis * 10, 3, 1), 16 | }, 17 | } 18 | 19 | describe("Rope Constraint", function() 20 | local Bone = BoneTree.Bones[2] 21 | local i = 0 22 | 23 | local ReRun 24 | 25 | local function LimitCallback() 26 | local NewPosition = RopeConstraint(Bone, Bone.Position, BoneTree) 27 | 28 | expect(NewPosition.Magnitude).to.equal(Bone.FreeLength) 29 | 30 | Bone.FreeLength = math.random(1, 20) 31 | 32 | ReRun() 33 | end 34 | 35 | local function SameCallback() 36 | local NewPosition = RopeConstraint(Bone, Bone.Position, BoneTree) 37 | 38 | expect(NewPosition.Magnitude).to.equal(Bone.Position.Magnitude) 39 | 40 | Bone.FreeLength = math.random(1, 20) 41 | 42 | ReRun() 43 | end 44 | 45 | ReRun = function() 46 | if i >= 10 then 47 | return 48 | end 49 | 50 | i += 1 51 | 52 | if Bone.Position.Magnitude < Bone.FreeLength then 53 | it(`Should stay the same #{i}`, SameCallback) 54 | else 55 | it(`Should limit to {Bone.FreeLength} studs #{i}`, LimitCallback) 56 | end 57 | end 58 | 59 | ReRun() 60 | end) 61 | end 62 | -------------------------------------------------------------------------------- /src-build/Components/Constraints/RotationConstraint.luau: -------------------------------------------------------------------------------- 1 | local function SafeUnit(v3) 2 | if v3.Magnitude == 0 then 3 | return Vector3.zero 4 | end 5 | 6 | return v3.Unit 7 | end 8 | 9 | return function(self, Position, BoneTree) 10 | 11 | local ParentIndex = self.ParentIndex 12 | local ParentBone = BoneTree.Bones[ParentIndex] 13 | 14 | if not ParentBone then 15 | 16 | return Position 17 | end 18 | 19 | local ParentBoneLimit = ParentBone.RotationLimit 20 | 21 | if ParentBoneLimit >= 180 then 22 | 23 | return Position 24 | end 25 | 26 | local GrandParentBone = BoneTree.Bones[ParentBone.ParentIndex] 27 | 28 | if not GrandParentBone then 29 | 30 | return Position 31 | end 32 | 33 | local ParentBonePosition = ParentBone.Position 34 | local DefaultDirection = SafeUnit(ParentBone.Position - GrandParentBone.Position) 35 | 36 | local DistanceToParent = (Position - ParentBonePosition).Magnitude 37 | local DirectionToSelf = SafeUnit(Position - ParentBonePosition) 38 | 39 | if ParentBoneLimit <= 0 then 40 | 41 | return ParentBonePosition + DefaultDirection * DistanceToParent 42 | end 43 | 44 | local RotationLimit = math.rad(self.RotationLimit) 45 | local VectorAngle = math.acos(DefaultDirection:Dot(DirectionToSelf)) 46 | local LimitedVector 47 | 48 | if VectorAngle >= RotationLimit then 49 | local Cross = SafeUnit(DefaultDirection:Cross(DirectionToSelf)) 50 | LimitedVector = CFrame.fromAxisAngle(Cross, RotationLimit) * DefaultDirection 51 | else 52 | LimitedVector = DirectionToSelf 53 | end 54 | 55 | if LimitedVector ~= LimitedVector then -- Somewhat hacky fix 56 | LimitedVector = DefaultDirection 57 | end 58 | 59 | Position = ParentBonePosition + LimitedVector * DistanceToParent 60 | 61 | 62 | return Position 63 | end 64 | -------------------------------------------------------------------------------- /src-build/Components/Constraints/SpringConstraint.luau: -------------------------------------------------------------------------------- 1 | --!native 2 | return function(self, Position, RestPosition, BoneTree, Delta) 3 | 4 | 5 | local Settings = BoneTree.Settings 6 | local Stiffness = Settings.Stiffness 7 | local Elasticity = Settings.Elasticity 8 | 9 | local ParentBone = BoneTree.Bones[self.ParentIndex] 10 | 11 | if ParentBone then 12 | local RestLength = self.FreeLength 13 | 14 | if Stiffness > 0 or Elasticity > 0 then 15 | local ParentBoneCFrame = CFrame.new(ParentBone.Position) * ParentBone.TransformOffset.Rotation 16 | RestPosition = RestPosition or (ParentBoneCFrame * CFrame.new(self.LocalTransformOffset.Position)).Position 17 | 18 | local ElasticDifference = RestPosition - Position 19 | Position += ElasticDifference * (Elasticity * Delta) 20 | 21 | if Stiffness > 0 then 22 | local StiffDifference = RestPosition - Position 23 | local Length = StiffDifference.Magnitude 24 | local MaxLength = RestLength * (1 - Stiffness) * 2 25 | if Length > MaxLength then 26 | Position += StiffDifference * ((Length - MaxLength) / Length) 27 | end 28 | end 29 | end 30 | 31 | local Difference = ParentBone.Position - Position 32 | local Length = Difference.Magnitude 33 | if Length > 0 then 34 | Position += Difference * ((Length - RestLength) / Length) 35 | end 36 | end 37 | 38 | 39 | return Position 40 | end 41 | -------------------------------------------------------------------------------- /src-build/Dependencies/Config.luau: -------------------------------------------------------------------------------- 1 | -- Configuration 2 | 3 | return { 4 | VERSION = "0.5.0", 5 | -- Controls if when an object is out of activation distance / fov if its bones should be sent back to their rest location. 6 | RESET_TRANSFORM_ON_SKIP = true, 7 | -- Wouldn't recommend enabling, controls if we should wait after each collider setup. 8 | YIELD_ON_COLLIDER_GATHER = false, 9 | -- Allows for debug tools out of studio 10 | ALLOW_LIVE_GAME_DEBUG = false, 11 | -- Maximum distance for field of view checks, if an object is out of this distance its skipped regardless of activation distance. 12 | FAR_PLANE = 500, 13 | -- Frequency of which we do frustum checks, 1 being every frame, 2 being every other frame, 3 being every 3rd frame and so on. 14 | FRUSTUM_FREQ = 2, 15 | -- Debug info in output, can lag the game. 16 | LOG_VERBOSE = false, 17 | -- Controls if we should reset bone positions when .Stop() is called 18 | RESET_BONE_ON_DESTROY = true, 19 | -- Enable or disable the startup print 20 | STARTUP_PRINT_ENABLED = true, 21 | -- Overlay config, not meant for end users 22 | DEBUG_OVERLAY_ENABLED = false, -- enable or disable when debug is enabled 23 | DEBUG_OVERLAY_TREE = true, -- enable tree debug 24 | DEBUG_OVERLAY_TREE_INFO = false, 25 | DEBUG_OVERLAY_TREE_OBJECTS = false, 26 | DEBUG_OVERLAY_TREE_NUMERICS = false, 27 | DEBUG_OVERLAY_TREE_OFFSET = 0, -- how offset into the roots we should be 28 | DEBUG_OVERLAY_MAX_TREES = 5, -- -1 for no max 29 | DEBUG_OVERLAY_BONE = true, -- enable bone debug info 30 | DEBUG_OVERLAY_BONE_OFFSET = 0, -- how offset into the bone tree we should be 31 | DEBUG_OVERLAY_MAX_BONES = -1, -- -1 for no max 32 | DEBUG_OVERLAY_BONE_INFO = false, 33 | DEBUG_OVERLAY_BONE_NUMERICS = false, 34 | DEBUG_OVERLAY_BONE_CONSTRAIN = false, 35 | DEBUG_OVERLAY_BONE_WELD = true, 36 | DEBUG_OVERLAY_BONE_FORCES = true, 37 | } 38 | -------------------------------------------------------------------------------- /src-build/Dependencies/Debug/Gizmo/Gizmos/Arrow.luau: -------------------------------------------------------------------------------- 1 | local Gizmo = {} 2 | Gizmo.__index = Gizmo 3 | 4 | function Gizmo.Init(Ceive, Propertys, Request, Release, Retain) 5 | local self = setmetatable({}, Gizmo) 6 | 7 | self.Ceive = Ceive 8 | self.Propertys = Propertys 9 | self.Request = Request 10 | self.Release = Release 11 | self.Retain = Retain 12 | 13 | return self 14 | end 15 | 16 | function Gizmo:Draw(Origin: Vector3, End: Vector3, Radius: number, Length: number, Subdivisions: number) 17 | local Ceive = self.Ceive 18 | 19 | if not Ceive.Enabled then 20 | return 21 | end 22 | 23 | Ceive.Ray:Draw(Origin, End) 24 | 25 | local ArrowCFrame = CFrame.lookAt(End + ((Origin - End).Unit * (Length * 0.5)), End) 26 | Ceive.Cone:Draw(ArrowCFrame, Radius, Length, Subdivisions) 27 | end 28 | 29 | function Gizmo:Create(Origin: Vector3, End: Vector3, Radius: number, Length: number, Subdivisions: number) 30 | local PropertyTable = { 31 | Origin = Origin, 32 | End = End, 33 | Radius = Radius, 34 | Length = Length, 35 | Subdivisions = Subdivisions, 36 | AlwaysOnTop = self.Propertys.AlwaysOnTop, 37 | Transparency = self.Propertys.Transparency, 38 | Color3 = self.Propertys.Color3, 39 | Enabled = true, 40 | Destroy = false, 41 | } 42 | 43 | self.Retain(self, PropertyTable) 44 | 45 | return PropertyTable 46 | end 47 | 48 | function Gizmo:Update(PropertyTable) 49 | local Ceive = self.Ceive 50 | 51 | Ceive.PushProperty("AlwaysOnTop", PropertyTable.AlwaysOnTop) 52 | Ceive.PushProperty("Transparency", PropertyTable.Transparency) 53 | Ceive.PushProperty("Color3", PropertyTable.Color3) 54 | 55 | self:Draw(PropertyTable.Origin, PropertyTable.End, PropertyTable.Radius, PropertyTable.Length, PropertyTable.Subdivisions) 56 | end 57 | 58 | return Gizmo 59 | -------------------------------------------------------------------------------- /src-build/Dependencies/Debug/Gizmo/Gizmos/Box.luau: -------------------------------------------------------------------------------- 1 | local Gizmo = {} 2 | Gizmo.__index = Gizmo 3 | 4 | function Gizmo.Init(Ceive, Propertys, Request, Release, Retain) 5 | local self = setmetatable({}, Gizmo) 6 | 7 | self.Ceive = Ceive 8 | self.Propertys = Propertys 9 | self.Request = Request 10 | self.Release = Release 11 | self.Retain = Retain 12 | 13 | return self 14 | end 15 | 16 | function Gizmo:Draw(Transform: CFrame, Size: Vector3, DrawTriangles: boolean) 17 | local Ceive = self.Ceive 18 | 19 | if not Ceive.Enabled then 20 | return 21 | end 22 | 23 | local Position = Transform.Position 24 | local Uv = Transform.UpVector 25 | local Rv = Transform.RightVector 26 | local Lv = Transform.LookVector 27 | local sO2 = Size * 0.5 28 | local sUv = Uv * sO2.Y 29 | local sRv = Rv * sO2.X 30 | local sLv = Lv * sO2.Z 31 | 32 | local function CalculateYFace(lUv, lRv, lLv) 33 | local TopLeft = Position + (lUv - lRv + lLv) 34 | local TopRight = Position + (lUv + lRv + lLv) 35 | local BottomLeft = Position + (lUv - lRv - lLv) 36 | local BottomRight = Position + (lUv + lRv - lLv) 37 | 38 | Ceive.Ray:Draw(TopLeft, TopRight) 39 | Ceive.Ray:Draw(TopLeft, BottomLeft) 40 | 41 | Ceive.Ray:Draw(TopRight, BottomRight) 42 | if DrawTriangles ~= false then 43 | Ceive.Ray:Draw(TopRight, BottomLeft) 44 | end 45 | 46 | Ceive.Ray:Draw(BottomLeft, BottomRight) 47 | end 48 | 49 | local function CalculateZFace(lUv, lRv, lLv) 50 | local TopLeft = Position + (lUv - lRv + lLv) 51 | local TopRight = Position + (lUv + lRv + lLv) 52 | local BottomLeft = Position + (-lUv - lRv + lLv) 53 | local BottomRight = Position + (-lUv + lRv + lLv) 54 | 55 | Ceive.Ray:Draw(TopLeft, TopRight) 56 | Ceive.Ray:Draw(TopLeft, BottomLeft) 57 | 58 | Ceive.Ray:Draw(TopRight, BottomRight) 59 | if DrawTriangles ~= false then 60 | Ceive.Ray:Draw(TopRight, BottomLeft) 61 | end 62 | 63 | Ceive.Ray:Draw(BottomLeft, BottomRight) 64 | end 65 | 66 | local function CalculateXFace(lUv, lRv, lLv) 67 | local TopLeft = Position + (lUv - lRv - lLv) 68 | local TopRight = Position + (lUv - lRv + lLv) 69 | local BottomLeft = Position + (-lUv - lRv - lLv) 70 | local BottomRight = Position + (-lUv - lRv + lLv) 71 | 72 | Ceive.Ray:Draw(TopLeft, TopRight) 73 | Ceive.Ray:Draw(TopLeft, BottomLeft) 74 | 75 | Ceive.Ray:Draw(TopRight, BottomRight) 76 | if DrawTriangles ~= false then 77 | Ceive.Ray:Draw(TopRight, BottomLeft) 78 | end 79 | 80 | Ceive.Ray:Draw(BottomLeft, BottomRight) 81 | end 82 | 83 | CalculateXFace(sUv, sRv, sLv) 84 | CalculateXFace(sUv, -sRv, sLv) 85 | 86 | CalculateYFace(sUv, sRv, sLv) 87 | CalculateYFace(-sUv, sRv, sLv) 88 | 89 | CalculateZFace(sUv, sRv, sLv) 90 | CalculateZFace(sUv, sRv, -sLv) 91 | end 92 | 93 | function Gizmo:Create(Transform: CFrame, Size: Vector3, DrawTriangles: boolean) 94 | local PropertyTable = { 95 | Transform = Transform, 96 | Size = Size, 97 | DrawTriangles = DrawTriangles, 98 | AlwaysOnTop = self.Propertys.AlwaysOnTop, 99 | Transparency = self.Propertys.Transparency, 100 | Color3 = self.Propertys.Color3, 101 | Enabled = true, 102 | Destroy = false, 103 | } 104 | 105 | self.Retain(self, PropertyTable) 106 | 107 | return PropertyTable 108 | end 109 | 110 | function Gizmo:Update(PropertyTable) 111 | local Ceive = self.Ceive 112 | 113 | Ceive.PushProperty("AlwaysOnTop", PropertyTable.AlwaysOnTop) 114 | Ceive.PushProperty("Transparency", PropertyTable.Transparency) 115 | Ceive.PushProperty("Color3", PropertyTable.Color3) 116 | 117 | self:Draw(PropertyTable.Transform, PropertyTable.Size, PropertyTable.DrawTriangles) 118 | end 119 | 120 | return Gizmo 121 | -------------------------------------------------------------------------------- /src-build/Dependencies/Debug/Gizmo/Gizmos/Capsule.luau: -------------------------------------------------------------------------------- 1 | local Rad180D = math.rad(180) 2 | 3 | local Gizmo = {} 4 | Gizmo.__index = Gizmo 5 | 6 | function Gizmo.Init(Ceive, Propertys, Request, Release, Retain) 7 | local self = setmetatable({}, Gizmo) 8 | 9 | self.Ceive = Ceive 10 | self.Propertys = Propertys 11 | self.Request = Request 12 | self.Release = Release 13 | self.Retain = Retain 14 | 15 | return self 16 | end 17 | 18 | function Gizmo:Draw(Transform: CFrame, Radius: number, Length: number, Subdivisions: number) 19 | local Ceive = self.Ceive 20 | 21 | if not Ceive.Enabled then 22 | return 23 | end 24 | 25 | -- Draw top and bottom of cylinder 26 | local TopOfCylinder = Transform.Position + (Transform.UpVector * (Length * 0.5)) 27 | local BottomOfCylinder = Transform.Position - (Transform.UpVector * (Length * 0.5)) 28 | 29 | TopOfCylinder = CFrame.lookAt(TopOfCylinder, TopOfCylinder + Transform.UpVector) 30 | BottomOfCylinder = CFrame.lookAt(BottomOfCylinder, BottomOfCylinder - Transform.UpVector) 31 | 32 | -- Draw Cylinder Lines 33 | 34 | local AnglePerChunk = math.floor(360 / Subdivisions) 35 | 36 | local LastTop 37 | local LastBottom 38 | 39 | local FirstTop 40 | local FirstBottom 41 | 42 | for i = 0, 360, AnglePerChunk do 43 | local XMagnitude = math.sin(math.rad(i)) * Radius 44 | local YMagnitude = math.cos(math.rad(i)) * Radius 45 | 46 | local VertexOffset = (Transform.LookVector * YMagnitude) + (Transform.RightVector * XMagnitude) 47 | local TopVertexPosition = TopOfCylinder.Position + VertexOffset 48 | local BottomVertexPosition = BottomOfCylinder.Position + VertexOffset 49 | 50 | Ceive.Ray:Draw(TopVertexPosition, BottomVertexPosition) 51 | 52 | Ceive.Circle:Draw( 53 | CFrame.new(TopOfCylinder.Position) * Transform.Rotation * CFrame.Angles(0, math.rad(i), 0), 54 | Radius, 55 | Subdivisions * 0.5, 56 | 90, 57 | false 58 | ) 59 | Ceive.Circle:Draw( 60 | CFrame.new(BottomOfCylinder.Position) * Transform.Rotation * CFrame.Angles(Rad180D, math.rad(i), 0), 61 | Radius, 62 | Subdivisions * 0.5, 63 | 90, 64 | false 65 | ) 66 | 67 | if not LastTop then 68 | LastTop = TopVertexPosition 69 | LastBottom = BottomVertexPosition 70 | 71 | FirstTop = TopVertexPosition 72 | FirstBottom = BottomVertexPosition 73 | 74 | continue 75 | end 76 | 77 | Ceive.Ray:Draw(LastTop, TopVertexPosition) 78 | Ceive.Ray:Draw(LastBottom, BottomVertexPosition) 79 | 80 | LastTop = TopVertexPosition 81 | LastBottom = BottomVertexPosition 82 | end 83 | 84 | Ceive.Ray:Draw(LastTop, FirstTop) 85 | Ceive.Ray:Draw(LastBottom, FirstBottom) 86 | end 87 | 88 | function Gizmo:Create(Transform: CFrame, Radius: number, Length: number, Subdivisions: number) 89 | local PropertyTable = { 90 | Transform = Transform, 91 | Radius = Radius, 92 | Length = Length, 93 | Subdivisions = Subdivisions, 94 | AlwaysOnTop = self.Propertys.AlwaysOnTop, 95 | Transparency = self.Propertys.Transparency, 96 | Color3 = self.Propertys.Color3, 97 | Enabled = true, 98 | Destroy = false, 99 | } 100 | 101 | self.Retain(self, PropertyTable) 102 | 103 | return PropertyTable 104 | end 105 | 106 | function Gizmo:Update(PropertyTable) 107 | local Ceive = self.Ceive 108 | 109 | Ceive.PushProperty("AlwaysOnTop", PropertyTable.AlwaysOnTop) 110 | Ceive.PushProperty("Transparency", PropertyTable.Transparency) 111 | Ceive.PushProperty("Color3", PropertyTable.Color3) 112 | 113 | self:Draw(PropertyTable.Transform, PropertyTable.Radius, PropertyTable.Length, PropertyTable.Subdivisions) 114 | end 115 | 116 | return Gizmo 117 | -------------------------------------------------------------------------------- /src-build/Dependencies/Debug/Gizmo/Gizmos/Circle.luau: -------------------------------------------------------------------------------- 1 | local Gizmo = {} 2 | Gizmo.__index = Gizmo 3 | 4 | function Gizmo.Init(Ceive, Propertys, Request, Release, Retain) 5 | local self = setmetatable({}, Gizmo) 6 | 7 | self.Ceive = Ceive 8 | self.Propertys = Propertys 9 | self.Request = Request 10 | self.Release = Release 11 | self.Retain = Retain 12 | 13 | return self 14 | end 15 | 16 | function Gizmo:Draw(Transform: CFrame, Radius: number, Subdivisions: number, Angle: number, ConnectToStart: boolean?) 17 | local Ceive = self.Ceive 18 | 19 | if not Ceive.Enabled then 20 | return 21 | end 22 | 23 | local AnglePerChunk = math.floor(Angle / Subdivisions) 24 | 25 | local PreviousVertex 26 | local FirstVertex 27 | 28 | local FinishingAngle = 0 29 | 30 | for i = 0, Angle, AnglePerChunk do 31 | local XMagnitude = math.sin(math.rad(i)) * Radius 32 | local YMagnitude = math.cos(math.rad(i)) * Radius 33 | 34 | local VertexPosition = Transform.Position + ((Transform.UpVector * YMagnitude) + (Transform.RightVector * XMagnitude)) 35 | 36 | if PreviousVertex == nil then 37 | PreviousVertex = VertexPosition 38 | FirstVertex = VertexPosition 39 | FinishingAngle = i 40 | continue 41 | end 42 | 43 | Ceive.Ray:Draw(PreviousVertex, VertexPosition) 44 | PreviousVertex = VertexPosition 45 | FinishingAngle = i 46 | end 47 | 48 | if FinishingAngle ~= Angle then 49 | local XMagnitude = math.sin(math.rad(Angle)) * Radius 50 | local YMagnitude = math.cos(math.rad(Angle)) * Radius 51 | 52 | local VertexPosition = Transform.Position + ((Transform.UpVector * YMagnitude) + (Transform.RightVector * XMagnitude)) 53 | 54 | Ceive.Ray:Draw(PreviousVertex, VertexPosition) 55 | end 56 | 57 | if ConnectToStart ~= false then 58 | Ceive.Ray:Draw(PreviousVertex, FirstVertex) 59 | end 60 | 61 | return PreviousVertex 62 | end 63 | 64 | function Gizmo:Create(Transform: CFrame, Radius: number, Subdivisions: number, Angle: number, ConnectToStart: boolean?) 65 | local PropertyTable = { 66 | Transform = Transform, 67 | Radius = Radius, 68 | Subdivisions = Subdivisions, 69 | Angle = Angle, 70 | ConnectToStart = ConnectToStart, 71 | AlwaysOnTop = self.Propertys.AlwaysOnTop, 72 | Transparency = self.Propertys.Transparency, 73 | Color3 = self.Propertys.Color3, 74 | Enabled = true, 75 | Destroy = false, 76 | } 77 | 78 | self.Retain(self, PropertyTable) 79 | 80 | return PropertyTable 81 | end 82 | 83 | function Gizmo:Update(PropertyTable) 84 | local Ceive = self.Ceive 85 | 86 | Ceive.PushProperty("AlwaysOnTop", PropertyTable.AlwaysOnTop) 87 | Ceive.PushProperty("Transparency", PropertyTable.Transparency) 88 | Ceive.PushProperty("Color3", PropertyTable.Color3) 89 | 90 | self:Draw(PropertyTable.Transform, PropertyTable.Radius, PropertyTable.Subdivisions, PropertyTable.Angle, PropertyTable.ConnectToStart) 91 | end 92 | 93 | return Gizmo 94 | -------------------------------------------------------------------------------- /src-build/Dependencies/Debug/Gizmo/Gizmos/Cone.luau: -------------------------------------------------------------------------------- 1 | local Rad90D = math.rad(90) 2 | 3 | local Gizmo = {} 4 | Gizmo.__index = Gizmo 5 | 6 | function Gizmo.Init(Ceive, Propertys, Request, Release, Retain) 7 | local self = setmetatable({}, Gizmo) 8 | 9 | self.Ceive = Ceive 10 | self.Propertys = Propertys 11 | self.Request = Request 12 | self.Release = Release 13 | self.Retain = Retain 14 | 15 | return self 16 | end 17 | 18 | function Gizmo:Draw(Transform: CFrame, Radius: number, Length: number, Subdivisions: number) 19 | local Ceive = self.Ceive 20 | 21 | if not Ceive.Enabled then 22 | return 23 | end 24 | 25 | Transform *= CFrame.Angles(-Rad90D, 0, 0) 26 | 27 | local TopOfCone = Transform.Position + Transform.UpVector * (Length * 0.5) 28 | local BottomOfCone = Transform.Position + -Transform.UpVector * (Length * 0.5) 29 | 30 | TopOfCone = CFrame.lookAt(TopOfCone, TopOfCone + Transform.UpVector) 31 | BottomOfCone = CFrame.lookAt(BottomOfCone, BottomOfCone - Transform.UpVector) 32 | 33 | local AnglePerChunk = math.floor(360 / Subdivisions) 34 | 35 | local Last 36 | local First 37 | 38 | for i = 0, 360, AnglePerChunk do 39 | local XMagnitude = math.sin(math.rad(i)) * Radius 40 | local YMagnitude = math.cos(math.rad(i)) * Radius 41 | 42 | local VertexOffset = (Transform.LookVector * YMagnitude) + (Transform.RightVector * XMagnitude) 43 | local VertexPosition = BottomOfCone.Position + VertexOffset 44 | 45 | if not Last then 46 | Last = VertexPosition 47 | First = VertexPosition 48 | 49 | Ceive.Ray:Draw(VertexPosition, TopOfCone.Position) 50 | 51 | continue 52 | end 53 | 54 | Ceive.Ray:Draw(VertexPosition, TopOfCone.Position) 55 | Ceive.Ray:Draw(Last, VertexPosition) 56 | 57 | Last = VertexPosition 58 | end 59 | 60 | Ceive.Ray:Draw(Last, First) 61 | end 62 | 63 | function Gizmo:Create(Transform: CFrame, Radius: number, Length: number, Subdivisions: number) 64 | local PropertyTable = { 65 | Transform = Transform, 66 | Radius = Radius, 67 | Length = Length, 68 | Subdivisions = Subdivisions, 69 | AlwaysOnTop = self.Propertys.AlwaysOnTop, 70 | Transparency = self.Propertys.Transparency, 71 | Color3 = self.Propertys.Color3, 72 | Enabled = true, 73 | Destroy = false, 74 | } 75 | 76 | self.Retain(self, PropertyTable) 77 | 78 | return PropertyTable 79 | end 80 | 81 | function Gizmo:Update(PropertyTable) 82 | local Ceive = self.Ceive 83 | 84 | Ceive.PushProperty("AlwaysOnTop", PropertyTable.AlwaysOnTop) 85 | Ceive.PushProperty("Transparency", PropertyTable.Transparency) 86 | Ceive.PushProperty("Color3", PropertyTable.Color3) 87 | 88 | self:Draw(PropertyTable.Transform, PropertyTable.Radius, PropertyTable.Length, PropertyTable.Subdivisions) 89 | end 90 | 91 | return Gizmo 92 | -------------------------------------------------------------------------------- /src-build/Dependencies/Debug/Gizmo/Gizmos/Cylinder.luau: -------------------------------------------------------------------------------- 1 | local Gizmo = {} 2 | Gizmo.__index = Gizmo 3 | 4 | function Gizmo.Init(Ceive, Propertys, Request, Release, Retain) 5 | local self = setmetatable({}, Gizmo) 6 | 7 | self.Ceive = Ceive 8 | self.Propertys = Propertys 9 | self.Request = Request 10 | self.Release = Release 11 | self.Retain = Retain 12 | 13 | return self 14 | end 15 | 16 | function Gizmo:Draw(Transform: CFrame, Radius: number, Length: number, Subdivisions: number) 17 | local Ceive = self.Ceive 18 | 19 | if not Ceive.Enabled then 20 | return 21 | end 22 | 23 | -- Draw top and bottom of cylinder 24 | local TopOfCylinder = Transform.Position + (Transform.UpVector * (Length * 0.5)) 25 | local BottomOfCylinder = Transform.Position - (Transform.UpVector * (Length * 0.5)) 26 | 27 | TopOfCylinder = CFrame.lookAt(TopOfCylinder, TopOfCylinder + Transform.UpVector) 28 | BottomOfCylinder = CFrame.lookAt(BottomOfCylinder, BottomOfCylinder - Transform.UpVector) 29 | 30 | -- Draw Cylinder Lines 31 | 32 | local AnglePerChunk = math.floor(360 / Subdivisions) 33 | 34 | local LastTop 35 | local LastBottom 36 | 37 | local FirstTop 38 | local FirstBottom 39 | 40 | for i = 0, 360, AnglePerChunk do 41 | local XMagnitude = math.sin(math.rad(i)) * Radius 42 | local YMagnitude = math.cos(math.rad(i)) * Radius 43 | 44 | local VertexOffset = (Transform.LookVector * YMagnitude) + (Transform.RightVector * XMagnitude) 45 | local TopVertexPosition = TopOfCylinder.Position + VertexOffset 46 | local BottomVertexPosition = BottomOfCylinder.Position + VertexOffset 47 | 48 | Ceive.Ray:Draw(TopVertexPosition, BottomVertexPosition) 49 | 50 | if not LastTop then 51 | LastTop = TopVertexPosition 52 | LastBottom = BottomVertexPosition 53 | 54 | FirstTop = TopVertexPosition 55 | FirstBottom = BottomVertexPosition 56 | 57 | continue 58 | end 59 | 60 | Ceive.Ray:Draw(LastTop, TopVertexPosition) 61 | Ceive.Ray:Draw(LastBottom, BottomVertexPosition) 62 | 63 | LastTop = TopVertexPosition 64 | LastBottom = BottomVertexPosition 65 | end 66 | 67 | Ceive.Ray:Draw(LastTop, FirstTop) 68 | Ceive.Ray:Draw(LastBottom, FirstBottom) 69 | end 70 | 71 | function Gizmo:Create(Transform: CFrame, Radius: number, Length: number, Subdivisions: number) 72 | local PropertyTable = { 73 | Transform = Transform, 74 | Radius = Radius, 75 | Length = Length, 76 | Subdivisions = Subdivisions, 77 | AlwaysOnTop = self.Propertys.AlwaysOnTop, 78 | Transparency = self.Propertys.Transparency, 79 | Color3 = self.Propertys.Color3, 80 | Enabled = true, 81 | Destroy = false, 82 | } 83 | 84 | self.Retain(self, PropertyTable) 85 | 86 | return PropertyTable 87 | end 88 | 89 | function Gizmo:Update(PropertyTable) 90 | local Ceive = self.Ceive 91 | 92 | Ceive.PushProperty("AlwaysOnTop", PropertyTable.AlwaysOnTop) 93 | Ceive.PushProperty("Transparency", PropertyTable.Transparency) 94 | Ceive.PushProperty("Color3", PropertyTable.Color3) 95 | 96 | self:Draw(PropertyTable.Transform, PropertyTable.Radius, PropertyTable.Length, PropertyTable.Subdivisions) 97 | end 98 | 99 | return Gizmo 100 | -------------------------------------------------------------------------------- /src-build/Dependencies/Debug/Gizmo/Gizmos/Line.luau: -------------------------------------------------------------------------------- 1 | local Gizmo = {} 2 | Gizmo.__index = Gizmo 3 | 4 | function Gizmo.Init(Ceive, Propertys, Request, Release, Retain) 5 | local self = setmetatable({}, Gizmo) 6 | 7 | self.Ceive = Ceive 8 | self.Propertys = Propertys 9 | self.Request = Request 10 | self.Release = Release 11 | self.Retain = Retain 12 | 13 | return self 14 | end 15 | 16 | function Gizmo:Draw(Transform: CFrame, Length: number) 17 | local Ceive = self.Ceive 18 | 19 | if not Ceive.Enabled then 20 | return 21 | end 22 | 23 | local Origin = Transform.Position + (Transform.LookVector * (-Length * 0.5)) 24 | local End = Transform.Position + (Transform.LookVector * (Length * 0.5)) 25 | 26 | Ceive.Ray:Draw(Origin, End) 27 | end 28 | 29 | function Gizmo:Create(Transform: CFrame, Length: number) 30 | local PropertyTable = { 31 | Transform = Transform, 32 | Length = Length, 33 | AlwaysOnTop = self.Propertys.AlwaysOnTop, 34 | Transparency = self.Propertys.Transparency, 35 | Color3 = self.Propertys.Color3, 36 | Enabled = true, 37 | Destroy = false, 38 | } 39 | 40 | self.Retain(self, PropertyTable) 41 | 42 | return PropertyTable 43 | end 44 | 45 | function Gizmo:Update(PropertyTable) 46 | local Ceive = self.Ceive 47 | 48 | Ceive.PushProperty("AlwaysOnTop", PropertyTable.AlwaysOnTop) 49 | Ceive.PushProperty("Transparency", PropertyTable.Transparency) 50 | Ceive.PushProperty("Color3", PropertyTable.Color3) 51 | 52 | self:Draw(PropertyTable.Transform, PropertyTable.Length) 53 | end 54 | 55 | return Gizmo 56 | -------------------------------------------------------------------------------- /src-build/Dependencies/Debug/Gizmo/Gizmos/Mesh.luau: -------------------------------------------------------------------------------- 1 | local function Map(n, start, stop, newStart, newStop) 2 | return ((n - start) / (stop - start)) * (newStop - newStart) + newStart 3 | end 4 | 5 | local Gizmo = {} 6 | Gizmo.__index = Gizmo 7 | 8 | function Gizmo.Init(Ceive, Propertys, Request, Release, Retain) 9 | local self = setmetatable({}, Gizmo) 10 | 11 | self.Ceive = Ceive 12 | self.Propertys = Propertys 13 | self.Request = Request 14 | self.Release = Release 15 | self.Retain = Retain 16 | 17 | return self 18 | end 19 | 20 | function Gizmo:Draw(Transform: CFrame, Size: Vector3, Vertices, Faces) 21 | local Ceive = self.Ceive 22 | 23 | if not Ceive.Enabled then 24 | return 25 | end 26 | 27 | local maxX = -math.huge 28 | local maxY = -math.huge 29 | local maxZ = -math.huge 30 | 31 | local minX = math.huge 32 | local minY = math.huge 33 | local minZ = math.huge 34 | 35 | for _, vertex in Vertices do 36 | maxX = math.max(maxX, vertex.x) 37 | maxY = math.max(maxY, vertex.y) 38 | maxZ = math.max(maxZ, vertex.z) 39 | 40 | minX = math.min(minX, vertex.x) 41 | minY = math.min(minY, vertex.y) 42 | minZ = math.min(minZ, vertex.z) 43 | end 44 | 45 | for i, vertex in Vertices do 46 | local vX = Map(vertex.x, minX, maxX, -0.5, 0.5) 47 | local vY = Map(vertex.y, minY, maxY, -0.5, 0.5) 48 | local vZ = Map(vertex.z, minZ, maxZ, -0.5, 0.5) 49 | 50 | local vertexCFrame = Transform * CFrame.new(Vector3.new(vX, vY, vZ) * Size) 51 | Vertices[i] = vertexCFrame 52 | end 53 | 54 | for _, face in Faces do 55 | if #face == 3 then 56 | local vCF1 = Vertices[face[1].v] 57 | local vCF2 = Vertices[face[2].v] 58 | local vCF3 = Vertices[face[3].v] 59 | 60 | Ceive.Ray:Draw(vCF1.Position, vCF2.Position) 61 | Ceive.Ray:Draw(vCF2.Position, vCF3.Position) 62 | Ceive.Ray:Draw(vCF3.Position, vCF1.Position) 63 | else 64 | local vCF1 = Vertices[face[1].v] 65 | local vCF2 = Vertices[face[2].v] 66 | local vCF3 = Vertices[face[3].v] 67 | local vCF4 = Vertices[face[4].v] 68 | 69 | Ceive.Ray:Draw(vCF1.Position, vCF2.Position) 70 | Ceive.Ray:Draw(vCF1.Position, vCF4.Position) 71 | Ceive.Ray:Draw(vCF4.Position, vCF2.Position) 72 | 73 | Ceive.Ray:Draw(vCF3.Position, vCF4.Position) 74 | Ceive.Ray:Draw(vCF2.Position, vCF3.Position) 75 | end 76 | end 77 | end 78 | 79 | function Gizmo:Create(Transform: CFrame, Size: Vector3, Vertices, Faces) 80 | local PropertyTable = { 81 | Transform = Transform, 82 | Size = Size, 83 | Vertices = Vertices, 84 | Faces = Faces, 85 | AlwaysOnTop = self.Propertys.AlwaysOnTop, 86 | Transparency = self.Propertys.Transparency, 87 | Color3 = self.Propertys.Color3, 88 | Enabled = true, 89 | Destroy = false, 90 | } 91 | 92 | self.Retain(self, PropertyTable) 93 | 94 | return PropertyTable 95 | end 96 | 97 | function Gizmo:Update(PropertyTable) 98 | local Ceive = self.Ceive 99 | 100 | Ceive.PushProperty("AlwaysOnTop", PropertyTable.AlwaysOnTop) 101 | Ceive.PushProperty("Transparency", PropertyTable.Transparency) 102 | Ceive.PushProperty("Color3", PropertyTable.Color3) 103 | 104 | self:Draw(PropertyTable.Transform, PropertyTable.Size, PropertyTable.Vertices, PropertyTable.Faces) 105 | end 106 | 107 | return Gizmo 108 | -------------------------------------------------------------------------------- /src-build/Dependencies/Debug/Gizmo/Gizmos/Plane.luau: -------------------------------------------------------------------------------- 1 | local Gizmo = {} 2 | Gizmo.__index = Gizmo 3 | 4 | function Gizmo.Init(Ceive, Propertys, Request, Release, Retain) 5 | local self = setmetatable({}, Gizmo) 6 | 7 | self.Ceive = Ceive 8 | self.Propertys = Propertys 9 | self.Request = Request 10 | self.Release = Release 11 | self.Retain = Retain 12 | 13 | return self 14 | end 15 | 16 | function Gizmo:Draw(Position: Vector3, Normal: Vector3, Size: Vector3) 17 | local Ceive = self.Ceive 18 | 19 | if not Ceive.Enabled then 20 | return 21 | end 22 | 23 | Size *= Vector3.new(1, 1, 0) 24 | 25 | local Transform = CFrame.lookAt(Position, Position + Normal) 26 | 27 | local Uv = Transform.UpVector 28 | local Rv = Transform.RightVector 29 | local Lv = Transform.LookVector 30 | local sO2 = Size * 0.5 31 | local sUv = Uv * sO2.Y 32 | local sRv = Rv * sO2.X 33 | local sLv = Lv * sO2.Z 34 | 35 | local function CalculateZFace(lUv, lRv, lLv) 36 | local TopLeft = Position + (lUv - lRv + lLv) 37 | local TopRight = Position + (lUv + lRv + lLv) 38 | local BottomLeft = Position + (-lUv - lRv + lLv) 39 | local BottomRight = Position + (-lUv + lRv + lLv) 40 | 41 | Ceive.Ray:Draw(TopLeft, TopRight) 42 | Ceive.Ray:Draw(TopLeft, BottomLeft) 43 | 44 | Ceive.Ray:Draw(TopRight, BottomRight) 45 | Ceive.Ray:Draw(TopRight, BottomLeft) 46 | 47 | Ceive.Ray:Draw(BottomLeft, BottomRight) 48 | end 49 | 50 | CalculateZFace(sUv, sRv, sLv) 51 | end 52 | 53 | function Gizmo:Create(Position: Vector3, Normal: Vector3, Size: Vector3) 54 | local PropertyTable = { 55 | Position = Position, 56 | Normal = Normal, 57 | Size = Size, 58 | AlwaysOnTop = self.Propertys.AlwaysOnTop, 59 | Transparency = self.Propertys.Transparency, 60 | Color3 = self.Propertys.Color3, 61 | Enabled = true, 62 | Destroy = false, 63 | } 64 | 65 | self.Retain(self, PropertyTable) 66 | 67 | return PropertyTable 68 | end 69 | 70 | function Gizmo:Update(PropertyTable) 71 | local Ceive = self.Ceive 72 | 73 | Ceive.PushProperty("AlwaysOnTop", PropertyTable.AlwaysOnTop) 74 | Ceive.PushProperty("Transparency", PropertyTable.Transparency) 75 | Ceive.PushProperty("Color3", PropertyTable.Color3) 76 | 77 | self:Draw(PropertyTable.Position, PropertyTable.Normal, PropertyTable.Size) 78 | end 79 | 80 | return Gizmo 81 | -------------------------------------------------------------------------------- /src-build/Dependencies/Debug/Gizmo/Gizmos/Ray.luau: -------------------------------------------------------------------------------- 1 | local Gizmo = {} 2 | Gizmo.__index = Gizmo 3 | 4 | function Gizmo.Init(Ceive, Propertys, Request, Release, Retain) 5 | local self = setmetatable({}, Gizmo) 6 | 7 | self.Ceive = Ceive 8 | self.Propertys = Propertys 9 | self.Request = Request 10 | self.Release = Release 11 | self.Retain = Retain 12 | 13 | return self 14 | end 15 | 16 | function Gizmo:Draw(Origin: Vector3, End: Vector3) 17 | local Ceive = self.Ceive 18 | 19 | if not Ceive.Enabled then 20 | return 21 | end 22 | 23 | if self.Propertys.AlwaysOnTop then 24 | Ceive.AOTWireframeHandle:AddLine(Origin, End) 25 | else 26 | Ceive.WireframeHandle:AddLine(Origin, End) 27 | end 28 | 29 | self.Ceive.ActiveRays += 1 30 | 31 | self.Ceive.ScheduleCleaning() 32 | end 33 | 34 | function Gizmo:Create(Origin: Vector3, End: Vector3) 35 | local PropertyTable = { 36 | Origin = Origin, 37 | End = End, 38 | AlwaysOnTop = self.Propertys.AlwaysOnTop, 39 | Transparency = self.Propertys.Transparency, 40 | Color3 = self.Propertys.Color3, 41 | Enabled = true, 42 | Destroy = false, 43 | } 44 | 45 | self.Retain(self, PropertyTable) 46 | 47 | return PropertyTable 48 | end 49 | 50 | function Gizmo:Update(PropertyTable) 51 | local Ceive = self.Ceive 52 | 53 | Ceive.PushProperty("AlwaysOnTop", PropertyTable.AlwaysOnTop) 54 | Ceive.PushProperty("Transparency", PropertyTable.Transparency) 55 | Ceive.PushProperty("Color3", PropertyTable.Color3) 56 | 57 | self:Draw(PropertyTable.Origin, PropertyTable.End) 58 | end 59 | 60 | return Gizmo 61 | -------------------------------------------------------------------------------- /src-build/Dependencies/Debug/Gizmo/Gizmos/Sphere.luau: -------------------------------------------------------------------------------- 1 | local Rad90D = math.rad(90) 2 | 3 | local Gizmo = {} 4 | Gizmo.__index = Gizmo 5 | 6 | function Gizmo.Init(Ceive, Propertys, Request, Release, Retain) 7 | local self = setmetatable({}, Gizmo) 8 | 9 | self.Ceive = Ceive 10 | self.Propertys = Propertys 11 | self.Request = Request 12 | self.Release = Release 13 | self.Retain = Retain 14 | 15 | return self 16 | end 17 | 18 | function Gizmo:Draw(Transform: CFrame, Radius: number, Subdivisions: number, Angle: number) 19 | local Ceive = self.Ceive 20 | 21 | if not Ceive.Enabled then 22 | return 23 | end 24 | 25 | Ceive.Circle:Draw(Transform, Radius, Subdivisions, Angle) 26 | Ceive.Circle:Draw(Transform * CFrame.Angles(0, Rad90D, 0), Radius, Subdivisions, Angle) 27 | Ceive.Circle:Draw(Transform * CFrame.Angles(Rad90D, 0, 0), Radius, Subdivisions, Angle) 28 | end 29 | 30 | function Gizmo:Create(Transform: CFrame, Radius: number, Subdivisions: number, Angle: number) 31 | local PropertyTable = { 32 | Transform = Transform, 33 | Radius = Radius, 34 | Subdivisions = Subdivisions, 35 | Angle = Angle, 36 | AlwaysOnTop = self.Propertys.AlwaysOnTop, 37 | Transparency = self.Propertys.Transparency, 38 | Color3 = self.Propertys.Color3, 39 | Enabled = true, 40 | Destroy = false, 41 | } 42 | 43 | self.Retain(self, PropertyTable) 44 | 45 | return PropertyTable 46 | end 47 | 48 | function Gizmo:Update(PropertyTable) 49 | local Ceive = self.Ceive 50 | 51 | Ceive.PushProperty("AlwaysOnTop", PropertyTable.AlwaysOnTop) 52 | Ceive.PushProperty("Transparency", PropertyTable.Transparency) 53 | Ceive.PushProperty("Color3", PropertyTable.Color3) 54 | 55 | self:Draw(PropertyTable.Transform, PropertyTable.Radius, PropertyTable.Subdivisions, PropertyTable.Angle) 56 | end 57 | 58 | return Gizmo 59 | -------------------------------------------------------------------------------- /src-build/Dependencies/Debug/Gizmo/Gizmos/Text.luau: -------------------------------------------------------------------------------- 1 | local DROP_SHADOW = true 2 | local OFFSET_PERCENTAGE = 0.00175 3 | 4 | local Camera = workspace.CurrentCamera 5 | 6 | local Gizmo = {} 7 | Gizmo.__index = Gizmo 8 | 9 | function Gizmo.Init(Ceive, Propertys, Request, Release, Retain) 10 | local self = setmetatable({}, Gizmo) 11 | 12 | self.Ceive = Ceive 13 | self.Propertys = Propertys 14 | self.Request = Request 15 | self.Release = Release 16 | self.Retain = Retain 17 | 18 | return self 19 | end 20 | 21 | function Gizmo:Draw(Origin: Vector3, Text: string, Size: number?) 22 | local Ceive = self.Ceive 23 | 24 | if not Ceive.Enabled then 25 | return 26 | end 27 | 28 | if self.Propertys.AlwaysOnTop then 29 | if DROP_SHADOW then 30 | local DistanceToCamera = (Origin - Camera.CFrame.Position).Magnitude 31 | local PrevColor = Ceive.PopProperty("Color3") 32 | 33 | Ceive.PushProperty("Color3", Color3.new()) 34 | local Offset = -(Vector3.xAxis + Vector3.yAxis).Unit 35 | Ceive.AOTWireframeHandle:AddText(Origin + Offset * (DistanceToCamera * OFFSET_PERCENTAGE), Text, Size) 36 | Ceive.PushProperty("Color3", PrevColor) 37 | end 38 | 39 | Ceive.AOTWireframeHandle:AddText(Origin, Text, Size) 40 | else 41 | if DROP_SHADOW then 42 | local DistanceToCamera = (Origin - Camera.CFrame.Position).Magnitude 43 | local PrevColor = Ceive.PopProperty("Color3") 44 | 45 | Ceive.PushProperty("Color3", Color3.new()) 46 | local Offset = -(Vector3.xAxis + Vector3.yAxis).Unit 47 | Ceive.WireframeHandle:AddText(Origin + Offset * (DistanceToCamera * OFFSET_PERCENTAGE), Text, Size) 48 | Ceive.PushProperty("Color3", PrevColor) 49 | end 50 | 51 | Ceive.WireframeHandle:AddText(Origin, Text, Size) 52 | end 53 | 54 | -- Should text count to active rays? 55 | --self.Ceive.ActiveRays += 1 56 | 57 | self.Ceive.ScheduleCleaning() 58 | end 59 | 60 | function Gizmo:Create(Origin: Vector3, Text: string, Size: number?) 61 | local PropertyTable = { 62 | Origin = Origin, 63 | Text = Text, 64 | Size = Size, 65 | AlwaysOnTop = self.Propertys.AlwaysOnTop, 66 | Transparency = self.Propertys.Transparency, 67 | Color3 = self.Propertys.Color3, 68 | Enabled = true, 69 | Destroy = false, 70 | } 71 | 72 | self.Retain(self, PropertyTable) 73 | 74 | return PropertyTable 75 | end 76 | 77 | function Gizmo:Update(PropertyTable) 78 | local Ceive = self.Ceive 79 | 80 | Ceive.PushProperty("AlwaysOnTop", PropertyTable.AlwaysOnTop) 81 | Ceive.PushProperty("Transparency", PropertyTable.Transparency) 82 | Ceive.PushProperty("Color3", PropertyTable.Color3) 83 | 84 | self:Draw(PropertyTable.Origin, PropertyTable.Text, PropertyTable.Size) 85 | end 86 | 87 | return Gizmo 88 | -------------------------------------------------------------------------------- /src-build/Dependencies/Debug/Gizmo/Gizmos/VolumeArrow.luau: -------------------------------------------------------------------------------- 1 | local Gizmo = {} 2 | Gizmo.__index = Gizmo 3 | 4 | function Gizmo.Init(Ceive, Propertys, Request, Release, Retain, Register) 5 | local self = setmetatable({}, Gizmo) 6 | 7 | self.Ceive = Ceive 8 | self.Propertys = Propertys 9 | self.Request = Request 10 | self.Release = Release 11 | self.Retain = Retain 12 | self.Register = Register 13 | 14 | return self 15 | end 16 | 17 | function Gizmo:Draw(Origin: Vector3, End: Vector3, CylinderRadius: number, ConeRadius: number, Length: number, UseCylinder: boolean?) 18 | local Ceive = self.Ceive 19 | 20 | if not Ceive.Enabled then 21 | return 22 | end 23 | 24 | local ArrowCFrame = CFrame.lookAt(End - (End - Origin).Unit * (Length * 0.5), End) 25 | 26 | if UseCylinder == true then 27 | local BottomCone = ArrowCFrame.Position 28 | local CylinderLength = (BottomCone - Origin).Magnitude 29 | local CylinderCFrame = CFrame.lookAt((Origin + BottomCone) * 0.5, End) 30 | 31 | Ceive.VolumeCylinder:Draw(CylinderCFrame, CylinderRadius, CylinderLength) 32 | else 33 | Ceive.Ray:Draw(Origin, End) 34 | end 35 | 36 | Ceive.VolumeCone:Draw(ArrowCFrame, ConeRadius, Length) 37 | self.Ceive.ScheduleCleaning() 38 | end 39 | 40 | function Gizmo:Create(Origin: Vector3, End: Vector3, CylinderRadius: number, ConeRadius: number, Length: number, UseCylinder: boolean?) 41 | local PropertyTable = { 42 | Origin = Origin, 43 | End = End, 44 | CylinderRadius = CylinderRadius, 45 | ConeRadius = ConeRadius, 46 | Length = Length, 47 | UseCylinder = UseCylinder, 48 | AlwaysOnTop = self.Propertys.AlwaysOnTop, 49 | Transparency = self.Propertys.Transparency, 50 | Color3 = self.Propertys.Color3, 51 | Enabled = true, 52 | Destroy = false, 53 | } 54 | 55 | self.Retain(self, PropertyTable) 56 | 57 | return PropertyTable 58 | end 59 | 60 | function Gizmo:Update(PropertyTable) 61 | local Ceive = self.Ceive 62 | 63 | Ceive.PushProperty("AlwaysOnTop", PropertyTable.AlwaysOnTop) 64 | Ceive.PushProperty("Transparency", PropertyTable.Transparency) 65 | Ceive.PushProperty("Color3", PropertyTable.Color3) 66 | 67 | self:Draw(PropertyTable.Origin, PropertyTable.End, PropertyTable.Radius, PropertyTable.Length, PropertyTable.UseCylinder) 68 | end 69 | 70 | return Gizmo 71 | -------------------------------------------------------------------------------- /src-build/Dependencies/Debug/Gizmo/Gizmos/VolumeBox.luau: -------------------------------------------------------------------------------- 1 | local Terrain = workspace.Terrain 2 | 3 | local Gizmo = {} 4 | Gizmo.__index = Gizmo 5 | 6 | function Gizmo.Init(Ceive, Propertys, Request, Release, Retain, Register) 7 | local self = setmetatable({}, Gizmo) 8 | 9 | self.Ceive = Ceive 10 | self.Propertys = Propertys 11 | self.Request = Request 12 | self.Release = Release 13 | self.Retain = Retain 14 | self.Register = Register 15 | 16 | return self 17 | end 18 | 19 | function Gizmo:Draw(Transform: CFrame, Size: Vector3) 20 | local Ceive = self.Ceive 21 | 22 | if not Ceive.Enabled then 23 | return 24 | end 25 | 26 | local Box = self.Request("BoxHandleAdornment") 27 | Box.Color3 = self.Propertys.Color3 28 | Box.Transparency = self.Propertys.Transparency 29 | 30 | Box.CFrame = Transform 31 | Box.Size = Size 32 | Box.AlwaysOnTop = self.Propertys.AlwaysOnTop 33 | Box.ZIndex = 1 34 | Box.Adornee = Terrain 35 | Box.Parent = Terrain 36 | 37 | Ceive.ActiveInstances += 1 38 | 39 | self.Register(Box) 40 | self.Ceive.ScheduleCleaning() 41 | end 42 | 43 | function Gizmo:Create(Transform: CFrame, Size: Vector3) 44 | local PropertyTable = { 45 | Transform = Transform, 46 | Size = Size, 47 | AlwaysOnTop = self.Propertys.AlwaysOnTop, 48 | Transparency = self.Propertys.Transparency, 49 | Color3 = self.Propertys.Color3, 50 | Enabled = true, 51 | Destroy = false, 52 | } 53 | 54 | self.Retain(self, PropertyTable) 55 | 56 | return PropertyTable 57 | end 58 | 59 | function Gizmo:Update(PropertyTable) 60 | local Ceive = self.Ceive 61 | 62 | Ceive.PushProperty("AlwaysOnTop", PropertyTable.AlwaysOnTop) 63 | Ceive.PushProperty("Transparency", PropertyTable.Transparency) 64 | Ceive.PushProperty("Color3", PropertyTable.Color3) 65 | 66 | self:Draw(PropertyTable.Transform, PropertyTable.Size) 67 | end 68 | 69 | return Gizmo 70 | -------------------------------------------------------------------------------- /src-build/Dependencies/Debug/Gizmo/Gizmos/VolumeCone.luau: -------------------------------------------------------------------------------- 1 | local Terrain = workspace.Terrain 2 | 3 | local Gizmo = {} 4 | Gizmo.__index = Gizmo 5 | 6 | function Gizmo.Init(Ceive, Propertys, Request, Release, Retain, Register) 7 | local self = setmetatable({}, Gizmo) 8 | 9 | self.Ceive = Ceive 10 | self.Propertys = Propertys 11 | self.Request = Request 12 | self.Release = Release 13 | self.Retain = Retain 14 | self.Register = Register 15 | 16 | return self 17 | end 18 | 19 | function Gizmo:Draw(Transform: CFrame, Radius: number, Length: number) 20 | local Ceive = self.Ceive 21 | 22 | if not Ceive.Enabled then 23 | return 24 | end 25 | 26 | local Cone = self.Request("ConeHandleAdornment") 27 | Cone.Color3 = self.Propertys.Color3 28 | Cone.Transparency = self.Propertys.Transparency 29 | 30 | Cone.CFrame = Transform 31 | Cone.AlwaysOnTop = self.Propertys.AlwaysOnTop 32 | Cone.ZIndex = 1 33 | Cone.Height = Length 34 | Cone.Radius = Radius 35 | Cone.Adornee = Terrain 36 | Cone.Parent = Terrain 37 | 38 | Ceive.ActiveInstances += 1 39 | 40 | self.Register(Cone) 41 | self.Ceive.ScheduleCleaning() 42 | end 43 | 44 | function Gizmo:Create(Transform: CFrame, Radius: number, Length: number) 45 | local PropertyTable = { 46 | Transform = Transform, 47 | Radius = Radius, 48 | Length = Length, 49 | AlwaysOnTop = self.Propertys.AlwaysOnTop, 50 | Transparency = self.Propertys.Transparency, 51 | Color3 = self.Propertys.Color3, 52 | Enabled = true, 53 | Destroy = false, 54 | } 55 | 56 | self.Retain(self, PropertyTable) 57 | 58 | return PropertyTable 59 | end 60 | 61 | function Gizmo:Update(PropertyTable) 62 | local Ceive = self.Ceive 63 | 64 | Ceive.PushProperty("AlwaysOnTop", PropertyTable.AlwaysOnTop) 65 | Ceive.PushProperty("Transparency", PropertyTable.Transparency) 66 | Ceive.PushProperty("Color3", PropertyTable.Color3) 67 | 68 | self:Draw(PropertyTable.Transform, PropertyTable.Radius, PropertyTable.Length) 69 | end 70 | 71 | return Gizmo 72 | -------------------------------------------------------------------------------- /src-build/Dependencies/Debug/Gizmo/Gizmos/VolumeCylinder.luau: -------------------------------------------------------------------------------- 1 | local Terrain = workspace.Terrain 2 | 3 | local Gizmo = {} 4 | Gizmo.__index = Gizmo 5 | 6 | function Gizmo.Init(Ceive, Propertys, Request, Release, Retain, Register) 7 | local self = setmetatable({}, Gizmo) 8 | 9 | self.Ceive = Ceive 10 | self.Propertys = Propertys 11 | self.Request = Request 12 | self.Release = Release 13 | self.Retain = Retain 14 | self.Register = Register 15 | 16 | return self 17 | end 18 | 19 | function Gizmo:Draw(Transform: CFrame, Radius: number, Length: number, InnerRadius: number?, Angle: number?) 20 | local Ceive = self.Ceive 21 | 22 | if not Ceive.Enabled then 23 | return 24 | end 25 | 26 | local Cylinder = self.Request("CylinderHandleAdornment") 27 | Cylinder.Color3 = self.Propertys.Color3 28 | Cylinder.Transparency = self.Propertys.Transparency 29 | 30 | Cylinder.CFrame = Transform 31 | Cylinder.Height = Length 32 | Cylinder.Radius = Radius 33 | Cylinder.InnerRadius = InnerRadius or 0 34 | Cylinder.Angle = Angle or 360 35 | Cylinder.AlwaysOnTop = self.Propertys.AlwaysOnTop 36 | Cylinder.ZIndex = 1 37 | Cylinder.Adornee = Terrain 38 | Cylinder.Parent = Terrain 39 | 40 | Ceive.ActiveInstances += 1 41 | 42 | self.Register(Cylinder) 43 | self.Ceive.ScheduleCleaning() 44 | end 45 | 46 | function Gizmo:Create(Transform: CFrame, Radius: number, Length: number, InnerRadius: number?, Angle: number?) 47 | local PropertyTable = { 48 | Transform = Transform, 49 | Radius = Radius, 50 | Length = Length, 51 | InnerRadius = InnerRadius or 0, 52 | Angle = Angle or 360, 53 | AlwaysOnTop = self.Propertys.AlwaysOnTop, 54 | Transparency = self.Propertys.Transparency, 55 | Color3 = self.Propertys.Color3, 56 | Enabled = true, 57 | Destroy = false, 58 | } 59 | 60 | self.Retain(self, PropertyTable) 61 | 62 | return PropertyTable 63 | end 64 | 65 | function Gizmo:Update(PropertyTable) 66 | local Ceive = self.Ceive 67 | 68 | Ceive.PushProperty("AlwaysOnTop", PropertyTable.AlwaysOnTop) 69 | Ceive.PushProperty("Transparency", PropertyTable.Transparency) 70 | Ceive.PushProperty("Color3", PropertyTable.Color3) 71 | 72 | self:Draw(PropertyTable.Transform, PropertyTable.Radius, PropertyTable.Length, PropertyTable.InnerRadius, PropertyTable.Angle) 73 | end 74 | 75 | return Gizmo 76 | -------------------------------------------------------------------------------- /src-build/Dependencies/Debug/Gizmo/Gizmos/VolumeSphere.luau: -------------------------------------------------------------------------------- 1 | local Terrain = workspace.Terrain 2 | 3 | local Gizmo = {} 4 | Gizmo.__index = Gizmo 5 | 6 | function Gizmo.Init(Ceive, Propertys, Request, Release, Retain, Register) 7 | local self = setmetatable({}, Gizmo) 8 | 9 | self.Ceive = Ceive 10 | self.Propertys = Propertys 11 | self.Request = Request 12 | self.Release = Release 13 | self.Retain = Retain 14 | self.Register = Register 15 | 16 | return self 17 | end 18 | 19 | function Gizmo:Draw(Transform: CFrame, Radius: number) 20 | local Ceive = self.Ceive 21 | 22 | if not Ceive.Enabled then 23 | return 24 | end 25 | 26 | local Sphere = self.Request("SphereHandleAdornment") 27 | Sphere.Color3 = self.Propertys.Color3 28 | Sphere.Transparency = self.Propertys.Transparency 29 | 30 | Sphere.CFrame = Transform 31 | Sphere.Radius = Radius 32 | Sphere.AlwaysOnTop = self.Propertys.AlwaysOnTop 33 | Sphere.ZIndex = 1 34 | Sphere.Adornee = Terrain 35 | Sphere.Parent = Terrain 36 | 37 | Ceive.ActiveInstances += 1 38 | 39 | self.Register(Sphere) 40 | self.Ceive.ScheduleCleaning() 41 | end 42 | 43 | function Gizmo:Create(Transform: CFrame, Radius: number) 44 | local PropertyTable = { 45 | Transform = Transform, 46 | Radius = Radius, 47 | AlwaysOnTop = self.Propertys.AlwaysOnTop, 48 | Transparency = self.Propertys.Transparency, 49 | Color3 = self.Propertys.Color3, 50 | Enabled = true, 51 | Destroy = false, 52 | } 53 | 54 | self.Retain(self, PropertyTable) 55 | 56 | return PropertyTable 57 | end 58 | 59 | function Gizmo:Update(PropertyTable) 60 | local Ceive = self.Ceive 61 | 62 | Ceive.PushProperty("AlwaysOnTop", PropertyTable.AlwaysOnTop) 63 | Ceive.PushProperty("Transparency", PropertyTable.Transparency) 64 | Ceive.PushProperty("Color3", PropertyTable.Color3) 65 | 66 | self:Draw(PropertyTable.Transform, PropertyTable.Radius) 67 | end 68 | 69 | return Gizmo 70 | -------------------------------------------------------------------------------- /src-build/Dependencies/Debug/Gizmo/Gizmos/Wedge.luau: -------------------------------------------------------------------------------- 1 | local Gizmo = {} 2 | Gizmo.__index = Gizmo 3 | 4 | function Gizmo.Init(Ceive, Propertys, Request, Release, Retain) 5 | local self = setmetatable({}, Gizmo) 6 | 7 | self.Ceive = Ceive 8 | self.Propertys = Propertys 9 | self.Request = Request 10 | self.Release = Release 11 | self.Retain = Retain 12 | 13 | return self 14 | end 15 | 16 | function Gizmo:Draw(Transform: CFrame, Size: Vector3, DrawTriangles: boolean) 17 | local Ceive = self.Ceive 18 | 19 | if not Ceive.Enabled then 20 | return 21 | end 22 | 23 | local Position = Transform.Position 24 | local Uv = Transform.UpVector 25 | local Rv = Transform.RightVector 26 | local Lv = Transform.LookVector 27 | local sO2 = Size * 0.5 28 | local sUv = Uv * sO2.Y 29 | local sRv = Rv * sO2.X 30 | local sLv = Lv * sO2.Z 31 | 32 | local YTopLeft 33 | local YTopRight 34 | 35 | local ZBottomLeft 36 | local ZBottomRight 37 | 38 | local function CalculateYFace(lUv, lRv, lLv) 39 | local TopLeft = Position + (lUv - lRv + lLv) 40 | local TopRight = Position + (lUv + lRv + lLv) 41 | local BottomLeft = Position + (lUv - lRv - lLv) 42 | local BottomRight = Position + (lUv + lRv - lLv) 43 | 44 | YTopLeft = TopLeft 45 | YTopRight = TopRight 46 | 47 | Ceive.Ray:Draw(TopLeft, TopRight) 48 | Ceive.Ray:Draw(TopLeft, BottomLeft) 49 | 50 | Ceive.Ray:Draw(TopRight, BottomRight) 51 | if DrawTriangles ~= false then 52 | Ceive.Ray:Draw(TopRight, BottomLeft) 53 | end 54 | 55 | Ceive.Ray:Draw(BottomLeft, BottomRight) 56 | end 57 | 58 | local function CalculateZFace(lUv, lRv, lLv) 59 | local TopLeft = Position + (lUv - lRv + lLv) 60 | local TopRight = Position + (lUv + lRv + lLv) 61 | local BottomLeft = Position + (-lUv - lRv + lLv) 62 | local BottomRight = Position + (-lUv + lRv + lLv) 63 | 64 | ZBottomLeft = TopLeft 65 | ZBottomRight = TopRight 66 | 67 | Ceive.Ray:Draw(TopLeft, TopRight) 68 | Ceive.Ray:Draw(TopLeft, BottomLeft) 69 | 70 | Ceive.Ray:Draw(TopRight, BottomRight) 71 | if DrawTriangles ~= false then 72 | Ceive.Ray:Draw(TopRight, BottomLeft) 73 | end 74 | 75 | Ceive.Ray:Draw(BottomLeft, BottomRight) 76 | end 77 | 78 | CalculateYFace(-sUv, sRv, sLv) 79 | 80 | CalculateZFace(sUv, sRv, -sLv) 81 | 82 | Ceive.Ray:Draw(YTopLeft, ZBottomLeft) 83 | Ceive.Ray:Draw(YTopRight, ZBottomRight) 84 | if DrawTriangles ~= false then 85 | Ceive.Ray:Draw(YTopRight, ZBottomLeft) 86 | end 87 | end 88 | 89 | function Gizmo:Create(Transform: CFrame, Size: Vector3, DrawTriangles: boolean) 90 | local PropertyTable = { 91 | Transform = Transform, 92 | Size = Size, 93 | DrawTriangles = DrawTriangles, 94 | AlwaysOnTop = self.Propertys.AlwaysOnTop, 95 | Transparency = self.Propertys.Transparency, 96 | Color3 = self.Propertys.Color3, 97 | Enabled = true, 98 | Destroy = false, 99 | } 100 | 101 | self.Retain(self, PropertyTable) 102 | 103 | return PropertyTable 104 | end 105 | 106 | function Gizmo:Update(PropertyTable) 107 | local Ceive = self.Ceive 108 | 109 | Ceive.PushProperty("AlwaysOnTop", PropertyTable.AlwaysOnTop) 110 | Ceive.PushProperty("Transparency", PropertyTable.Transparency) 111 | Ceive.PushProperty("Color3", PropertyTable.Color3) 112 | 113 | self:Draw(PropertyTable.Transform, PropertyTable.Size, PropertyTable.DrawTriangles) 114 | end 115 | 116 | return Gizmo 117 | -------------------------------------------------------------------------------- /src-build/Dependencies/Debug/Gizmo/init.luau: -------------------------------------------------------------------------------- 1 | --[[ 2 | 3 | Acts as a wrapper for Gizmo.lua, respects IsStudio and AllowLiveGameDebug 4 | 5 | ]] 6 | 7 | local Dependencies = script.Parent.Parent 8 | 9 | local Config = require(Dependencies:WaitForChild("Config")) 10 | local Gizmo = require(script:WaitForChild("Gizmo")) 11 | 12 | local IsStudio = game:GetService("RunService"):IsStudio() 13 | local IsEnabled = IsStudio or Config.ALLOW_LIVE_GAME_DEBUG 14 | if IsEnabled then 15 | Gizmo.Init() 16 | end 17 | 18 | type ICeive = Gizmo.ICeive & { Init: nil } 19 | 20 | local Wrapper: ICeive = setmetatable({}, { 21 | __index = function(_, Index) 22 | if IsEnabled then 23 | return Gizmo[Index] 24 | else 25 | local GizmoFunctions = { 26 | SetStyle = true, 27 | AddDebrisInSeconds = true, 28 | PushProperty = true, 29 | PopProperty = true, 30 | AddDebrisInFrames = true, 31 | SetEnabled = true, 32 | DoCleaning = true, 33 | ScheduleCleaning = true, 34 | TweenProperties = true, 35 | } 36 | 37 | if GizmoFunctions[Index] then 38 | return function() end 39 | end 40 | 41 | return { 42 | Draw = function() end, 43 | Create = function() end, 44 | } 45 | end 46 | end, 47 | }) :: any 48 | 49 | return table.freeze(Wrapper) 50 | -------------------------------------------------------------------------------- /src-build/Dependencies/Debug/ImOverlay/init.luau: -------------------------------------------------------------------------------- 1 | -- TODO: Figure out the metatable stuff we should do here 2 | return require(script.CeiveImOverlay) 3 | -------------------------------------------------------------------------------- /src-build/Dependencies/DefaultObjectSettings.luau: -------------------------------------------------------------------------------- 1 | local FORCE_MULTIPLIER = 0.2 2 | 3 | return table.freeze({ 4 | Damping = 0.1, 5 | Stiffness = 0.2, 6 | Inertia = 0, 7 | Elasticity = 3, 8 | AnchorDepth = 0, 9 | 10 | AnchorsRotate = false, 11 | 12 | Constraint = "Spring", 13 | Force = Vector3.yAxis * FORCE_MULTIPLIER, 14 | Gravity = -Vector3.yAxis * 25, 15 | 16 | WindType = "Hybrid", 17 | MatchWorkspaceWind = true, 18 | WindInfluence = 1, 19 | WindStrength = 2, 20 | WindSpeed = 1, 21 | WindDirection = Vector3.xAxis, 22 | 23 | UpdateRate = 60, 24 | ActivationDistance = 45, 25 | ThrottleDistance = 15, 26 | }) 27 | -------------------------------------------------------------------------------- /src-build/Dependencies/Frustum.luau: -------------------------------------------------------------------------------- 1 | --!native 2 | local Dependencies = script.Parent 3 | local Config = require(Dependencies:WaitForChild("Config")) 4 | local Utilities = require(Dependencies:WaitForChild("Utilities")) 5 | 6 | local Class = {} 7 | 8 | function Class.GetCFrames(camera, distance) 9 | 10 | local cameraCFrame = camera.CFrame 11 | local cameraPos = cameraCFrame.Position 12 | local rightVec, upVec = cameraCFrame.RightVector, cameraCFrame.UpVector 13 | 14 | local distance2 = distance * 0.5 15 | local farPlaneHeight2 = math.tan(((camera.FieldOfView + 5) * 0.5) * 0.017453) * distance 16 | local farPlaneWidth2 = farPlaneHeight2 * (camera.ViewportSize.X / camera.ViewportSize.Y) 17 | local farPlaneCFrame = cameraCFrame * CFrame.new(0, 0, -distance) 18 | local farPlaneTopRight = farPlaneCFrame * Vector3.new(farPlaneWidth2, farPlaneHeight2, 0) 19 | local farPlaneBottomLeft = farPlaneCFrame * Vector3.new(-farPlaneWidth2, -farPlaneHeight2, 0) 20 | local farPlaneBottomRight = farPlaneCFrame * Vector3.new(farPlaneWidth2, -farPlaneHeight2, 0) 21 | 22 | local frustumCFrameInverse = (cameraCFrame * CFrame.new(0, 0, -distance2)):Inverse() 23 | 24 | local rightNormal = upVec:Cross(farPlaneBottomRight - cameraPos).Unit 25 | local leftNormal = upVec:Cross(farPlaneBottomLeft - cameraPos).Unit 26 | local topNormal = rightVec:Cross(cameraPos - farPlaneTopRight).Unit 27 | local bottomNormal = rightVec:Cross(cameraPos - farPlaneBottomRight).Unit 28 | 29 | return frustumCFrameInverse, farPlaneWidth2, farPlaneHeight2, distance2, rightNormal, leftNormal, topNormal, bottomNormal, cameraCFrame 30 | end 31 | 32 | function Class.InViewFrustum( 33 | point, 34 | frustumCFrameInverse, 35 | farPlaneWidth2, 36 | farPlaneHeight2, 37 | distance2, 38 | rightNormal, 39 | leftNormal, 40 | topNormal, 41 | bottomNormal, 42 | cameraCf 43 | ) 44 | 45 | 46 | local cameraPos = cameraCf.Position 47 | 48 | -- Check if point lies outside frustum OBB 49 | local relativeToOBB = frustumCFrameInverse * point 50 | if 51 | relativeToOBB.X > farPlaneWidth2 52 | or relativeToOBB.X < -farPlaneWidth2 53 | or relativeToOBB.Y > farPlaneHeight2 54 | or relativeToOBB.Y < -farPlaneHeight2 55 | or relativeToOBB.Z > distance2 56 | or relativeToOBB.Z < -distance2 57 | then 58 | 59 | return false 60 | end 61 | 62 | -- Check if point lies outside a frustum plane 63 | local lookToCell = point - cameraPos 64 | if rightNormal:Dot(lookToCell) < 0 or leftNormal:Dot(lookToCell) > 0 or topNormal:Dot(lookToCell) < 0 or bottomNormal:Dot(lookToCell) > 0 then 65 | 66 | return false 67 | end 68 | 69 | 70 | return true 71 | end 72 | 73 | function Class.ObjectInFrustum( 74 | Object, 75 | frustumCFrameInverse, 76 | farPlaneWidth2, 77 | farPlaneHeight2, 78 | distance2, 79 | rightNormal, 80 | leftNormal, 81 | topNormal, 82 | bottomNormal, 83 | cameraCFrame 84 | ) 85 | local CF = Object.CFrame 86 | local Size = Object.Size 87 | 88 | -- Allows for really big root parts to still be checked correctly 89 | local HalfFarPlane = Config.FAR_PLANE * 0.5 90 | local LinePosition = cameraCFrame.Position + (cameraCFrame.LookVector * HalfFarPlane) 91 | 92 | local Closest = Utilities.ClosestPointOnLine(LinePosition, cameraCFrame.LookVector, HalfFarPlane, CF.Position) 93 | local Inside, point = Utilities.ClosestPointInBox(CF, Size, Closest) 94 | 95 | if Inside then 96 | return true 97 | end 98 | 99 | if 100 | Class.InViewFrustum( 101 | point, 102 | frustumCFrameInverse, 103 | farPlaneWidth2, 104 | farPlaneHeight2, 105 | distance2, 106 | rightNormal, 107 | leftNormal, 108 | topNormal, 109 | bottomNormal, 110 | cameraCFrame 111 | ) 112 | then 113 | return true 114 | end 115 | 116 | return false 117 | end 118 | 119 | return Class 120 | -------------------------------------------------------------------------------- /src-build/Dependencies/Frustum.spec.luau: -------------------------------------------------------------------------------- 1 | local Frustum = require(script.Parent:WaitForChild("Frustum")) 2 | 3 | return function() 4 | local FakeCamera = { 5 | CFrame = CFrame.identity, 6 | FieldOfView = 70, 7 | ViewportSize = Vector2.new(1920, 1080), 8 | } 9 | 10 | local ReturnedCFrames = {} 11 | 12 | describe("Generates CFrames", function() 13 | local SolveStart = os.clock() 14 | local SolveEnd 15 | 16 | ReturnedCFrames = table.pack(Frustum.GetCFrames(FakeCamera, 500)) 17 | SolveEnd = os.clock() 18 | 19 | ReturnedCFrames["n"] = nil 20 | 21 | print(`Solved view frustum in {string.format("%.2f", (SolveEnd - SolveStart) * 1e6)}μs`) 22 | end) 23 | 24 | describe("Point In View", function() 25 | local CloseInView = Vector3.new(0, 0, -5) 26 | local FarPlaneView = Vector3.new(0, 0, -550) 27 | local OutOfView = Vector3.new(0, 0, 5) 28 | 29 | it("Close In View Point", function() 30 | expect(Frustum.InViewFrustum(CloseInView, table.unpack(ReturnedCFrames))).to.equal(true) 31 | end) 32 | 33 | it("Past FarPlane Point", function() 34 | expect(Frustum.InViewFrustum(FarPlaneView, table.unpack(ReturnedCFrames))).to.equal(false) 35 | end) 36 | 37 | it("Out Of View Point", function() 38 | expect(Frustum.InViewFrustum(OutOfView, table.unpack(ReturnedCFrames))).to.equal(false) 39 | end) 40 | end) 41 | 42 | describe("Object In View", function() 43 | local CloseFakeObject = { 44 | CFrame = CFrame.new(0, 0, -5), 45 | Size = Vector3.new(1, 1, 3), 46 | } 47 | 48 | local FarFakeObject = { 49 | CFrame = CFrame.new(0, 0, -550), 50 | Size = Vector3.new(1, 1, 3), 51 | } 52 | 53 | local OutOfViewFakeObject = { 54 | CFrame = CFrame.new(0, 0, 5), 55 | Size = Vector3.new(1, 1, 3), 56 | } 57 | 58 | it("Close In View Object", function() 59 | expect(Frustum.ObjectInFrustum(CloseFakeObject, table.unpack(ReturnedCFrames))).to.equal(true) 60 | end) 61 | 62 | it("Past FarPlane Object", function() 63 | expect(Frustum.ObjectInFrustum(FarFakeObject, table.unpack(ReturnedCFrames))).to.equal(false) 64 | end) 65 | 66 | it("Out Of View Object", function() 67 | expect(Frustum.ObjectInFrustum(OutOfViewFakeObject, table.unpack(ReturnedCFrames))).to.equal(false) 68 | end) 69 | end) 70 | end 71 | -------------------------------------------------------------------------------- /src-build/Dependencies/Iris/API.luau: -------------------------------------------------------------------------------- 1 | local Types = require(script.Parent.Types) 2 | 3 | return function(Iris: Types.Iris) 4 | -- basic wrapper for nearly every widget, saves space. 5 | local function wrapper(name: string): (arguments: Types.WidgetArguments?, states: Types.States?) -> Types.Widget 6 | return function(arguments: Types.WidgetArguments?, states: Types.States?): Types.Widget 7 | return Iris.Internal._Insert(name, arguments, states) 8 | end 9 | end 10 | 11 | --[[ 12 | ---------------------------- 13 | [SECTION] Window API 14 | ---------------------------- 15 | ]] 16 | 17 | Iris.Window = wrapper("Window") 18 | 19 | Iris.SetFocusedWindow = Iris.Internal.SetFocusedWindow 20 | 21 | Iris.Tooltip = wrapper("Tooltip") 22 | 23 | Iris.MenuBar = wrapper("MenuBar") 24 | 25 | Iris.Menu = wrapper("Menu") 26 | 27 | Iris.MenuItem = wrapper("MenuItem") 28 | 29 | Iris.MenuToggle = wrapper("MenuToggle") 30 | 31 | Iris.Separator = wrapper("Separator") 32 | 33 | Iris.Indent = wrapper("Indent") 34 | 35 | Iris.SameLine = wrapper("SameLine") 36 | 37 | Iris.Group = wrapper("Group") 38 | 39 | Iris.Text = wrapper("Text") 40 | 41 | Iris.TextWrapped = function(arguments: Types.WidgetArguments): Types.Widget 42 | arguments[2] = true 43 | return Iris.Internal._Insert("Text", arguments) 44 | end 45 | 46 | Iris.TextColored = function(arguments: Types.WidgetArguments): Types.Widget 47 | arguments[3] = arguments[2] 48 | arguments[2] = nil 49 | return Iris.Internal._Insert("Text", arguments) 50 | end 51 | 52 | Iris.SeparatorText = wrapper("SeparatorText") 53 | 54 | Iris.InputText = wrapper("InputText") 55 | 56 | Iris.Button = wrapper("Button") 57 | 58 | Iris.SmallButton = wrapper("SmallButton") 59 | 60 | Iris.Checkbox = wrapper("Checkbox") 61 | 62 | Iris.RadioButton = wrapper("RadioButton") 63 | 64 | Iris.Tree = wrapper("Tree") 65 | 66 | Iris.CollapsingHeader = wrapper("CollapsingHeader") 67 | 68 | Iris.InputNum = wrapper("InputNum") 69 | 70 | Iris.InputVector2 = wrapper("InputVector2") 71 | 72 | Iris.InputVector3 = wrapper("InputVector3") 73 | 74 | Iris.InputUDim = wrapper("InputUDim") 75 | 76 | Iris.InputUDim2 = wrapper("InputUDim2") 77 | 78 | Iris.InputRect = wrapper("InputRect") 79 | 80 | Iris.DragNum = wrapper("DragNum") 81 | 82 | Iris.DragVector2 = wrapper("DragVector2") 83 | 84 | Iris.DragVector3 = wrapper("DragVector3") 85 | 86 | Iris.DragUDim = wrapper("DragUDim") 87 | 88 | Iris.DragUDim2 = wrapper("DragUDim2") 89 | 90 | Iris.DragRect = wrapper("DragRect") 91 | 92 | Iris.InputColor3 = wrapper("InputColor3") 93 | 94 | Iris.InputColor4 = wrapper("InputColor4") 95 | 96 | Iris.SliderNum = wrapper("SliderNum") 97 | 98 | Iris.SliderVector2 = wrapper("SliderVector2") 99 | 100 | Iris.SliderVector3 = wrapper("SliderVector3") 101 | 102 | Iris.SliderUDim = wrapper("SliderUDim") 103 | 104 | Iris.SliderUDim2 = wrapper("SliderUDim2") 105 | 106 | Iris.SliderRect = wrapper("SliderRect") 107 | 108 | Iris.Selectable = wrapper("Selectable") 109 | 110 | Iris.Combo = wrapper("Combo") 111 | 112 | Iris.ComboArray = function(arguments: Types.WidgetArguments, states: Types.WidgetStates?, selectionArray: { any }) 113 | local defaultState 114 | if states == nil then 115 | defaultState = Iris.State(selectionArray[1]) 116 | else 117 | defaultState = states 118 | end 119 | local thisWidget = Iris.Internal._Insert("Combo", arguments, defaultState) 120 | local sharedIndex: Types.State = thisWidget.state.index 121 | for _, Selection in selectionArray do 122 | Iris.Internal._Insert("Selectable", { Selection, Selection }, { index = sharedIndex } :: Types.States) 123 | end 124 | Iris.End() 125 | 126 | return thisWidget 127 | end 128 | 129 | Iris.ComboEnum = function(arguments: Types.WidgetArguments, states: Types.WidgetStates?, enumType: Enum) 130 | local defaultState 131 | if states == nil then 132 | defaultState = Iris.State(enumType[1]) 133 | else 134 | defaultState = states 135 | end 136 | local thisWidget = Iris.Internal._Insert("Combo", arguments, defaultState) 137 | local sharedIndex = thisWidget.state.index 138 | for _, Selection in enumType:GetEnumItems() do 139 | Iris.Internal._Insert("Selectable", { Selection.Name, Selection }, { index = sharedIndex } :: Types.States) 140 | end 141 | Iris.End() 142 | 143 | return thisWidget 144 | end 145 | Iris.InputEnum = Iris.ComboEnum 146 | 147 | Iris.Table = wrapper("Table") 148 | 149 | Iris.NextColumn = function() 150 | Iris.Internal._GetParentWidget().RowColumnIndex += 1 151 | end 152 | 153 | Iris.SetColumnIndex = function(columnIndex: number) 154 | local ParentWidget: Types.Widget = Iris.Internal._GetParentWidget() 155 | assert(columnIndex >= ParentWidget.InitialNumColumns, "Iris.SetColumnIndex Argument must be in column range") 156 | ParentWidget.RowColumnIndex = math.floor(ParentWidget.RowColumnIndex / ParentWidget.InitialNumColumns) + (columnIndex - 1) 157 | end 158 | 159 | Iris.NextRow = function() 160 | -- sets column Index back to 0, increments Row 161 | local ParentWidget: Types.Widget = Iris.Internal._GetParentWidget() 162 | local InitialNumColumns: number = ParentWidget.InitialNumColumns 163 | local nextRow: number = math.floor((ParentWidget.RowColumnIndex + 1) / InitialNumColumns) * InitialNumColumns 164 | ParentWidget.RowColumnIndex = nextRow 165 | end 166 | end 167 | -------------------------------------------------------------------------------- /src-build/Dependencies/Iris/widgets/Button.luau: -------------------------------------------------------------------------------- 1 | local Types = require(script.Parent.Parent.Types) 2 | 3 | return function(Iris: Types.Internal, widgets: Types.WidgetUtility) 4 | local abstractButton = { 5 | hasState = false, 6 | hasChildren = false, 7 | Args = { 8 | ["Text"] = 1, 9 | }, 10 | Events = { 11 | ["clicked"] = widgets.EVENTS.click(function(thisWidget: Types.Widget) 12 | return thisWidget.Instance 13 | end), 14 | ["rightClicked"] = widgets.EVENTS.rightClick(function(thisWidget: Types.Widget) 15 | return thisWidget.Instance 16 | end), 17 | ["doubleClicked"] = widgets.EVENTS.doubleClick(function(thisWidget: Types.Widget) 18 | return thisWidget.Instance 19 | end), 20 | ["ctrlClicked"] = widgets.EVENTS.ctrlClick(function(thisWidget: Types.Widget) 21 | return thisWidget.Instance 22 | end), 23 | ["hovered"] = widgets.EVENTS.hover(function(thisWidget: Types.Widget) 24 | return thisWidget.Instance 25 | end), 26 | }, 27 | Generate = function(thisWidget: Types.Widget): TextButton 28 | local Button: TextButton = Instance.new("TextButton") 29 | Button.Size = UDim2.fromOffset(0, 0) 30 | Button.BackgroundColor3 = Iris._config.ButtonColor 31 | Button.BackgroundTransparency = Iris._config.ButtonTransparency 32 | Button.AutoButtonColor = false 33 | 34 | widgets.applyTextStyle(Button) 35 | Button.AutomaticSize = Enum.AutomaticSize.XY 36 | 37 | widgets.applyFrameStyle(Button) 38 | 39 | widgets.applyInteractionHighlights(Button, Button, { 40 | ButtonColor = Iris._config.ButtonColor, 41 | ButtonTransparency = Iris._config.ButtonTransparency, 42 | ButtonHoveredColor = Iris._config.ButtonHoveredColor, 43 | ButtonHoveredTransparency = Iris._config.ButtonHoveredTransparency, 44 | ButtonActiveColor = Iris._config.ButtonActiveColor, 45 | ButtonActiveTransparency = Iris._config.ButtonActiveTransparency, 46 | }) 47 | 48 | Button.ZIndex = thisWidget.ZIndex 49 | Button.LayoutOrder = thisWidget.ZIndex 50 | 51 | return Button 52 | end, 53 | Update = function(thisWidget: Types.Widget) 54 | local Button = thisWidget.Instance :: TextButton 55 | Button.Text = thisWidget.arguments.Text or "Button" 56 | end, 57 | Discard = function(thisWidget: Types.Widget) 58 | thisWidget.Instance:Destroy() 59 | end, 60 | } :: Types.WidgetClass 61 | widgets.abstractButton = abstractButton 62 | 63 | Iris.WidgetConstructor( 64 | "Button", 65 | widgets.extend(abstractButton, { 66 | Generate = function(thisWidget: Types.Widget): TextButton 67 | local Button: TextButton = abstractButton.Generate(thisWidget) 68 | Button.Name = "Iris_Button" 69 | 70 | return Button 71 | end, 72 | } :: Types.WidgetClass) 73 | ) 74 | 75 | Iris.WidgetConstructor( 76 | "SmallButton", 77 | widgets.extend(abstractButton, { 78 | Generate = function(thisWidget: Types.Widget): TextButton 79 | local SmallButton = abstractButton.Generate(thisWidget) :: TextButton 80 | SmallButton.Name = "Iris_SmallButton" 81 | 82 | local uiPadding: UIPadding = SmallButton.UIPadding 83 | uiPadding.PaddingLeft = UDim.new(0, 2) 84 | uiPadding.PaddingRight = UDim.new(0, 2) 85 | uiPadding.PaddingTop = UDim.new(0, 0) 86 | uiPadding.PaddingBottom = UDim.new(0, 0) 87 | 88 | return SmallButton 89 | end, 90 | } :: Types.WidgetClass) 91 | ) 92 | end 93 | -------------------------------------------------------------------------------- /src-build/Dependencies/Runtime.client.luau: -------------------------------------------------------------------------------- 1 | local Actor: Actor = script.Parent 2 | local RootObject 3 | local ColliderDescriptions 4 | local SmartboneModule 5 | local SmartboneClass 6 | 7 | local Setup = false 8 | 9 | local CONNECTIONS = {} 10 | 11 | local function c(Conn: RBXScriptConnection) 12 | table.insert(CONNECTIONS, Conn) 13 | end 14 | 15 | local function cleanup() 16 | for _, Conn: RBXScriptConnection in CONNECTIONS do 17 | Conn:Disconnect() 18 | end 19 | end 20 | 21 | local Bind 22 | Bind = Actor:BindToMessage("Setup", function(m_Object, m_ColliderDescriptions, m_SmartBone) 23 | RootObject = m_Object 24 | ColliderDescriptions = m_ColliderDescriptions 25 | SmartboneModule = m_SmartBone 26 | SmartboneClass = require(m_SmartBone) 27 | 28 | Setup = true 29 | 30 | Bind:Disconnect() 31 | end) 32 | 33 | repeat 34 | task.wait() 35 | until Setup 36 | 37 | local CollectionService = game:GetService("CollectionService") 38 | local RunService = game:GetService("RunService") 39 | local BonePhysics = SmartboneClass.new() 40 | local Dependencies = SmartboneModule.Dependencies 41 | local DebugUi = require(Dependencies.Debug.DebugUi) 42 | local Iris 43 | local Config = require(Dependencies.Config) 44 | local Utilities = require(Dependencies.Utilities) 45 | local ShouldDebug = RunService:IsStudio() or Config.ALLOW_LIVE_GAME_DEBUG 46 | local OverlayEvent = SmartboneModule:WaitForChild("OverlayEvent") 47 | 48 | local ForceDestroy = false 49 | 50 | -- So much work for such a basic debug tool 51 | local ImOverlay = { 52 | Begin = function(...) 53 | OverlayEvent:Fire("Begin", ...) 54 | end, 55 | End = function(...) 56 | OverlayEvent:Fire("End", ...) 57 | end, 58 | Text = function(...) 59 | OverlayEvent:Fire("Text", ...) 60 | end, 61 | } 62 | 63 | -- Frame counter for getting animatedworldcframe 64 | shared.FrameCounter = 0 65 | local FrameCounterOverflow = 131072 66 | 67 | if ShouldDebug then 68 | Iris = require(Dependencies.Iris) 69 | if not Iris.HasInit() then 70 | Iris = Iris.Init() 71 | end 72 | end 73 | 74 | Actor.Name = `{RootObject.Name} - {BonePhysics.ID}` 75 | 76 | BonePhysics:LoadObject(RootObject) 77 | 78 | for _, ColliderDescription in ColliderDescriptions do 79 | BonePhysics:LoadRawCollider(ColliderDescription[1], ColliderDescription[2]) 80 | end 81 | 82 | local DebugState 83 | 84 | if ShouldDebug then 85 | DebugState = { 86 | DRAW_BONE = Iris.State(false), 87 | DRAW_PHYSICAL_BONE = Iris.State(false), 88 | DRAW_ROOT_PART = Iris.State(false), 89 | DRAW_BOUNDING_BOX = Iris.State(false), 90 | DRAW_AXIS_LIMITS = Iris.State(false), 91 | DRAW_COLLIDERS = Iris.State(false), 92 | DRAW_COLLIDER_INFLUENCE = Iris.State(false), 93 | DRAW_COLLIDER_AWAKE = Iris.State(false), 94 | DRAW_COLLIDER_BROADPHASE = Iris.State(false), 95 | DRAW_FILL_COLLIDERS = Iris.State(false), 96 | DRAW_CONTACTS = Iris.State(false), 97 | DRAW_ROTATION_LIMITS = Iris.State(false), 98 | DRAW_ACCELERATION_INFO = Iris.State(false), 99 | } 100 | end 101 | 102 | -- ShouldDebug is just if we are in studio or not 103 | if ShouldDebug then 104 | Iris:Connect(function() 105 | if RootObject:GetAttribute("Debug") ~= nil then 106 | DebugUi(Iris, BonePhysics, DebugState) 107 | end 108 | end) 109 | end 110 | 111 | c(CollectionService:GetInstanceAddedSignal("SmartCollider"):Connect(function(Object: BasePart) 112 | if not Object:IsA("BasePart") then 113 | return 114 | end 115 | 116 | local ColliderKey = Object:GetAttribute("ColliderKey") 117 | local RootColliderKey = RootObject:GetAttribute("ColliderKey") 118 | 119 | if tostring(ColliderKey) ~= tostring(RootColliderKey) then 120 | return 121 | end 122 | 123 | local ColliderObject = Utilities.GetCollider(Object) 124 | 125 | BonePhysics:LoadRawCollider(ColliderObject, Object) 126 | end)) 127 | 128 | c(Actor:BindToMessage("Destroy", function() 129 | ForceDestroy = true 130 | end)) 131 | 132 | c(RunService.Heartbeat:ConnectParallel(function(deltaTime) 133 | shared.FrameCounter += 1 134 | 135 | if shared.FrameCounter > FrameCounterOverflow then 136 | shared.FrameCounter = 0 137 | end 138 | 139 | BonePhysics:StepBoneTrees(deltaTime) 140 | 141 | if BonePhysics.ShouldDestroy or ForceDestroy then 142 | BonePhysics:Destroy() 143 | 144 | task.synchronize() 145 | cleanup() 146 | Actor:Destroy() 147 | return 148 | end 149 | 150 | -- ShouldDebug is just if we are in studio or not 151 | if ShouldDebug then 152 | if RootObject:GetAttribute("Debug") ~= nil then 153 | task.synchronize() 154 | BonePhysics:DrawDebug( 155 | DebugState.DRAW_COLLIDERS:get(), 156 | DebugState.DRAW_CONTACTS:get(), 157 | DebugState.DRAW_PHYSICAL_BONE:get(), 158 | DebugState.DRAW_BONE:get(), 159 | DebugState.DRAW_AXIS_LIMITS:get(), 160 | DebugState.DRAW_ROOT_PART:get(), 161 | DebugState.DRAW_FILL_COLLIDERS:get(), 162 | DebugState.DRAW_COLLIDER_INFLUENCE:get(), 163 | DebugState.DRAW_COLLIDER_AWAKE:get(), 164 | DebugState.DRAW_COLLIDER_BROADPHASE:get(), 165 | DebugState.DRAW_BOUNDING_BOX:get(), 166 | DebugState.DRAW_ROTATION_LIMITS:get(), 167 | DebugState.DRAW_ACCELERATION_INFO:get() 168 | ) 169 | 170 | BonePhysics:DrawOverlay(ImOverlay) 171 | end 172 | end 173 | end)) 174 | -------------------------------------------------------------------------------- /src.project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "SmartBone2", 3 | "tree": { 4 | "$className": "DataModel", 5 | 6 | "ReplicatedStorage": { 7 | "SmartBone": { 8 | "$path": "src" 9 | } 10 | }, 11 | 12 | "StarterPlayer": { 13 | "StarterPlayerScripts": { 14 | "$path": "dev/client" 15 | } 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Components/Collision/Colliders/Box.luau: -------------------------------------------------------------------------------- 1 | local function SafeUnit(v3) 2 | if v3.Magnitude == 0 then 3 | return Vector3.zero 4 | end 5 | 6 | return v3.Unit 7 | end 8 | 9 | local function ClosestPointFunc(cframe, size, point) 10 | local rel = cframe:pointToObjectSpace(point) 11 | local sx, sy, sz = size.x, size.y, size.z 12 | local rx, ry, rz = rel.x, rel.y, rel.z 13 | 14 | -- constrain to within the box 15 | local cx = math.clamp(rx, -sx * 0.5, sx * 0.5) 16 | local cy = math.clamp(ry, -sy * 0.5, sy * 0.5) 17 | local cz = math.clamp(rz, -sz * 0.5, sz * 0.5) 18 | 19 | if not (cx == rx and cy == ry and cz == rz) then 20 | local closestPoint = cframe * Vector3.new(cx, cy, cz) 21 | local normal = SafeUnit(point - closestPoint) 22 | return false, closestPoint, normal 23 | end 24 | 25 | -- else, they are intersecting, find the surface the point is closest to 26 | 27 | local posX = rx - sx * 0.5 28 | local posY = ry - sy * 0.5 29 | local posZ = rz - sz * 0.5 30 | local negX = -rx - sx * 0.5 31 | local negY = -ry - sy * 0.5 32 | local negZ = -rz - sz * 0.5 33 | 34 | local max = math.max(posX, posY, posZ, negX, negY, negZ) 35 | if max == posX then 36 | local closestPoint = cframe * Vector3.new(sx * 0.5, ry, rz) 37 | return true, closestPoint, cframe.XVector 38 | elseif max == posY then 39 | local closestPoint = cframe * Vector3.new(rx, sy * 0.5, rz) 40 | return true, closestPoint, cframe.YVector 41 | elseif max == posZ then 42 | local closestPoint = cframe * Vector3.new(rx, ry, sz * 0.5) 43 | return true, closestPoint, cframe.ZVector 44 | elseif max == negX then 45 | local closestPoint = cframe * Vector3.new(-sx * 0.5, ry, rz) 46 | return true, closestPoint, -cframe.XVector 47 | elseif max == negY then 48 | local closestPoint = cframe * Vector3.new(rx, -sy * 0.5, rz) 49 | return true, closestPoint, -cframe.YVector 50 | elseif max == negZ then 51 | local closestPoint = cframe * Vector3.new(rx, ry, -sz * 0.5) 52 | return true, closestPoint, -cframe.ZVector 53 | end 54 | 55 | -- Shouldnt reach 56 | warn("CLOSEST POINT ON BOX FAIL") 57 | return false, cframe.Position, Vector3.zero 58 | end 59 | 60 | return function(BoxCFrame, BoxSize, Point, Radius) -- Sphere vs Box 61 | debug.profilebegin("Box Testing") 62 | local IsInside, ClosestPoint, Normal = ClosestPointFunc(BoxCFrame, BoxSize, Point) 63 | 64 | if IsInside then 65 | return IsInside, ClosestPoint, Normal 66 | end 67 | 68 | local DistanceToCp = (ClosestPoint - Point).Magnitude 69 | 70 | IsInside = (DistanceToCp < Radius) 71 | debug.profileend() 72 | return IsInside, ClosestPoint, Normal 73 | end 74 | -------------------------------------------------------------------------------- /src/Components/Collision/Colliders/Capsule.luau: -------------------------------------------------------------------------------- 1 | --!native 2 | local function SafeUnit(v3) 3 | if v3.Magnitude == 0 then 4 | return Vector3.zero 5 | end 6 | 7 | return v3.Unit 8 | end 9 | 10 | local function solve(p0, d0, len, p1) 11 | local v = p1 - p0 12 | local k = v:Dot(d0) 13 | k = math.clamp(k, -len, len) 14 | return p0 + d0 * k 15 | end 16 | 17 | local function ClosestPointFunc(cframe, length, radius, point) 18 | local l0 = solve(cframe.Position, cframe.UpVector, length * 0.5, point) 19 | 20 | local distance = (l0 - point).Magnitude 21 | local normal = SafeUnit(point - l0) 22 | local is_inside = (distance <= radius) 23 | 24 | return is_inside, l0 + (normal * radius), normal 25 | end 26 | 27 | return function(CapsuleCFrame, CapsuleSize, Point, Radius) 28 | debug.profilebegin("Capsule Testing") 29 | local CapsuleRadius = (CapsuleSize.Y < CapsuleSize.Z and CapsuleSize.Y or CapsuleSize.Z) * 0.5 30 | local CapsuleLength = CapsuleSize.X 31 | 32 | CapsuleCFrame *= CFrame.Angles(math.rad(90), -math.rad(90), 0) -- Optomize 33 | 34 | local IsInside, ClosestPoint, Normal = ClosestPointFunc(CapsuleCFrame, CapsuleLength, CapsuleRadius, Point) 35 | 36 | if IsInside then 37 | return IsInside, ClosestPoint, Normal 38 | end 39 | 40 | local DistanceToCp = (ClosestPoint - Point).Magnitude 41 | 42 | IsInside = (DistanceToCp < Radius) 43 | debug.profileend() 44 | return IsInside, ClosestPoint, Normal 45 | end 46 | -------------------------------------------------------------------------------- /src/Components/Collision/Colliders/Cylinder.luau: -------------------------------------------------------------------------------- 1 | --!native 2 | local function SafeUnit(v3) 3 | if v3.Magnitude == 0 then 4 | return Vector3.zero 5 | end 6 | 7 | return v3.Unit 8 | end 9 | 10 | local function solve(p0, d0, len, p1) 11 | local v = p1 - p0 12 | local k = v:Dot(d0) 13 | k = math.clamp(k, -len, len) 14 | return p0 + d0 * k, k 15 | end 16 | 17 | local function ProjectOnPlane(pos, normal, point) 18 | local d = point - pos 19 | local v_dot = d:Dot(normal) 20 | local v = point - v_dot * normal 21 | 22 | return v 23 | end 24 | 25 | local function ClosestPointFunc(cframe, size, point) 26 | local radius = (size.Y < size.Z and size.Y or size.Z) * 0.5 27 | local length = size.X * 0.5 28 | local l0, k = solve(cframe.Position, cframe.RightVector, length, point) 29 | 30 | local endPlane = cframe.Position + -cframe.RightVector * length 31 | local topPlane = cframe.Position + cframe.RightVector * length 32 | 33 | local endPlaneN = -cframe.RightVector 34 | local topPlaneN = cframe.RightVector 35 | 36 | local projEnd = ProjectOnPlane(endPlane, endPlaneN, point) 37 | local projTop = ProjectOnPlane(topPlane, topPlaneN, point) 38 | 39 | local function GetFinalProj(proj, o) 40 | local projDir = SafeUnit(proj - o) 41 | local projDistance = (proj - o).Magnitude 42 | return o + projDir * (projDistance < radius and projDistance or radius) 43 | end 44 | 45 | projEnd = GetFinalProj(projEnd, endPlane) 46 | projTop = GetFinalProj(projTop, topPlane) 47 | 48 | local radiusDistance = (l0 - point).Magnitude 49 | local radiusNormal = SafeUnit(point - l0) 50 | local radiusInside = (radiusDistance <= radius) 51 | local radiusPosition = l0 + (radiusNormal * radius) 52 | 53 | local d0 = (projTop - point).Magnitude 54 | local d1 = (projEnd - point).Magnitude 55 | local d2 = (radiusPosition - point).Magnitude 56 | 57 | local d = math.min(d0, d1, d2) 58 | 59 | if k == length or d == d0 then 60 | local dot = SafeUnit(point - projTop):Dot(topPlaneN) 61 | return dot < 0, projTop, topPlaneN 62 | elseif k == -length or d == d1 then 63 | local dot = SafeUnit(point - projEnd):Dot(endPlaneN) 64 | return dot < 0, projEnd, endPlaneN 65 | end 66 | 67 | return radiusInside, radiusPosition, radiusNormal 68 | end 69 | 70 | return function(CylinderCFrame, CylinderSize, Point, Radius) -- IsInside, PushPosition, PushNormal 71 | debug.profilebegin("Cylinder Testing") 72 | local IsInside, PushPosition, PushNormal = ClosestPointFunc(CylinderCFrame, CylinderSize, Point) 73 | 74 | if IsInside then 75 | return IsInside, PushPosition, PushNormal 76 | end 77 | 78 | local PointDistance = (PushPosition - Point).Magnitude 79 | 80 | IsInside = PointDistance < Radius 81 | debug.profileend() 82 | return IsInside, PushPosition, PushNormal 83 | end 84 | -------------------------------------------------------------------------------- /src/Components/Collision/Colliders/Sphere.luau: -------------------------------------------------------------------------------- 1 | --!native 2 | local function SafeUnit(v3) 3 | if v3.Magnitude == 0 then 4 | return Vector3.zero 5 | end 6 | 7 | return v3.Unit 8 | end 9 | 10 | local function ClosestPointFunc(position, radius, point) 11 | local distance = (position - point).Magnitude 12 | local normal = SafeUnit(point - position) 13 | local is_inside = (distance <= radius) 14 | 15 | return is_inside, position + (normal * radius), normal 16 | end 17 | 18 | return function(Sphere0Point, Sphere0Radius, Sphere1Point, Sphere1Radius) 19 | debug.profilebegin("Sphere Testing") 20 | Sphere0Point = Sphere0Point.Position 21 | Sphere0Radius = math.min(Sphere0Radius.X, Sphere0Radius.Y, Sphere0Radius.Z) * 0.5 22 | 23 | local IsInside, ClosestPoint, Normal = ClosestPointFunc(Sphere0Point, Sphere0Radius, Sphere1Point) 24 | 25 | if IsInside then 26 | return IsInside, ClosestPoint, Normal 27 | end 28 | 29 | local DistanceToCp = (ClosestPoint - Sphere1Point).Magnitude 30 | 31 | IsInside = (DistanceToCp < Sphere1Radius) 32 | debug.profileend() 33 | return IsInside, ClosestPoint, Normal 34 | end 35 | -------------------------------------------------------------------------------- /src/Components/Collision/Colliders/Triangle.luau: -------------------------------------------------------------------------------- 1 | --[[ 2 | 3 | !! THIS IS NOT MEANT TO BE USED AS A COLLIDER SOLVER, ITS MEANT TO BE USED IN OTHER COLLIDER SOLVERS !! 4 | 5 | ]] 6 | 7 | --!native 8 | local dot = Vector3.new().Dot 9 | local cross = Vector3.new().Cross 10 | local clamp = math.clamp 11 | 12 | local function SafeUnit(v3) 13 | if v3.Magnitude == 0 then 14 | return Vector3.zero 15 | end 16 | 17 | return v3.Unit 18 | end 19 | 20 | local function ClosestPointOnLineSegment(A, B, P) 21 | local AB = B - A 22 | local t = dot(P - A, AB) / dot(AB, AB) 23 | return A + clamp(t, 0, 1) * AB 24 | end 25 | 26 | local function ProjectOnPlane(pos, normal, point) 27 | local d = point - pos 28 | local v_dot = d:Dot(normal) 29 | local v = point - v_dot * normal 30 | 31 | return v 32 | end 33 | 34 | local function SameSide(p1, p2, a, b) 35 | local cp1 = cross(b - a, p1 - a) 36 | local cp2 = cross(b - a, p2 - a) 37 | if dot(cp1, cp2) >= 0 then 38 | return true 39 | else 40 | return false 41 | end 42 | end 43 | 44 | local function PointInTriangle(p, a, b, c) 45 | if SameSide(p, a, b, c) and SameSide(p, b, a, c) and SameSide(p, c, a, b) then 46 | return true 47 | end 48 | 49 | return false 50 | end 51 | 52 | local function ClosestPointOnTri(v0, v1, v2, point) -- ClosestPoint, Normal 53 | debug.profilebegin("Triangle") 54 | local Edge0 = ClosestPointOnLineSegment(v0, v1, point) 55 | local Edge1 = ClosestPointOnLineSegment(v1, v2, point) 56 | local Edge2 = ClosestPointOnLineSegment(v2, v0, point) 57 | 58 | local Normal = SafeUnit(cross(v1 - v0, v2 - v0)) 59 | local Center = (v0 + v1 + v2) * 0.3333 60 | local Projected = ProjectOnPlane(Center, Normal, point) 61 | 62 | if PointInTriangle(point, v0, v1, v2) then 63 | debug.profileend() 64 | return Projected, Normal 65 | end 66 | 67 | local d0 = (Edge0 - point).Magnitude 68 | local d1 = (Edge1 - point).Magnitude 69 | local d2 = (Edge2 - point).Magnitude 70 | 71 | local d = math.min(d0, d1, d2) 72 | 73 | if d == d0 then 74 | debug.profileend() 75 | return Edge0, Normal 76 | elseif d == d1 then 77 | debug.profileend() 78 | return Edge1, Normal 79 | elseif d == d2 then 80 | debug.profileend() 81 | return Edge2, Normal 82 | end 83 | 84 | debug.profileend() 85 | return point, Normal 86 | end 87 | 88 | return ClosestPointOnTri 89 | -------------------------------------------------------------------------------- /src/Components/Constraints/AxisConstraint.luau: -------------------------------------------------------------------------------- 1 | local function SafeUnit(v3) 2 | if v3.Magnitude == 0 then 3 | return Vector3.zero 4 | end 5 | 6 | return v3.Unit 7 | end 8 | 9 | local inf = math.huge 10 | 11 | return function(self, Position, LastPosition, RootCFrame) 12 | debug.profilebegin("Axis Constraint") 13 | local RootOffset = RootCFrame:Inverse() * Position 14 | 15 | local X = RootOffset.X 16 | local Y = RootOffset.Y 17 | local Z = RootOffset.Z 18 | 19 | local XLimit = self.XAxisLimits 20 | local YLimit = self.YAxisLimits 21 | local ZLimit = self.ZAxisLimits 22 | 23 | local XLock = self.AxisLocked[1] and 0 or 1 24 | local YLock = self.AxisLocked[2] and 0 or 1 25 | local ZLock = self.AxisLocked[3] and 0 or 1 26 | 27 | -- Most bones probably wont have an axis limit, this allows us to skip all the other stuff 28 | if XLimit.Min == -inf and XLimit.Max == inf and YLimit.Min == -inf and YLimit.Max == inf and ZLimit.Min == -inf and ZLimit.Max == inf then 29 | if XLock == 1 and YLock == 1 and ZLock == 1 then 30 | debug.profileend() 31 | return Position 32 | else 33 | return RootCFrame * Vector3.new(X * XLock, Y * YLock, Z * ZLock) 34 | end 35 | end 36 | 37 | -- If our radius is > than the diff between min and max 38 | -- We do this because its faster than math.min() ¯\_(ツ)_/¯ 39 | local XMin = XLimit.Min + self.Radius 40 | local XMax = XMin <= (XLimit.Max - self.Radius) and XLimit.Max - self.Radius or XMin 41 | 42 | local YMin = YLimit.Min + self.Radius 43 | local YMax = YMin <= (YLimit.Max - self.Radius) and YLimit.Max - self.Radius or YMin 44 | 45 | local ZMin = ZLimit.Min + self.Radius 46 | local ZMax = ZMin <= (ZLimit.Max - self.Radius) and ZLimit.Max - self.Radius or ZMin 47 | 48 | X = X < XMin and XMin or (X > XMax and XMax or X) 49 | Y = Y < YMin and YMin or (Y > YMax and YMax or Y) 50 | Z = Z < ZMin and ZMin or (Z > ZMax and ZMax or Z) 51 | 52 | X *= XLock 53 | Y *= YLock 54 | Z *= ZLock 55 | 56 | local WorldSpace = RootCFrame * Vector3.new(X, Y, Z) 57 | 58 | Position = WorldSpace 59 | 60 | local XAxis = RootCFrame.RightVector 61 | local YAxis = RootCFrame.UpVector 62 | local ZAxis = RootCFrame.LookVector 63 | 64 | local DifferenceDirection = SafeUnit(Position - LastPosition) 65 | 66 | -- Remove our velocity on the vectors we collided with, stops any weird jittering. 67 | if X ~= RootOffset.X then 68 | local Normal = XAxis:Dot(DifferenceDirection) < 0 and -XAxis or XAxis 69 | self:ClipVelocity(Position, Normal) 70 | end 71 | 72 | if Y ~= RootOffset.Y then 73 | local Normal = YAxis:Dot(DifferenceDirection) < 0 and -YAxis or YAxis 74 | self:ClipVelocity(Position, Normal) 75 | end 76 | 77 | if Z ~= RootOffset.Z then 78 | local Normal = ZAxis:Dot(DifferenceDirection) > 0 and -ZAxis or ZAxis 79 | self:ClipVelocity(Position, Normal) 80 | end 81 | debug.profileend() 82 | 83 | return Position 84 | end 85 | -------------------------------------------------------------------------------- /src/Components/Constraints/AxisConstraint.spec.luau: -------------------------------------------------------------------------------- 1 | local AxisConstraint = require(script.Parent:WaitForChild("AxisConstraint")) 2 | 3 | return function() 4 | local Bone = { 5 | Radius = 0, 6 | XAxisLimits = NumberRange.new(-math.huge, math.huge), 7 | YAxisLimits = NumberRange.new(-math.huge, math.huge), 8 | ZAxisLimits = NumberRange.new(-math.huge, math.huge), 9 | AxisLocked = { false, false, false }, 10 | ClipVelocity = function() end, 11 | } 12 | 13 | afterEach(function() 14 | Bone.AxisLocked = { false, false, false } 15 | end) 16 | 17 | describe("Axis Lock", function() 18 | it("Should lock X Axis", function() 19 | Bone.AxisLocked = { true, false, false } 20 | 21 | local Result = AxisConstraint(Bone, Vector3.new(-10, 0, 0), Vector3.zero, CFrame.identity) 22 | 23 | expect(Result.X).to.equal(0) 24 | end) 25 | 26 | it("Should lock Y Axis", function() 27 | Bone.AxisLocked = { false, true, false } 28 | 29 | local Result = AxisConstraint(Bone, Vector3.new(0, -10, 0), Vector3.zero, CFrame.identity) 30 | 31 | expect(Result.Y).to.equal(0) 32 | end) 33 | 34 | it("Should lock Z Axis", function() 35 | Bone.AxisLocked = { false, false, true } 36 | 37 | local Result = AxisConstraint(Bone, Vector3.new(0, 0, -10), Vector3.zero, CFrame.identity) 38 | 39 | expect(Result.Z).to.equal(0) 40 | end) 41 | end) 42 | 43 | describe("Axis Limit", function() 44 | describe("Should limit X Axis", function() 45 | it("Min Limit", function() 46 | Bone.XAxisLimits = NumberRange.new(-5, math.huge) 47 | 48 | local Result = AxisConstraint(Bone, Vector3.new(-10, 0, 0), Vector3.zero, CFrame.identity) 49 | 50 | expect(Result.X).to.equal(-5) 51 | end) 52 | 53 | it("Max Limit", function() 54 | Bone.XAxisLimits = NumberRange.new(-math.huge, 5) 55 | 56 | local Result = AxisConstraint(Bone, Vector3.new(10, 0, 0), Vector3.zero, CFrame.identity) 57 | 58 | expect(Result.X).to.equal(5) 59 | end) 60 | end) 61 | 62 | describe("Should limit Y Axis", function() 63 | it("Min Limit", function() 64 | Bone.YAxisLimits = NumberRange.new(-5, math.huge) 65 | 66 | local Result = AxisConstraint(Bone, Vector3.new(0, -10, 0), Vector3.zero, CFrame.identity) 67 | 68 | expect(Result.Y).to.equal(-5) 69 | end) 70 | 71 | it("Max Limit", function() 72 | Bone.YAxisLimits = NumberRange.new(-math.huge, 5) 73 | 74 | local Result = AxisConstraint(Bone, Vector3.new(0, 10, 0), Vector3.zero, CFrame.identity) 75 | 76 | expect(Result.Y).to.equal(5) 77 | end) 78 | end) 79 | 80 | describe("Should limit Z Axis", function() 81 | it("Min Limit", function() 82 | Bone.ZAxisLimits = NumberRange.new(-5, math.huge) 83 | 84 | local Result = AxisConstraint(Bone, Vector3.new(0, 0, -10), Vector3.zero, CFrame.identity) 85 | 86 | expect(Result.Z).to.equal(-5) 87 | end) 88 | 89 | it("Max Limit", function() 90 | Bone.ZAxisLimits = NumberRange.new(-math.huge, 5) 91 | 92 | local Result = AxisConstraint(Bone, Vector3.new(0, 0, 10), Vector3.zero, CFrame.identity) 93 | 94 | expect(Result.Z).to.equal(5) 95 | end) 96 | end) 97 | end) 98 | end 99 | -------------------------------------------------------------------------------- /src/Components/Constraints/CollisionConstraint.luau: -------------------------------------------------------------------------------- 1 | return function(self, Position, Colliders) 2 | debug.profilebegin("Collision Constraint") 3 | local Collisions = {} 4 | local HitParts = {} 5 | 6 | for _, Collider in Colliders do 7 | local ColliderCollisions = Collider:GetCollisions(Position, self.Radius) 8 | 9 | if #ColliderCollisions > 0 then 10 | table.insert(HitParts, Collider:GetObject()) 11 | end 12 | 13 | for _, Collision in ColliderCollisions do 14 | table.insert(Collisions, Collision) 15 | end 16 | end 17 | 18 | for _, Collision in Collisions do 19 | Position = Collision.ClosestPoint + (Collision.Normal * self.Radius) 20 | -- self:ClipVelocity(Position, Collision.Normal) -- This causes some weird glitching issues, not sure why tbh 21 | end 22 | 23 | self.CollisionsData = Collisions 24 | self.CollisionHits = HitParts 25 | debug.profileend() 26 | 27 | return Position 28 | end 29 | -------------------------------------------------------------------------------- /src/Components/Constraints/DistanceConstraint.luau: -------------------------------------------------------------------------------- 1 | local function SafeUnit(v3) 2 | if v3.Magnitude == 0 then 3 | return Vector3.zero 4 | end 5 | 6 | return v3.Unit 7 | end 8 | 9 | return function(self, Position, BoneTree) 10 | debug.profilebegin("Distance Constraint") 11 | local ParentBone = BoneTree.Bones[self.ParentIndex] 12 | 13 | if ParentBone then 14 | local RestLength = self.FreeLength 15 | local BoneDirection = SafeUnit(Position - ParentBone.Position) 16 | 17 | local RestPosition = ParentBone.Position + (BoneDirection * RestLength) 18 | 19 | debug.profileend() 20 | return RestPosition 21 | end 22 | 23 | debug.profileend() 24 | return 25 | end 26 | -------------------------------------------------------------------------------- /src/Components/Constraints/DistanceContraint.spec.luau: -------------------------------------------------------------------------------- 1 | local DistanceConstraint = require(script.Parent:WaitForChild("DistanceConstraint")) 2 | 3 | local function CreateBone(Position, FreeLength, Parent) 4 | return { 5 | Position = Position, 6 | FreeLength = FreeLength, 7 | ParentIndex = Parent, 8 | } 9 | end 10 | 11 | return function() 12 | local BoneTree = { 13 | Bones = { 14 | CreateBone(Vector3.zero, 3, 0), 15 | CreateBone(Vector3.yAxis, 3, 1), 16 | }, 17 | } 18 | 19 | describe("Distance Constraint", function() 20 | local Bone = BoneTree.Bones[2] 21 | 22 | local function Callback() 23 | local NewPosition = DistanceConstraint(Bone, Bone.Position, BoneTree) 24 | 25 | expect(NewPosition.Magnitude).to.equal(Bone.FreeLength) 26 | 27 | Bone.Position = NewPosition 28 | end 29 | 30 | for i = 1, 10 do 31 | it(`Should limit to {Bone.FreeLength} studs #{i}`, Callback) 32 | Bone.FreeLength = math.random(1, 20) 33 | end 34 | end) 35 | end 36 | -------------------------------------------------------------------------------- /src/Components/Constraints/FrictionConstraint.luau: -------------------------------------------------------------------------------- 1 | return function(self, Position, LastPosition) 2 | local Alpha = 1 - self.Friction 3 | 4 | return LastPosition:Lerp(Position, Alpha) 5 | end 6 | -------------------------------------------------------------------------------- /src/Components/Constraints/RopeConstraint.luau: -------------------------------------------------------------------------------- 1 | local function SafeUnit(v3) 2 | if v3.Magnitude == 0 then 3 | return Vector3.zero 4 | end 5 | 6 | return v3.Unit 7 | end 8 | 9 | return function(self, Position, BoneTree) 10 | debug.profilebegin("Rope Constraint") 11 | local ParentBone = BoneTree.Bones[self.ParentIndex] 12 | 13 | if ParentBone then 14 | local RestLength = self.FreeLength 15 | local BoneSub = (Position - ParentBone.Position) 16 | local BoneDirection = SafeUnit(BoneSub) 17 | local BoneDistance = BoneSub.Magnitude < RestLength and BoneSub.Magnitude or RestLength 18 | 19 | local RestPosition = ParentBone.Position + (BoneDirection * BoneDistance) 20 | 21 | debug.profileend() 22 | return RestPosition 23 | end 24 | 25 | debug.profileend() 26 | return 27 | end 28 | -------------------------------------------------------------------------------- /src/Components/Constraints/RopeConstraint.spec.luau: -------------------------------------------------------------------------------- 1 | local RopeConstraint = require(script.Parent:WaitForChild("RopeConstraint")) 2 | 3 | local function CreateBone(Position, FreeLength, Parent) 4 | return { 5 | Position = Position, 6 | FreeLength = FreeLength, 7 | ParentIndex = Parent, 8 | } 9 | end 10 | 11 | return function() 12 | local BoneTree = { 13 | Bones = { 14 | CreateBone(Vector3.zero, 3, 0), 15 | CreateBone(Vector3.yAxis * 10, 3, 1), 16 | }, 17 | } 18 | 19 | describe("Rope Constraint", function() 20 | local Bone = BoneTree.Bones[2] 21 | local i = 0 22 | 23 | local ReRun 24 | 25 | local function LimitCallback() 26 | local NewPosition = RopeConstraint(Bone, Bone.Position, BoneTree) 27 | 28 | expect(NewPosition.Magnitude).to.equal(Bone.FreeLength) 29 | 30 | Bone.FreeLength = math.random(1, 20) 31 | 32 | ReRun() 33 | end 34 | 35 | local function SameCallback() 36 | local NewPosition = RopeConstraint(Bone, Bone.Position, BoneTree) 37 | 38 | expect(NewPosition.Magnitude).to.equal(Bone.Position.Magnitude) 39 | 40 | Bone.FreeLength = math.random(1, 20) 41 | 42 | ReRun() 43 | end 44 | 45 | ReRun = function() 46 | if i >= 10 then 47 | return 48 | end 49 | 50 | i += 1 51 | 52 | if Bone.Position.Magnitude < Bone.FreeLength then 53 | it(`Should stay the same #{i}`, SameCallback) 54 | else 55 | it(`Should limit to {Bone.FreeLength} studs #{i}`, LimitCallback) 56 | end 57 | end 58 | 59 | ReRun() 60 | end) 61 | end 62 | -------------------------------------------------------------------------------- /src/Components/Constraints/RotationConstraint.luau: -------------------------------------------------------------------------------- 1 | local function SafeUnit(v3) 2 | if v3.Magnitude == 0 then 3 | return Vector3.zero 4 | end 5 | 6 | return v3.Unit 7 | end 8 | 9 | return function(self, Position, BoneTree) 10 | debug.profilebegin("Rotation Constraint") 11 | local ParentIndex = self.ParentIndex 12 | local ParentBone = BoneTree.Bones[ParentIndex] 13 | 14 | if not ParentBone then 15 | debug.profileend() 16 | return Position 17 | end 18 | 19 | local ParentBoneLimit = ParentBone.RotationLimit 20 | 21 | if ParentBoneLimit >= 180 then 22 | debug.profileend() 23 | return Position 24 | end 25 | 26 | local GrandParentBone = BoneTree.Bones[ParentBone.ParentIndex] 27 | 28 | if not GrandParentBone then 29 | debug.profileend() 30 | return Position 31 | end 32 | 33 | local ParentBonePosition = ParentBone.Position 34 | local DefaultDirection = SafeUnit(ParentBone.Position - GrandParentBone.Position) 35 | 36 | local DistanceToParent = (Position - ParentBonePosition).Magnitude 37 | local DirectionToSelf = SafeUnit(Position - ParentBonePosition) 38 | 39 | if ParentBoneLimit <= 0 then 40 | debug.profileend() 41 | return ParentBonePosition + DefaultDirection * DistanceToParent 42 | end 43 | 44 | local RotationLimit = math.rad(self.RotationLimit) 45 | local VectorAngle = math.acos(DefaultDirection:Dot(DirectionToSelf)) 46 | local LimitedVector 47 | 48 | if VectorAngle >= RotationLimit then 49 | local Cross = SafeUnit(DefaultDirection:Cross(DirectionToSelf)) 50 | LimitedVector = CFrame.fromAxisAngle(Cross, RotationLimit) * DefaultDirection 51 | else 52 | LimitedVector = DirectionToSelf 53 | end 54 | 55 | if LimitedVector ~= LimitedVector then -- Somewhat hacky fix 56 | LimitedVector = DefaultDirection 57 | end 58 | 59 | Position = ParentBonePosition + LimitedVector * DistanceToParent 60 | 61 | debug.profileend() 62 | return Position 63 | end 64 | -------------------------------------------------------------------------------- /src/Components/Constraints/SpringConstraint.luau: -------------------------------------------------------------------------------- 1 | --!native 2 | return function(self, Position, RestPosition, BoneTree, Delta) 3 | debug.profilebegin("Spring Constraint") 4 | 5 | local Settings = BoneTree.Settings 6 | local Stiffness = Settings.Stiffness 7 | local Elasticity = Settings.Elasticity 8 | 9 | local ParentBone = BoneTree.Bones[self.ParentIndex] 10 | 11 | if ParentBone then 12 | local RestLength = self.FreeLength 13 | 14 | if Stiffness > 0 or Elasticity > 0 then 15 | local ParentBoneCFrame = CFrame.new(ParentBone.Position) * ParentBone.TransformOffset.Rotation 16 | RestPosition = RestPosition or (ParentBoneCFrame * CFrame.new(self.LocalTransformOffset.Position)).Position 17 | 18 | local ElasticDifference = RestPosition - Position 19 | Position += ElasticDifference * (Elasticity * Delta) 20 | 21 | if Stiffness > 0 then 22 | local StiffDifference = RestPosition - Position 23 | local Length = StiffDifference.Magnitude 24 | local MaxLength = RestLength * (1 - Stiffness) * 2 25 | if Length > MaxLength then 26 | Position += StiffDifference * ((Length - MaxLength) / Length) 27 | end 28 | end 29 | end 30 | 31 | local Difference = ParentBone.Position - Position 32 | local Length = Difference.Magnitude 33 | if Length > 0 then 34 | Position += Difference * ((Length - RestLength) / Length) 35 | end 36 | end 37 | debug.profileend() 38 | 39 | return Position 40 | end 41 | -------------------------------------------------------------------------------- /src/Dependencies/Config.luau: -------------------------------------------------------------------------------- 1 | -- Configuration 2 | 3 | return { 4 | VERSION = "0.5.0", 5 | -- Controls if when an object is out of activation distance / fov if its bones should be sent back to their rest location. 6 | RESET_TRANSFORM_ON_SKIP = true, 7 | -- Wouldn't recommend enabling, controls if we should wait after each collider setup. 8 | YIELD_ON_COLLIDER_GATHER = false, 9 | -- Allows for debug tools out of studio 10 | ALLOW_LIVE_GAME_DEBUG = false, 11 | -- Maximum distance for field of view checks, if an object is out of this distance its skipped regardless of activation distance. 12 | FAR_PLANE = 500, 13 | -- Frequency of which we do frustum checks, 1 being every frame, 2 being every other frame, 3 being every 3rd frame and so on. 14 | FRUSTUM_FREQ = 2, 15 | -- Debug info in output, can lag the game. 16 | LOG_VERBOSE = false, 17 | -- Controls if we should reset bone positions when .Stop() is called 18 | RESET_BONE_ON_DESTROY = true, 19 | -- Enable or disable the startup print 20 | STARTUP_PRINT_ENABLED = true, 21 | -- Overlay config, not meant for end users 22 | DEBUG_OVERLAY_ENABLED = false, -- enable or disable when debug is enabled 23 | DEBUG_OVERLAY_TREE = true, -- enable tree debug 24 | DEBUG_OVERLAY_TREE_INFO = false, 25 | DEBUG_OVERLAY_TREE_OBJECTS = false, 26 | DEBUG_OVERLAY_TREE_NUMERICS = false, 27 | DEBUG_OVERLAY_TREE_OFFSET = 0, -- how offset into the roots we should be 28 | DEBUG_OVERLAY_MAX_TREES = 5, -- -1 for no max 29 | DEBUG_OVERLAY_BONE = true, -- enable bone debug info 30 | DEBUG_OVERLAY_BONE_OFFSET = 0, -- how offset into the bone tree we should be 31 | DEBUG_OVERLAY_MAX_BONES = -1, -- -1 for no max 32 | DEBUG_OVERLAY_BONE_INFO = false, 33 | DEBUG_OVERLAY_BONE_NUMERICS = false, 34 | DEBUG_OVERLAY_BONE_CONSTRAIN = false, 35 | DEBUG_OVERLAY_BONE_WELD = true, 36 | DEBUG_OVERLAY_BONE_FORCES = true, 37 | } 38 | -------------------------------------------------------------------------------- /src/Dependencies/Debug/Gizmo/Gizmos/Arrow.luau: -------------------------------------------------------------------------------- 1 | local Gizmo = {} 2 | Gizmo.__index = Gizmo 3 | 4 | function Gizmo.Init(Ceive, Propertys, Request, Release, Retain) 5 | local self = setmetatable({}, Gizmo) 6 | 7 | self.Ceive = Ceive 8 | self.Propertys = Propertys 9 | self.Request = Request 10 | self.Release = Release 11 | self.Retain = Retain 12 | 13 | return self 14 | end 15 | 16 | function Gizmo:Draw(Origin: Vector3, End: Vector3, Radius: number, Length: number, Subdivisions: number) 17 | local Ceive = self.Ceive 18 | 19 | if not Ceive.Enabled then 20 | return 21 | end 22 | 23 | Ceive.Ray:Draw(Origin, End) 24 | 25 | local ArrowCFrame = CFrame.lookAt(End + ((Origin - End).Unit * (Length * 0.5)), End) 26 | Ceive.Cone:Draw(ArrowCFrame, Radius, Length, Subdivisions) 27 | end 28 | 29 | function Gizmo:Create(Origin: Vector3, End: Vector3, Radius: number, Length: number, Subdivisions: number) 30 | local PropertyTable = { 31 | Origin = Origin, 32 | End = End, 33 | Radius = Radius, 34 | Length = Length, 35 | Subdivisions = Subdivisions, 36 | AlwaysOnTop = self.Propertys.AlwaysOnTop, 37 | Transparency = self.Propertys.Transparency, 38 | Color3 = self.Propertys.Color3, 39 | Enabled = true, 40 | Destroy = false, 41 | } 42 | 43 | self.Retain(self, PropertyTable) 44 | 45 | return PropertyTable 46 | end 47 | 48 | function Gizmo:Update(PropertyTable) 49 | local Ceive = self.Ceive 50 | 51 | Ceive.PushProperty("AlwaysOnTop", PropertyTable.AlwaysOnTop) 52 | Ceive.PushProperty("Transparency", PropertyTable.Transparency) 53 | Ceive.PushProperty("Color3", PropertyTable.Color3) 54 | 55 | self:Draw(PropertyTable.Origin, PropertyTable.End, PropertyTable.Radius, PropertyTable.Length, PropertyTable.Subdivisions) 56 | end 57 | 58 | return Gizmo 59 | -------------------------------------------------------------------------------- /src/Dependencies/Debug/Gizmo/Gizmos/Box.luau: -------------------------------------------------------------------------------- 1 | local Gizmo = {} 2 | Gizmo.__index = Gizmo 3 | 4 | function Gizmo.Init(Ceive, Propertys, Request, Release, Retain) 5 | local self = setmetatable({}, Gizmo) 6 | 7 | self.Ceive = Ceive 8 | self.Propertys = Propertys 9 | self.Request = Request 10 | self.Release = Release 11 | self.Retain = Retain 12 | 13 | return self 14 | end 15 | 16 | function Gizmo:Draw(Transform: CFrame, Size: Vector3, DrawTriangles: boolean) 17 | local Ceive = self.Ceive 18 | 19 | if not Ceive.Enabled then 20 | return 21 | end 22 | 23 | local Position = Transform.Position 24 | local Uv = Transform.UpVector 25 | local Rv = Transform.RightVector 26 | local Lv = Transform.LookVector 27 | local sO2 = Size * 0.5 28 | local sUv = Uv * sO2.Y 29 | local sRv = Rv * sO2.X 30 | local sLv = Lv * sO2.Z 31 | 32 | local function CalculateYFace(lUv, lRv, lLv) 33 | local TopLeft = Position + (lUv - lRv + lLv) 34 | local TopRight = Position + (lUv + lRv + lLv) 35 | local BottomLeft = Position + (lUv - lRv - lLv) 36 | local BottomRight = Position + (lUv + lRv - lLv) 37 | 38 | Ceive.Ray:Draw(TopLeft, TopRight) 39 | Ceive.Ray:Draw(TopLeft, BottomLeft) 40 | 41 | Ceive.Ray:Draw(TopRight, BottomRight) 42 | if DrawTriangles ~= false then 43 | Ceive.Ray:Draw(TopRight, BottomLeft) 44 | end 45 | 46 | Ceive.Ray:Draw(BottomLeft, BottomRight) 47 | end 48 | 49 | local function CalculateZFace(lUv, lRv, lLv) 50 | local TopLeft = Position + (lUv - lRv + lLv) 51 | local TopRight = Position + (lUv + lRv + lLv) 52 | local BottomLeft = Position + (-lUv - lRv + lLv) 53 | local BottomRight = Position + (-lUv + lRv + lLv) 54 | 55 | Ceive.Ray:Draw(TopLeft, TopRight) 56 | Ceive.Ray:Draw(TopLeft, BottomLeft) 57 | 58 | Ceive.Ray:Draw(TopRight, BottomRight) 59 | if DrawTriangles ~= false then 60 | Ceive.Ray:Draw(TopRight, BottomLeft) 61 | end 62 | 63 | Ceive.Ray:Draw(BottomLeft, BottomRight) 64 | end 65 | 66 | local function CalculateXFace(lUv, lRv, lLv) 67 | local TopLeft = Position + (lUv - lRv - lLv) 68 | local TopRight = Position + (lUv - lRv + lLv) 69 | local BottomLeft = Position + (-lUv - lRv - lLv) 70 | local BottomRight = Position + (-lUv - lRv + lLv) 71 | 72 | Ceive.Ray:Draw(TopLeft, TopRight) 73 | Ceive.Ray:Draw(TopLeft, BottomLeft) 74 | 75 | Ceive.Ray:Draw(TopRight, BottomRight) 76 | if DrawTriangles ~= false then 77 | Ceive.Ray:Draw(TopRight, BottomLeft) 78 | end 79 | 80 | Ceive.Ray:Draw(BottomLeft, BottomRight) 81 | end 82 | 83 | CalculateXFace(sUv, sRv, sLv) 84 | CalculateXFace(sUv, -sRv, sLv) 85 | 86 | CalculateYFace(sUv, sRv, sLv) 87 | CalculateYFace(-sUv, sRv, sLv) 88 | 89 | CalculateZFace(sUv, sRv, sLv) 90 | CalculateZFace(sUv, sRv, -sLv) 91 | end 92 | 93 | function Gizmo:Create(Transform: CFrame, Size: Vector3, DrawTriangles: boolean) 94 | local PropertyTable = { 95 | Transform = Transform, 96 | Size = Size, 97 | DrawTriangles = DrawTriangles, 98 | AlwaysOnTop = self.Propertys.AlwaysOnTop, 99 | Transparency = self.Propertys.Transparency, 100 | Color3 = self.Propertys.Color3, 101 | Enabled = true, 102 | Destroy = false, 103 | } 104 | 105 | self.Retain(self, PropertyTable) 106 | 107 | return PropertyTable 108 | end 109 | 110 | function Gizmo:Update(PropertyTable) 111 | local Ceive = self.Ceive 112 | 113 | Ceive.PushProperty("AlwaysOnTop", PropertyTable.AlwaysOnTop) 114 | Ceive.PushProperty("Transparency", PropertyTable.Transparency) 115 | Ceive.PushProperty("Color3", PropertyTable.Color3) 116 | 117 | self:Draw(PropertyTable.Transform, PropertyTable.Size, PropertyTable.DrawTriangles) 118 | end 119 | 120 | return Gizmo 121 | -------------------------------------------------------------------------------- /src/Dependencies/Debug/Gizmo/Gizmos/Capsule.luau: -------------------------------------------------------------------------------- 1 | local Rad180D = math.rad(180) 2 | 3 | local Gizmo = {} 4 | Gizmo.__index = Gizmo 5 | 6 | function Gizmo.Init(Ceive, Propertys, Request, Release, Retain) 7 | local self = setmetatable({}, Gizmo) 8 | 9 | self.Ceive = Ceive 10 | self.Propertys = Propertys 11 | self.Request = Request 12 | self.Release = Release 13 | self.Retain = Retain 14 | 15 | return self 16 | end 17 | 18 | function Gizmo:Draw(Transform: CFrame, Radius: number, Length: number, Subdivisions: number) 19 | local Ceive = self.Ceive 20 | 21 | if not Ceive.Enabled then 22 | return 23 | end 24 | 25 | -- Draw top and bottom of cylinder 26 | local TopOfCylinder = Transform.Position + (Transform.UpVector * (Length * 0.5)) 27 | local BottomOfCylinder = Transform.Position - (Transform.UpVector * (Length * 0.5)) 28 | 29 | TopOfCylinder = CFrame.lookAt(TopOfCylinder, TopOfCylinder + Transform.UpVector) 30 | BottomOfCylinder = CFrame.lookAt(BottomOfCylinder, BottomOfCylinder - Transform.UpVector) 31 | 32 | -- Draw Cylinder Lines 33 | 34 | local AnglePerChunk = math.floor(360 / Subdivisions) 35 | 36 | local LastTop 37 | local LastBottom 38 | 39 | local FirstTop 40 | local FirstBottom 41 | 42 | for i = 0, 360, AnglePerChunk do 43 | local XMagnitude = math.sin(math.rad(i)) * Radius 44 | local YMagnitude = math.cos(math.rad(i)) * Radius 45 | 46 | local VertexOffset = (Transform.LookVector * YMagnitude) + (Transform.RightVector * XMagnitude) 47 | local TopVertexPosition = TopOfCylinder.Position + VertexOffset 48 | local BottomVertexPosition = BottomOfCylinder.Position + VertexOffset 49 | 50 | Ceive.Ray:Draw(TopVertexPosition, BottomVertexPosition) 51 | 52 | Ceive.Circle:Draw( 53 | CFrame.new(TopOfCylinder.Position) * Transform.Rotation * CFrame.Angles(0, math.rad(i), 0), 54 | Radius, 55 | Subdivisions * 0.5, 56 | 90, 57 | false 58 | ) 59 | Ceive.Circle:Draw( 60 | CFrame.new(BottomOfCylinder.Position) * Transform.Rotation * CFrame.Angles(Rad180D, math.rad(i), 0), 61 | Radius, 62 | Subdivisions * 0.5, 63 | 90, 64 | false 65 | ) 66 | 67 | if not LastTop then 68 | LastTop = TopVertexPosition 69 | LastBottom = BottomVertexPosition 70 | 71 | FirstTop = TopVertexPosition 72 | FirstBottom = BottomVertexPosition 73 | 74 | continue 75 | end 76 | 77 | Ceive.Ray:Draw(LastTop, TopVertexPosition) 78 | Ceive.Ray:Draw(LastBottom, BottomVertexPosition) 79 | 80 | LastTop = TopVertexPosition 81 | LastBottom = BottomVertexPosition 82 | end 83 | 84 | Ceive.Ray:Draw(LastTop, FirstTop) 85 | Ceive.Ray:Draw(LastBottom, FirstBottom) 86 | end 87 | 88 | function Gizmo:Create(Transform: CFrame, Radius: number, Length: number, Subdivisions: number) 89 | local PropertyTable = { 90 | Transform = Transform, 91 | Radius = Radius, 92 | Length = Length, 93 | Subdivisions = Subdivisions, 94 | AlwaysOnTop = self.Propertys.AlwaysOnTop, 95 | Transparency = self.Propertys.Transparency, 96 | Color3 = self.Propertys.Color3, 97 | Enabled = true, 98 | Destroy = false, 99 | } 100 | 101 | self.Retain(self, PropertyTable) 102 | 103 | return PropertyTable 104 | end 105 | 106 | function Gizmo:Update(PropertyTable) 107 | local Ceive = self.Ceive 108 | 109 | Ceive.PushProperty("AlwaysOnTop", PropertyTable.AlwaysOnTop) 110 | Ceive.PushProperty("Transparency", PropertyTable.Transparency) 111 | Ceive.PushProperty("Color3", PropertyTable.Color3) 112 | 113 | self:Draw(PropertyTable.Transform, PropertyTable.Radius, PropertyTable.Length, PropertyTable.Subdivisions) 114 | end 115 | 116 | return Gizmo 117 | -------------------------------------------------------------------------------- /src/Dependencies/Debug/Gizmo/Gizmos/Circle.luau: -------------------------------------------------------------------------------- 1 | local Gizmo = {} 2 | Gizmo.__index = Gizmo 3 | 4 | function Gizmo.Init(Ceive, Propertys, Request, Release, Retain) 5 | local self = setmetatable({}, Gizmo) 6 | 7 | self.Ceive = Ceive 8 | self.Propertys = Propertys 9 | self.Request = Request 10 | self.Release = Release 11 | self.Retain = Retain 12 | 13 | return self 14 | end 15 | 16 | function Gizmo:Draw(Transform: CFrame, Radius: number, Subdivisions: number, Angle: number, ConnectToStart: boolean?) 17 | local Ceive = self.Ceive 18 | 19 | if not Ceive.Enabled then 20 | return 21 | end 22 | 23 | local AnglePerChunk = math.floor(Angle / Subdivisions) 24 | 25 | local PreviousVertex = nil 26 | local FirstVertex = nil 27 | 28 | local FinishingAngle = 0 29 | 30 | for i = 0, Angle, AnglePerChunk do 31 | local XMagnitude = math.sin(math.rad(i)) * Radius 32 | local YMagnitude = math.cos(math.rad(i)) * Radius 33 | 34 | local VertexPosition = Transform.Position + ((Transform.UpVector * YMagnitude) + (Transform.RightVector * XMagnitude)) 35 | 36 | if PreviousVertex == nil then 37 | PreviousVertex = VertexPosition 38 | FirstVertex = VertexPosition 39 | FinishingAngle = i 40 | continue 41 | end 42 | 43 | Ceive.Ray:Draw(PreviousVertex, VertexPosition) 44 | PreviousVertex = VertexPosition 45 | FinishingAngle = i 46 | end 47 | 48 | if FinishingAngle ~= Angle then 49 | local XMagnitude = math.sin(math.rad(Angle)) * Radius 50 | local YMagnitude = math.cos(math.rad(Angle)) * Radius 51 | 52 | local VertexPosition = Transform.Position + ((Transform.UpVector * YMagnitude) + (Transform.RightVector * XMagnitude)) 53 | 54 | Ceive.Ray:Draw(PreviousVertex, VertexPosition) 55 | end 56 | 57 | if ConnectToStart ~= false then 58 | Ceive.Ray:Draw(PreviousVertex, FirstVertex) 59 | end 60 | 61 | return PreviousVertex 62 | end 63 | 64 | function Gizmo:Create(Transform: CFrame, Radius: number, Subdivisions: number, Angle: number, ConnectToStart: boolean?) 65 | local PropertyTable = { 66 | Transform = Transform, 67 | Radius = Radius, 68 | Subdivisions = Subdivisions, 69 | Angle = Angle, 70 | ConnectToStart = ConnectToStart, 71 | AlwaysOnTop = self.Propertys.AlwaysOnTop, 72 | Transparency = self.Propertys.Transparency, 73 | Color3 = self.Propertys.Color3, 74 | Enabled = true, 75 | Destroy = false, 76 | } 77 | 78 | self.Retain(self, PropertyTable) 79 | 80 | return PropertyTable 81 | end 82 | 83 | function Gizmo:Update(PropertyTable) 84 | local Ceive = self.Ceive 85 | 86 | Ceive.PushProperty("AlwaysOnTop", PropertyTable.AlwaysOnTop) 87 | Ceive.PushProperty("Transparency", PropertyTable.Transparency) 88 | Ceive.PushProperty("Color3", PropertyTable.Color3) 89 | 90 | self:Draw(PropertyTable.Transform, PropertyTable.Radius, PropertyTable.Subdivisions, PropertyTable.Angle, PropertyTable.ConnectToStart) 91 | end 92 | 93 | return Gizmo 94 | -------------------------------------------------------------------------------- /src/Dependencies/Debug/Gizmo/Gizmos/Cone.luau: -------------------------------------------------------------------------------- 1 | local Rad90D = math.rad(90) 2 | 3 | local Gizmo = {} 4 | Gizmo.__index = Gizmo 5 | 6 | function Gizmo.Init(Ceive, Propertys, Request, Release, Retain) 7 | local self = setmetatable({}, Gizmo) 8 | 9 | self.Ceive = Ceive 10 | self.Propertys = Propertys 11 | self.Request = Request 12 | self.Release = Release 13 | self.Retain = Retain 14 | 15 | return self 16 | end 17 | 18 | function Gizmo:Draw(Transform: CFrame, Radius: number, Length: number, Subdivisions: number) 19 | local Ceive = self.Ceive 20 | 21 | if not Ceive.Enabled then 22 | return 23 | end 24 | 25 | Transform *= CFrame.Angles(-Rad90D, 0, 0) 26 | 27 | local TopOfCone = Transform.Position + Transform.UpVector * (Length * 0.5) 28 | local BottomOfCone = Transform.Position + -Transform.UpVector * (Length * 0.5) 29 | 30 | TopOfCone = CFrame.lookAt(TopOfCone, TopOfCone + Transform.UpVector) 31 | BottomOfCone = CFrame.lookAt(BottomOfCone, BottomOfCone - Transform.UpVector) 32 | 33 | local AnglePerChunk = math.floor(360 / Subdivisions) 34 | 35 | local Last 36 | local First 37 | 38 | for i = 0, 360, AnglePerChunk do 39 | local XMagnitude = math.sin(math.rad(i)) * Radius 40 | local YMagnitude = math.cos(math.rad(i)) * Radius 41 | 42 | local VertexOffset = (Transform.LookVector * YMagnitude) + (Transform.RightVector * XMagnitude) 43 | local VertexPosition = BottomOfCone.Position + VertexOffset 44 | 45 | if not Last then 46 | Last = VertexPosition 47 | First = VertexPosition 48 | 49 | Ceive.Ray:Draw(VertexPosition, TopOfCone.Position) 50 | 51 | continue 52 | end 53 | 54 | Ceive.Ray:Draw(VertexPosition, TopOfCone.Position) 55 | Ceive.Ray:Draw(Last, VertexPosition) 56 | 57 | Last = VertexPosition 58 | end 59 | 60 | Ceive.Ray:Draw(Last, First) 61 | end 62 | 63 | function Gizmo:Create(Transform: CFrame, Radius: number, Length: number, Subdivisions: number) 64 | local PropertyTable = { 65 | Transform = Transform, 66 | Radius = Radius, 67 | Length = Length, 68 | Subdivisions = Subdivisions, 69 | AlwaysOnTop = self.Propertys.AlwaysOnTop, 70 | Transparency = self.Propertys.Transparency, 71 | Color3 = self.Propertys.Color3, 72 | Enabled = true, 73 | Destroy = false, 74 | } 75 | 76 | self.Retain(self, PropertyTable) 77 | 78 | return PropertyTable 79 | end 80 | 81 | function Gizmo:Update(PropertyTable) 82 | local Ceive = self.Ceive 83 | 84 | Ceive.PushProperty("AlwaysOnTop", PropertyTable.AlwaysOnTop) 85 | Ceive.PushProperty("Transparency", PropertyTable.Transparency) 86 | Ceive.PushProperty("Color3", PropertyTable.Color3) 87 | 88 | self:Draw(PropertyTable.Transform, PropertyTable.Radius, PropertyTable.Length, PropertyTable.Subdivisions) 89 | end 90 | 91 | return Gizmo 92 | -------------------------------------------------------------------------------- /src/Dependencies/Debug/Gizmo/Gizmos/Cylinder.luau: -------------------------------------------------------------------------------- 1 | local Gizmo = {} 2 | Gizmo.__index = Gizmo 3 | 4 | function Gizmo.Init(Ceive, Propertys, Request, Release, Retain) 5 | local self = setmetatable({}, Gizmo) 6 | 7 | self.Ceive = Ceive 8 | self.Propertys = Propertys 9 | self.Request = Request 10 | self.Release = Release 11 | self.Retain = Retain 12 | 13 | return self 14 | end 15 | 16 | function Gizmo:Draw(Transform: CFrame, Radius: number, Length: number, Subdivisions: number) 17 | local Ceive = self.Ceive 18 | 19 | if not Ceive.Enabled then 20 | return 21 | end 22 | 23 | -- Draw top and bottom of cylinder 24 | local TopOfCylinder = Transform.Position + (Transform.UpVector * (Length * 0.5)) 25 | local BottomOfCylinder = Transform.Position - (Transform.UpVector * (Length * 0.5)) 26 | 27 | TopOfCylinder = CFrame.lookAt(TopOfCylinder, TopOfCylinder + Transform.UpVector) 28 | BottomOfCylinder = CFrame.lookAt(BottomOfCylinder, BottomOfCylinder - Transform.UpVector) 29 | 30 | -- Draw Cylinder Lines 31 | 32 | local AnglePerChunk = math.floor(360 / Subdivisions) 33 | 34 | local LastTop 35 | local LastBottom 36 | 37 | local FirstTop 38 | local FirstBottom 39 | 40 | for i = 0, 360, AnglePerChunk do 41 | local XMagnitude = math.sin(math.rad(i)) * Radius 42 | local YMagnitude = math.cos(math.rad(i)) * Radius 43 | 44 | local VertexOffset = (Transform.LookVector * YMagnitude) + (Transform.RightVector * XMagnitude) 45 | local TopVertexPosition = TopOfCylinder.Position + VertexOffset 46 | local BottomVertexPosition = BottomOfCylinder.Position + VertexOffset 47 | 48 | Ceive.Ray:Draw(TopVertexPosition, BottomVertexPosition) 49 | 50 | if not LastTop then 51 | LastTop = TopVertexPosition 52 | LastBottom = BottomVertexPosition 53 | 54 | FirstTop = TopVertexPosition 55 | FirstBottom = BottomVertexPosition 56 | 57 | continue 58 | end 59 | 60 | Ceive.Ray:Draw(LastTop, TopVertexPosition) 61 | Ceive.Ray:Draw(LastBottom, BottomVertexPosition) 62 | 63 | LastTop = TopVertexPosition 64 | LastBottom = BottomVertexPosition 65 | end 66 | 67 | Ceive.Ray:Draw(LastTop, FirstTop) 68 | Ceive.Ray:Draw(LastBottom, FirstBottom) 69 | end 70 | 71 | function Gizmo:Create(Transform: CFrame, Radius: number, Length: number, Subdivisions: number) 72 | local PropertyTable = { 73 | Transform = Transform, 74 | Radius = Radius, 75 | Length = Length, 76 | Subdivisions = Subdivisions, 77 | AlwaysOnTop = self.Propertys.AlwaysOnTop, 78 | Transparency = self.Propertys.Transparency, 79 | Color3 = self.Propertys.Color3, 80 | Enabled = true, 81 | Destroy = false, 82 | } 83 | 84 | self.Retain(self, PropertyTable) 85 | 86 | return PropertyTable 87 | end 88 | 89 | function Gizmo:Update(PropertyTable) 90 | local Ceive = self.Ceive 91 | 92 | Ceive.PushProperty("AlwaysOnTop", PropertyTable.AlwaysOnTop) 93 | Ceive.PushProperty("Transparency", PropertyTable.Transparency) 94 | Ceive.PushProperty("Color3", PropertyTable.Color3) 95 | 96 | self:Draw(PropertyTable.Transform, PropertyTable.Radius, PropertyTable.Length, PropertyTable.Subdivisions) 97 | end 98 | 99 | return Gizmo 100 | -------------------------------------------------------------------------------- /src/Dependencies/Debug/Gizmo/Gizmos/Line.luau: -------------------------------------------------------------------------------- 1 | local Gizmo = {} 2 | Gizmo.__index = Gizmo 3 | 4 | function Gizmo.Init(Ceive, Propertys, Request, Release, Retain) 5 | local self = setmetatable({}, Gizmo) 6 | 7 | self.Ceive = Ceive 8 | self.Propertys = Propertys 9 | self.Request = Request 10 | self.Release = Release 11 | self.Retain = Retain 12 | 13 | return self 14 | end 15 | 16 | function Gizmo:Draw(Transform: CFrame, Length: number) 17 | local Ceive = self.Ceive 18 | 19 | if not Ceive.Enabled then 20 | return 21 | end 22 | 23 | local Origin = Transform.Position + (Transform.LookVector * (-Length * 0.5)) 24 | local End = Transform.Position + (Transform.LookVector * (Length * 0.5)) 25 | 26 | Ceive.Ray:Draw(Origin, End) 27 | end 28 | 29 | function Gizmo:Create(Transform: CFrame, Length: number) 30 | local PropertyTable = { 31 | Transform = Transform, 32 | Length = Length, 33 | AlwaysOnTop = self.Propertys.AlwaysOnTop, 34 | Transparency = self.Propertys.Transparency, 35 | Color3 = self.Propertys.Color3, 36 | Enabled = true, 37 | Destroy = false, 38 | } 39 | 40 | self.Retain(self, PropertyTable) 41 | 42 | return PropertyTable 43 | end 44 | 45 | function Gizmo:Update(PropertyTable) 46 | local Ceive = self.Ceive 47 | 48 | Ceive.PushProperty("AlwaysOnTop", PropertyTable.AlwaysOnTop) 49 | Ceive.PushProperty("Transparency", PropertyTable.Transparency) 50 | Ceive.PushProperty("Color3", PropertyTable.Color3) 51 | 52 | self:Draw(PropertyTable.Transform, PropertyTable.Length) 53 | end 54 | 55 | return Gizmo 56 | -------------------------------------------------------------------------------- /src/Dependencies/Debug/Gizmo/Gizmos/Mesh.luau: -------------------------------------------------------------------------------- 1 | local function Map(n, start, stop, newStart, newStop) 2 | return ((n - start) / (stop - start)) * (newStop - newStart) + newStart 3 | end 4 | 5 | local Gizmo = {} 6 | Gizmo.__index = Gizmo 7 | 8 | function Gizmo.Init(Ceive, Propertys, Request, Release, Retain) 9 | local self = setmetatable({}, Gizmo) 10 | 11 | self.Ceive = Ceive 12 | self.Propertys = Propertys 13 | self.Request = Request 14 | self.Release = Release 15 | self.Retain = Retain 16 | 17 | return self 18 | end 19 | 20 | function Gizmo:Draw(Transform: CFrame, Size: Vector3, Vertices, Faces) 21 | local Ceive = self.Ceive 22 | 23 | if not Ceive.Enabled then 24 | return 25 | end 26 | 27 | local maxX = -math.huge 28 | local maxY = -math.huge 29 | local maxZ = -math.huge 30 | 31 | local minX = math.huge 32 | local minY = math.huge 33 | local minZ = math.huge 34 | 35 | for _, vertex in Vertices do 36 | maxX = math.max(maxX, vertex.x) 37 | maxY = math.max(maxY, vertex.y) 38 | maxZ = math.max(maxZ, vertex.z) 39 | 40 | minX = math.min(minX, vertex.x) 41 | minY = math.min(minY, vertex.y) 42 | minZ = math.min(minZ, vertex.z) 43 | end 44 | 45 | for i, vertex in Vertices do 46 | local vX = Map(vertex.x, minX, maxX, -0.5, 0.5) 47 | local vY = Map(vertex.y, minY, maxY, -0.5, 0.5) 48 | local vZ = Map(vertex.z, minZ, maxZ, -0.5, 0.5) 49 | 50 | local vertexCFrame = Transform * CFrame.new(Vector3.new(vX, vY, vZ) * Size) 51 | Vertices[i] = vertexCFrame 52 | end 53 | 54 | for _, face in Faces do 55 | if #face == 3 then 56 | local vCF1 = Vertices[face[1].v] 57 | local vCF2 = Vertices[face[2].v] 58 | local vCF3 = Vertices[face[3].v] 59 | 60 | Ceive.Ray:Draw(vCF1.Position, vCF2.Position) 61 | Ceive.Ray:Draw(vCF2.Position, vCF3.Position) 62 | Ceive.Ray:Draw(vCF3.Position, vCF1.Position) 63 | else 64 | local vCF1 = Vertices[face[1].v] 65 | local vCF2 = Vertices[face[2].v] 66 | local vCF3 = Vertices[face[3].v] 67 | local vCF4 = Vertices[face[4].v] 68 | 69 | Ceive.Ray:Draw(vCF1.Position, vCF2.Position) 70 | Ceive.Ray:Draw(vCF1.Position, vCF4.Position) 71 | Ceive.Ray:Draw(vCF4.Position, vCF2.Position) 72 | 73 | Ceive.Ray:Draw(vCF3.Position, vCF4.Position) 74 | Ceive.Ray:Draw(vCF2.Position, vCF3.Position) 75 | end 76 | end 77 | end 78 | 79 | function Gizmo:Create(Transform: CFrame, Size: Vector3, Vertices, Faces) 80 | local PropertyTable = { 81 | Transform = Transform, 82 | Size = Size, 83 | Vertices = Vertices, 84 | Faces = Faces, 85 | AlwaysOnTop = self.Propertys.AlwaysOnTop, 86 | Transparency = self.Propertys.Transparency, 87 | Color3 = self.Propertys.Color3, 88 | Enabled = true, 89 | Destroy = false, 90 | } 91 | 92 | self.Retain(self, PropertyTable) 93 | 94 | return PropertyTable 95 | end 96 | 97 | function Gizmo:Update(PropertyTable) 98 | local Ceive = self.Ceive 99 | 100 | Ceive.PushProperty("AlwaysOnTop", PropertyTable.AlwaysOnTop) 101 | Ceive.PushProperty("Transparency", PropertyTable.Transparency) 102 | Ceive.PushProperty("Color3", PropertyTable.Color3) 103 | 104 | self:Draw(PropertyTable.Transform, PropertyTable.Size, PropertyTable.Vertices, PropertyTable.Faces) 105 | end 106 | 107 | return Gizmo 108 | -------------------------------------------------------------------------------- /src/Dependencies/Debug/Gizmo/Gizmos/Plane.luau: -------------------------------------------------------------------------------- 1 | local Gizmo = {} 2 | Gizmo.__index = Gizmo 3 | 4 | function Gizmo.Init(Ceive, Propertys, Request, Release, Retain) 5 | local self = setmetatable({}, Gizmo) 6 | 7 | self.Ceive = Ceive 8 | self.Propertys = Propertys 9 | self.Request = Request 10 | self.Release = Release 11 | self.Retain = Retain 12 | 13 | return self 14 | end 15 | 16 | function Gizmo:Draw(Position: Vector3, Normal: Vector3, Size: Vector3) 17 | local Ceive = self.Ceive 18 | 19 | if not Ceive.Enabled then 20 | return 21 | end 22 | 23 | Size *= Vector3.new(1, 1, 0) 24 | 25 | local Transform = CFrame.lookAt(Position, Position + Normal) 26 | 27 | local Uv = Transform.UpVector 28 | local Rv = Transform.RightVector 29 | local Lv = Transform.LookVector 30 | local sO2 = Size * 0.5 31 | local sUv = Uv * sO2.Y 32 | local sRv = Rv * sO2.X 33 | local sLv = Lv * sO2.Z 34 | 35 | local function CalculateZFace(lUv, lRv, lLv) 36 | local TopLeft = Position + (lUv - lRv + lLv) 37 | local TopRight = Position + (lUv + lRv + lLv) 38 | local BottomLeft = Position + (-lUv - lRv + lLv) 39 | local BottomRight = Position + (-lUv + lRv + lLv) 40 | 41 | Ceive.Ray:Draw(TopLeft, TopRight) 42 | Ceive.Ray:Draw(TopLeft, BottomLeft) 43 | 44 | Ceive.Ray:Draw(TopRight, BottomRight) 45 | Ceive.Ray:Draw(TopRight, BottomLeft) 46 | 47 | Ceive.Ray:Draw(BottomLeft, BottomRight) 48 | end 49 | 50 | CalculateZFace(sUv, sRv, sLv) 51 | end 52 | 53 | function Gizmo:Create(Position: Vector3, Normal: Vector3, Size: Vector3) 54 | local PropertyTable = { 55 | Position = Position, 56 | Normal = Normal, 57 | Size = Size, 58 | AlwaysOnTop = self.Propertys.AlwaysOnTop, 59 | Transparency = self.Propertys.Transparency, 60 | Color3 = self.Propertys.Color3, 61 | Enabled = true, 62 | Destroy = false, 63 | } 64 | 65 | self.Retain(self, PropertyTable) 66 | 67 | return PropertyTable 68 | end 69 | 70 | function Gizmo:Update(PropertyTable) 71 | local Ceive = self.Ceive 72 | 73 | Ceive.PushProperty("AlwaysOnTop", PropertyTable.AlwaysOnTop) 74 | Ceive.PushProperty("Transparency", PropertyTable.Transparency) 75 | Ceive.PushProperty("Color3", PropertyTable.Color3) 76 | 77 | self:Draw(PropertyTable.Position, PropertyTable.Normal, PropertyTable.Size) 78 | end 79 | 80 | return Gizmo 81 | -------------------------------------------------------------------------------- /src/Dependencies/Debug/Gizmo/Gizmos/Ray.luau: -------------------------------------------------------------------------------- 1 | local Gizmo = {} 2 | Gizmo.__index = Gizmo 3 | 4 | function Gizmo.Init(Ceive, Propertys, Request, Release, Retain) 5 | local self = setmetatable({}, Gizmo) 6 | 7 | self.Ceive = Ceive 8 | self.Propertys = Propertys 9 | self.Request = Request 10 | self.Release = Release 11 | self.Retain = Retain 12 | 13 | return self 14 | end 15 | 16 | function Gizmo:Draw(Origin: Vector3, End: Vector3) 17 | local Ceive = self.Ceive 18 | 19 | if not Ceive.Enabled then 20 | return 21 | end 22 | 23 | if self.Propertys.AlwaysOnTop then 24 | Ceive.AOTWireframeHandle:AddLine(Origin, End) 25 | else 26 | Ceive.WireframeHandle:AddLine(Origin, End) 27 | end 28 | 29 | self.Ceive.ActiveRays += 1 30 | 31 | self.Ceive.ScheduleCleaning() 32 | end 33 | 34 | function Gizmo:Create(Origin: Vector3, End: Vector3) 35 | local PropertyTable = { 36 | Origin = Origin, 37 | End = End, 38 | AlwaysOnTop = self.Propertys.AlwaysOnTop, 39 | Transparency = self.Propertys.Transparency, 40 | Color3 = self.Propertys.Color3, 41 | Enabled = true, 42 | Destroy = false, 43 | } 44 | 45 | self.Retain(self, PropertyTable) 46 | 47 | return PropertyTable 48 | end 49 | 50 | function Gizmo:Update(PropertyTable) 51 | local Ceive = self.Ceive 52 | 53 | Ceive.PushProperty("AlwaysOnTop", PropertyTable.AlwaysOnTop) 54 | Ceive.PushProperty("Transparency", PropertyTable.Transparency) 55 | Ceive.PushProperty("Color3", PropertyTable.Color3) 56 | 57 | self:Draw(PropertyTable.Origin, PropertyTable.End) 58 | end 59 | 60 | return Gizmo 61 | -------------------------------------------------------------------------------- /src/Dependencies/Debug/Gizmo/Gizmos/Sphere.luau: -------------------------------------------------------------------------------- 1 | local Rad90D = math.rad(90) 2 | 3 | local Gizmo = {} 4 | Gizmo.__index = Gizmo 5 | 6 | function Gizmo.Init(Ceive, Propertys, Request, Release, Retain) 7 | local self = setmetatable({}, Gizmo) 8 | 9 | self.Ceive = Ceive 10 | self.Propertys = Propertys 11 | self.Request = Request 12 | self.Release = Release 13 | self.Retain = Retain 14 | 15 | return self 16 | end 17 | 18 | function Gizmo:Draw(Transform: CFrame, Radius: number, Subdivisions: number, Angle: number) 19 | local Ceive = self.Ceive 20 | 21 | if not Ceive.Enabled then 22 | return 23 | end 24 | 25 | Ceive.Circle:Draw(Transform, Radius, Subdivisions, Angle) 26 | Ceive.Circle:Draw(Transform * CFrame.Angles(0, Rad90D, 0), Radius, Subdivisions, Angle) 27 | Ceive.Circle:Draw(Transform * CFrame.Angles(Rad90D, 0, 0), Radius, Subdivisions, Angle) 28 | end 29 | 30 | function Gizmo:Create(Transform: CFrame, Radius: number, Subdivisions: number, Angle: number) 31 | local PropertyTable = { 32 | Transform = Transform, 33 | Radius = Radius, 34 | Subdivisions = Subdivisions, 35 | Angle = Angle, 36 | AlwaysOnTop = self.Propertys.AlwaysOnTop, 37 | Transparency = self.Propertys.Transparency, 38 | Color3 = self.Propertys.Color3, 39 | Enabled = true, 40 | Destroy = false, 41 | } 42 | 43 | self.Retain(self, PropertyTable) 44 | 45 | return PropertyTable 46 | end 47 | 48 | function Gizmo:Update(PropertyTable) 49 | local Ceive = self.Ceive 50 | 51 | Ceive.PushProperty("AlwaysOnTop", PropertyTable.AlwaysOnTop) 52 | Ceive.PushProperty("Transparency", PropertyTable.Transparency) 53 | Ceive.PushProperty("Color3", PropertyTable.Color3) 54 | 55 | self:Draw(PropertyTable.Transform, PropertyTable.Radius, PropertyTable.Subdivisions, PropertyTable.Angle) 56 | end 57 | 58 | return Gizmo 59 | -------------------------------------------------------------------------------- /src/Dependencies/Debug/Gizmo/Gizmos/Text.luau: -------------------------------------------------------------------------------- 1 | local DROP_SHADOW = true 2 | local OFFSET_PERCENTAGE = 0.00175 3 | 4 | local Camera = workspace.CurrentCamera 5 | 6 | local Gizmo = {} 7 | Gizmo.__index = Gizmo 8 | 9 | function Gizmo.Init(Ceive, Propertys, Request, Release, Retain) 10 | local self = setmetatable({}, Gizmo) 11 | 12 | self.Ceive = Ceive 13 | self.Propertys = Propertys 14 | self.Request = Request 15 | self.Release = Release 16 | self.Retain = Retain 17 | 18 | return self 19 | end 20 | 21 | function Gizmo:Draw(Origin: Vector3, Text: string, Size: number?) 22 | local Ceive = self.Ceive 23 | 24 | if not Ceive.Enabled then 25 | return 26 | end 27 | 28 | if self.Propertys.AlwaysOnTop then 29 | if DROP_SHADOW then 30 | local DistanceToCamera = (Origin - Camera.CFrame.Position).Magnitude 31 | local PrevColor = Ceive.PopProperty("Color3") 32 | 33 | Ceive.PushProperty("Color3", Color3.new()) 34 | local Offset = -(Vector3.xAxis + Vector3.yAxis).Unit 35 | Ceive.AOTWireframeHandle:AddText(Origin + Offset * (DistanceToCamera * OFFSET_PERCENTAGE), Text, Size) 36 | Ceive.PushProperty("Color3", PrevColor) 37 | end 38 | 39 | Ceive.AOTWireframeHandle:AddText(Origin, Text, Size) 40 | else 41 | if DROP_SHADOW then 42 | local DistanceToCamera = (Origin - Camera.CFrame.Position).Magnitude 43 | local PrevColor = Ceive.PopProperty("Color3") 44 | 45 | Ceive.PushProperty("Color3", Color3.new()) 46 | local Offset = -(Vector3.xAxis + Vector3.yAxis).Unit 47 | Ceive.WireframeHandle:AddText(Origin + Offset * (DistanceToCamera * OFFSET_PERCENTAGE), Text, Size) 48 | Ceive.PushProperty("Color3", PrevColor) 49 | end 50 | 51 | Ceive.WireframeHandle:AddText(Origin, Text, Size) 52 | end 53 | 54 | -- Should text count to active rays? 55 | --self.Ceive.ActiveRays += 1 56 | 57 | self.Ceive.ScheduleCleaning() 58 | end 59 | 60 | function Gizmo:Create(Origin: Vector3, Text: string, Size: number?) 61 | local PropertyTable = { 62 | Origin = Origin, 63 | Text = Text, 64 | Size = Size, 65 | AlwaysOnTop = self.Propertys.AlwaysOnTop, 66 | Transparency = self.Propertys.Transparency, 67 | Color3 = self.Propertys.Color3, 68 | Enabled = true, 69 | Destroy = false, 70 | } 71 | 72 | self.Retain(self, PropertyTable) 73 | 74 | return PropertyTable 75 | end 76 | 77 | function Gizmo:Update(PropertyTable) 78 | local Ceive = self.Ceive 79 | 80 | Ceive.PushProperty("AlwaysOnTop", PropertyTable.AlwaysOnTop) 81 | Ceive.PushProperty("Transparency", PropertyTable.Transparency) 82 | Ceive.PushProperty("Color3", PropertyTable.Color3) 83 | 84 | self:Draw(PropertyTable.Origin, PropertyTable.Text, PropertyTable.Size) 85 | end 86 | 87 | return Gizmo 88 | -------------------------------------------------------------------------------- /src/Dependencies/Debug/Gizmo/Gizmos/VolumeArrow.luau: -------------------------------------------------------------------------------- 1 | local Gizmo = {} 2 | Gizmo.__index = Gizmo 3 | 4 | function Gizmo.Init(Ceive, Propertys, Request, Release, Retain, Register) 5 | local self = setmetatable({}, Gizmo) 6 | 7 | self.Ceive = Ceive 8 | self.Propertys = Propertys 9 | self.Request = Request 10 | self.Release = Release 11 | self.Retain = Retain 12 | self.Register = Register 13 | 14 | return self 15 | end 16 | 17 | function Gizmo:Draw(Origin: Vector3, End: Vector3, CylinderRadius: number, ConeRadius: number, Length: number, UseCylinder: boolean?) 18 | local Ceive = self.Ceive 19 | 20 | if not Ceive.Enabled then 21 | return 22 | end 23 | 24 | local ArrowCFrame = CFrame.lookAt(End - (End - Origin).Unit * (Length * 0.5), End) 25 | 26 | if UseCylinder == true then 27 | local BottomCone = ArrowCFrame.Position 28 | local CylinderLength = (BottomCone - Origin).Magnitude 29 | local CylinderCFrame = CFrame.lookAt((Origin + BottomCone) * 0.5, End) 30 | 31 | Ceive.VolumeCylinder:Draw(CylinderCFrame, CylinderRadius, CylinderLength) 32 | else 33 | Ceive.Ray:Draw(Origin, End) 34 | end 35 | 36 | Ceive.VolumeCone:Draw(ArrowCFrame, ConeRadius, Length) 37 | self.Ceive.ScheduleCleaning() 38 | end 39 | 40 | function Gizmo:Create(Origin: Vector3, End: Vector3, CylinderRadius: number, ConeRadius: number, Length: number, UseCylinder: boolean?) 41 | local PropertyTable = { 42 | Origin = Origin, 43 | End = End, 44 | CylinderRadius = CylinderRadius, 45 | ConeRadius = ConeRadius, 46 | Length = Length, 47 | UseCylinder = UseCylinder, 48 | AlwaysOnTop = self.Propertys.AlwaysOnTop, 49 | Transparency = self.Propertys.Transparency, 50 | Color3 = self.Propertys.Color3, 51 | Enabled = true, 52 | Destroy = false, 53 | } 54 | 55 | self.Retain(self, PropertyTable) 56 | 57 | return PropertyTable 58 | end 59 | 60 | function Gizmo:Update(PropertyTable) 61 | local Ceive = self.Ceive 62 | 63 | Ceive.PushProperty("AlwaysOnTop", PropertyTable.AlwaysOnTop) 64 | Ceive.PushProperty("Transparency", PropertyTable.Transparency) 65 | Ceive.PushProperty("Color3", PropertyTable.Color3) 66 | 67 | self:Draw(PropertyTable.Origin, PropertyTable.End, PropertyTable.Radius, PropertyTable.Length, PropertyTable.UseCylinder) 68 | end 69 | 70 | return Gizmo 71 | -------------------------------------------------------------------------------- /src/Dependencies/Debug/Gizmo/Gizmos/VolumeBox.luau: -------------------------------------------------------------------------------- 1 | local Terrain = workspace.Terrain 2 | 3 | local Gizmo = {} 4 | Gizmo.__index = Gizmo 5 | 6 | function Gizmo.Init(Ceive, Propertys, Request, Release, Retain, Register) 7 | local self = setmetatable({}, Gizmo) 8 | 9 | self.Ceive = Ceive 10 | self.Propertys = Propertys 11 | self.Request = Request 12 | self.Release = Release 13 | self.Retain = Retain 14 | self.Register = Register 15 | 16 | return self 17 | end 18 | 19 | function Gizmo:Draw(Transform: CFrame, Size: Vector3) 20 | local Ceive = self.Ceive 21 | 22 | if not Ceive.Enabled then 23 | return 24 | end 25 | 26 | local Box = self.Request("BoxHandleAdornment") 27 | Box.Color3 = self.Propertys.Color3 28 | Box.Transparency = self.Propertys.Transparency 29 | 30 | Box.CFrame = Transform 31 | Box.Size = Size 32 | Box.AlwaysOnTop = self.Propertys.AlwaysOnTop 33 | Box.ZIndex = 1 34 | Box.Adornee = Terrain 35 | Box.Parent = Terrain 36 | 37 | Ceive.ActiveInstances += 1 38 | 39 | self.Register(Box) 40 | self.Ceive.ScheduleCleaning() 41 | end 42 | 43 | function Gizmo:Create(Transform: CFrame, Size: Vector3) 44 | local PropertyTable = { 45 | Transform = Transform, 46 | Size = Size, 47 | AlwaysOnTop = self.Propertys.AlwaysOnTop, 48 | Transparency = self.Propertys.Transparency, 49 | Color3 = self.Propertys.Color3, 50 | Enabled = true, 51 | Destroy = false, 52 | } 53 | 54 | self.Retain(self, PropertyTable) 55 | 56 | return PropertyTable 57 | end 58 | 59 | function Gizmo:Update(PropertyTable) 60 | local Ceive = self.Ceive 61 | 62 | Ceive.PushProperty("AlwaysOnTop", PropertyTable.AlwaysOnTop) 63 | Ceive.PushProperty("Transparency", PropertyTable.Transparency) 64 | Ceive.PushProperty("Color3", PropertyTable.Color3) 65 | 66 | self:Draw(PropertyTable.Transform, PropertyTable.Size) 67 | end 68 | 69 | return Gizmo 70 | -------------------------------------------------------------------------------- /src/Dependencies/Debug/Gizmo/Gizmos/VolumeCone.luau: -------------------------------------------------------------------------------- 1 | local Terrain = workspace.Terrain 2 | 3 | local Gizmo = {} 4 | Gizmo.__index = Gizmo 5 | 6 | function Gizmo.Init(Ceive, Propertys, Request, Release, Retain, Register) 7 | local self = setmetatable({}, Gizmo) 8 | 9 | self.Ceive = Ceive 10 | self.Propertys = Propertys 11 | self.Request = Request 12 | self.Release = Release 13 | self.Retain = Retain 14 | self.Register = Register 15 | 16 | return self 17 | end 18 | 19 | function Gizmo:Draw(Transform: CFrame, Radius: number, Length: number) 20 | local Ceive = self.Ceive 21 | 22 | if not Ceive.Enabled then 23 | return 24 | end 25 | 26 | local Cone = self.Request("ConeHandleAdornment") 27 | Cone.Color3 = self.Propertys.Color3 28 | Cone.Transparency = self.Propertys.Transparency 29 | 30 | Cone.CFrame = Transform 31 | Cone.AlwaysOnTop = self.Propertys.AlwaysOnTop 32 | Cone.ZIndex = 1 33 | Cone.Height = Length 34 | Cone.Radius = Radius 35 | Cone.Adornee = Terrain 36 | Cone.Parent = Terrain 37 | 38 | Ceive.ActiveInstances += 1 39 | 40 | self.Register(Cone) 41 | self.Ceive.ScheduleCleaning() 42 | end 43 | 44 | function Gizmo:Create(Transform: CFrame, Radius: number, Length: number) 45 | local PropertyTable = { 46 | Transform = Transform, 47 | Radius = Radius, 48 | Length = Length, 49 | AlwaysOnTop = self.Propertys.AlwaysOnTop, 50 | Transparency = self.Propertys.Transparency, 51 | Color3 = self.Propertys.Color3, 52 | Enabled = true, 53 | Destroy = false, 54 | } 55 | 56 | self.Retain(self, PropertyTable) 57 | 58 | return PropertyTable 59 | end 60 | 61 | function Gizmo:Update(PropertyTable) 62 | local Ceive = self.Ceive 63 | 64 | Ceive.PushProperty("AlwaysOnTop", PropertyTable.AlwaysOnTop) 65 | Ceive.PushProperty("Transparency", PropertyTable.Transparency) 66 | Ceive.PushProperty("Color3", PropertyTable.Color3) 67 | 68 | self:Draw(PropertyTable.Transform, PropertyTable.Radius, PropertyTable.Length) 69 | end 70 | 71 | return Gizmo 72 | -------------------------------------------------------------------------------- /src/Dependencies/Debug/Gizmo/Gizmos/VolumeCylinder.luau: -------------------------------------------------------------------------------- 1 | local Terrain = workspace.Terrain 2 | 3 | local Gizmo = {} 4 | Gizmo.__index = Gizmo 5 | 6 | function Gizmo.Init(Ceive, Propertys, Request, Release, Retain, Register) 7 | local self = setmetatable({}, Gizmo) 8 | 9 | self.Ceive = Ceive 10 | self.Propertys = Propertys 11 | self.Request = Request 12 | self.Release = Release 13 | self.Retain = Retain 14 | self.Register = Register 15 | 16 | return self 17 | end 18 | 19 | function Gizmo:Draw(Transform: CFrame, Radius: number, Length: number, InnerRadius: number?, Angle: number?) 20 | local Ceive = self.Ceive 21 | 22 | if not Ceive.Enabled then 23 | return 24 | end 25 | 26 | local Cylinder = self.Request("CylinderHandleAdornment") 27 | Cylinder.Color3 = self.Propertys.Color3 28 | Cylinder.Transparency = self.Propertys.Transparency 29 | 30 | Cylinder.CFrame = Transform 31 | Cylinder.Height = Length 32 | Cylinder.Radius = Radius 33 | Cylinder.InnerRadius = InnerRadius or 0 34 | Cylinder.Angle = Angle or 360 35 | Cylinder.AlwaysOnTop = self.Propertys.AlwaysOnTop 36 | Cylinder.ZIndex = 1 37 | Cylinder.Adornee = Terrain 38 | Cylinder.Parent = Terrain 39 | 40 | Ceive.ActiveInstances += 1 41 | 42 | self.Register(Cylinder) 43 | self.Ceive.ScheduleCleaning() 44 | end 45 | 46 | function Gizmo:Create(Transform: CFrame, Radius: number, Length: number, InnerRadius: number?, Angle: number?) 47 | local PropertyTable = { 48 | Transform = Transform, 49 | Radius = Radius, 50 | Length = Length, 51 | InnerRadius = InnerRadius or 0, 52 | Angle = Angle or 360, 53 | AlwaysOnTop = self.Propertys.AlwaysOnTop, 54 | Transparency = self.Propertys.Transparency, 55 | Color3 = self.Propertys.Color3, 56 | Enabled = true, 57 | Destroy = false, 58 | } 59 | 60 | self.Retain(self, PropertyTable) 61 | 62 | return PropertyTable 63 | end 64 | 65 | function Gizmo:Update(PropertyTable) 66 | local Ceive = self.Ceive 67 | 68 | Ceive.PushProperty("AlwaysOnTop", PropertyTable.AlwaysOnTop) 69 | Ceive.PushProperty("Transparency", PropertyTable.Transparency) 70 | Ceive.PushProperty("Color3", PropertyTable.Color3) 71 | 72 | self:Draw(PropertyTable.Transform, PropertyTable.Radius, PropertyTable.Length, PropertyTable.InnerRadius, PropertyTable.Angle) 73 | end 74 | 75 | return Gizmo 76 | -------------------------------------------------------------------------------- /src/Dependencies/Debug/Gizmo/Gizmos/VolumeSphere.luau: -------------------------------------------------------------------------------- 1 | local Terrain = workspace.Terrain 2 | 3 | local Gizmo = {} 4 | Gizmo.__index = Gizmo 5 | 6 | function Gizmo.Init(Ceive, Propertys, Request, Release, Retain, Register) 7 | local self = setmetatable({}, Gizmo) 8 | 9 | self.Ceive = Ceive 10 | self.Propertys = Propertys 11 | self.Request = Request 12 | self.Release = Release 13 | self.Retain = Retain 14 | self.Register = Register 15 | 16 | return self 17 | end 18 | 19 | function Gizmo:Draw(Transform: CFrame, Radius: number) 20 | local Ceive = self.Ceive 21 | 22 | if not Ceive.Enabled then 23 | return 24 | end 25 | 26 | local Sphere = self.Request("SphereHandleAdornment") 27 | Sphere.Color3 = self.Propertys.Color3 28 | Sphere.Transparency = self.Propertys.Transparency 29 | 30 | Sphere.CFrame = Transform 31 | Sphere.Radius = Radius 32 | Sphere.AlwaysOnTop = self.Propertys.AlwaysOnTop 33 | Sphere.ZIndex = 1 34 | Sphere.Adornee = Terrain 35 | Sphere.Parent = Terrain 36 | 37 | Ceive.ActiveInstances += 1 38 | 39 | self.Register(Sphere) 40 | self.Ceive.ScheduleCleaning() 41 | end 42 | 43 | function Gizmo:Create(Transform: CFrame, Radius: number) 44 | local PropertyTable = { 45 | Transform = Transform, 46 | Radius = Radius, 47 | AlwaysOnTop = self.Propertys.AlwaysOnTop, 48 | Transparency = self.Propertys.Transparency, 49 | Color3 = self.Propertys.Color3, 50 | Enabled = true, 51 | Destroy = false, 52 | } 53 | 54 | self.Retain(self, PropertyTable) 55 | 56 | return PropertyTable 57 | end 58 | 59 | function Gizmo:Update(PropertyTable) 60 | local Ceive = self.Ceive 61 | 62 | Ceive.PushProperty("AlwaysOnTop", PropertyTable.AlwaysOnTop) 63 | Ceive.PushProperty("Transparency", PropertyTable.Transparency) 64 | Ceive.PushProperty("Color3", PropertyTable.Color3) 65 | 66 | self:Draw(PropertyTable.Transform, PropertyTable.Radius) 67 | end 68 | 69 | return Gizmo 70 | -------------------------------------------------------------------------------- /src/Dependencies/Debug/Gizmo/Gizmos/Wedge.luau: -------------------------------------------------------------------------------- 1 | local Gizmo = {} 2 | Gizmo.__index = Gizmo 3 | 4 | function Gizmo.Init(Ceive, Propertys, Request, Release, Retain) 5 | local self = setmetatable({}, Gizmo) 6 | 7 | self.Ceive = Ceive 8 | self.Propertys = Propertys 9 | self.Request = Request 10 | self.Release = Release 11 | self.Retain = Retain 12 | 13 | return self 14 | end 15 | 16 | function Gizmo:Draw(Transform: CFrame, Size: Vector3, DrawTriangles: boolean) 17 | local Ceive = self.Ceive 18 | 19 | if not Ceive.Enabled then 20 | return 21 | end 22 | 23 | local Position = Transform.Position 24 | local Uv = Transform.UpVector 25 | local Rv = Transform.RightVector 26 | local Lv = Transform.LookVector 27 | local sO2 = Size * 0.5 28 | local sUv = Uv * sO2.Y 29 | local sRv = Rv * sO2.X 30 | local sLv = Lv * sO2.Z 31 | 32 | local YTopLeft 33 | local YTopRight 34 | 35 | local ZBottomLeft 36 | local ZBottomRight 37 | 38 | local function CalculateYFace(lUv, lRv, lLv) 39 | local TopLeft = Position + (lUv - lRv + lLv) 40 | local TopRight = Position + (lUv + lRv + lLv) 41 | local BottomLeft = Position + (lUv - lRv - lLv) 42 | local BottomRight = Position + (lUv + lRv - lLv) 43 | 44 | YTopLeft = TopLeft 45 | YTopRight = TopRight 46 | 47 | Ceive.Ray:Draw(TopLeft, TopRight) 48 | Ceive.Ray:Draw(TopLeft, BottomLeft) 49 | 50 | Ceive.Ray:Draw(TopRight, BottomRight) 51 | if DrawTriangles ~= false then 52 | Ceive.Ray:Draw(TopRight, BottomLeft) 53 | end 54 | 55 | Ceive.Ray:Draw(BottomLeft, BottomRight) 56 | end 57 | 58 | local function CalculateZFace(lUv, lRv, lLv) 59 | local TopLeft = Position + (lUv - lRv + lLv) 60 | local TopRight = Position + (lUv + lRv + lLv) 61 | local BottomLeft = Position + (-lUv - lRv + lLv) 62 | local BottomRight = Position + (-lUv + lRv + lLv) 63 | 64 | ZBottomLeft = TopLeft 65 | ZBottomRight = TopRight 66 | 67 | Ceive.Ray:Draw(TopLeft, TopRight) 68 | Ceive.Ray:Draw(TopLeft, BottomLeft) 69 | 70 | Ceive.Ray:Draw(TopRight, BottomRight) 71 | if DrawTriangles ~= false then 72 | Ceive.Ray:Draw(TopRight, BottomLeft) 73 | end 74 | 75 | Ceive.Ray:Draw(BottomLeft, BottomRight) 76 | end 77 | 78 | CalculateYFace(-sUv, sRv, sLv) 79 | 80 | CalculateZFace(sUv, sRv, -sLv) 81 | 82 | Ceive.Ray:Draw(YTopLeft, ZBottomLeft) 83 | Ceive.Ray:Draw(YTopRight, ZBottomRight) 84 | if DrawTriangles ~= false then 85 | Ceive.Ray:Draw(YTopRight, ZBottomLeft) 86 | end 87 | end 88 | 89 | function Gizmo:Create(Transform: CFrame, Size: Vector3, DrawTriangles: boolean) 90 | local PropertyTable = { 91 | Transform = Transform, 92 | Size = Size, 93 | DrawTriangles = DrawTriangles, 94 | AlwaysOnTop = self.Propertys.AlwaysOnTop, 95 | Transparency = self.Propertys.Transparency, 96 | Color3 = self.Propertys.Color3, 97 | Enabled = true, 98 | Destroy = false, 99 | } 100 | 101 | self.Retain(self, PropertyTable) 102 | 103 | return PropertyTable 104 | end 105 | 106 | function Gizmo:Update(PropertyTable) 107 | local Ceive = self.Ceive 108 | 109 | Ceive.PushProperty("AlwaysOnTop", PropertyTable.AlwaysOnTop) 110 | Ceive.PushProperty("Transparency", PropertyTable.Transparency) 111 | Ceive.PushProperty("Color3", PropertyTable.Color3) 112 | 113 | self:Draw(PropertyTable.Transform, PropertyTable.Size, PropertyTable.DrawTriangles) 114 | end 115 | 116 | return Gizmo 117 | -------------------------------------------------------------------------------- /src/Dependencies/Debug/Gizmo/init.luau: -------------------------------------------------------------------------------- 1 | --[[ 2 | 3 | Acts as a wrapper for Gizmo.lua, respects IsStudio and AllowLiveGameDebug 4 | 5 | ]] 6 | 7 | local Dependencies = script.Parent.Parent 8 | 9 | local Config = require(Dependencies:WaitForChild("Config")) 10 | local Gizmo = require(script:WaitForChild("Gizmo")) 11 | 12 | local IsStudio = game:GetService("RunService"):IsStudio() 13 | local IsEnabled = IsStudio or Config.ALLOW_LIVE_GAME_DEBUG 14 | if IsEnabled then 15 | Gizmo.Init() 16 | end 17 | 18 | type ICeive = Gizmo.ICeive & { Init: nil } 19 | 20 | local Wrapper: ICeive = setmetatable({}, { 21 | __index = function(_, Index) 22 | if IsEnabled then 23 | return Gizmo[Index] 24 | else 25 | local GizmoFunctions = { 26 | SetStyle = true, 27 | AddDebrisInSeconds = true, 28 | PushProperty = true, 29 | PopProperty = true, 30 | AddDebrisInFrames = true, 31 | SetEnabled = true, 32 | DoCleaning = true, 33 | ScheduleCleaning = true, 34 | TweenProperties = true, 35 | } 36 | 37 | if GizmoFunctions[Index] then 38 | return function() end 39 | end 40 | 41 | return { 42 | Draw = function() end, 43 | Create = function() end, 44 | } 45 | end 46 | end, 47 | }) :: any 48 | 49 | return table.freeze(Wrapper) 50 | -------------------------------------------------------------------------------- /src/Dependencies/Debug/ImOverlay/init.luau: -------------------------------------------------------------------------------- 1 | -- TODO: Figure out the metatable stuff we should do here 2 | return require(script.CeiveImOverlay) 3 | -------------------------------------------------------------------------------- /src/Dependencies/DefaultObjectSettings.luau: -------------------------------------------------------------------------------- 1 | local FORCE_MULTIPLIER = 0.2 2 | 3 | return table.freeze({ 4 | Damping = 0.1, 5 | Stiffness = 0.2, 6 | Inertia = 0, 7 | Elasticity = 3, 8 | AnchorDepth = 0, 9 | 10 | AnchorsRotate = false, 11 | 12 | Constraint = "Spring", 13 | Force = Vector3.yAxis * FORCE_MULTIPLIER, 14 | Gravity = -Vector3.yAxis * 25, 15 | 16 | WindType = "Hybrid", 17 | MatchWorkspaceWind = true, 18 | WindInfluence = 1, 19 | WindStrength = 2, 20 | WindSpeed = 1, 21 | WindDirection = Vector3.xAxis, 22 | 23 | UpdateRate = 60, 24 | ActivationDistance = 45, 25 | ThrottleDistance = 15, 26 | }) 27 | -------------------------------------------------------------------------------- /src/Dependencies/Frustum.luau: -------------------------------------------------------------------------------- 1 | --!native 2 | local Dependencies = script.Parent 3 | local Config = require(Dependencies:WaitForChild("Config")) 4 | local Utilities = require(Dependencies:WaitForChild("Utilities")) 5 | 6 | local Class = {} 7 | 8 | function Class.GetCFrames(camera, distance) 9 | debug.profilebegin("Frustum::GetCFrames") 10 | local cameraCFrame = camera.CFrame 11 | local cameraPos = cameraCFrame.Position 12 | local rightVec, upVec = cameraCFrame.RightVector, cameraCFrame.UpVector 13 | 14 | local distance2 = distance * 0.5 15 | local farPlaneHeight2 = math.tan(((camera.FieldOfView + 5) * 0.5) * 0.017453) * distance 16 | local farPlaneWidth2 = farPlaneHeight2 * (camera.ViewportSize.X / camera.ViewportSize.Y) 17 | local farPlaneCFrame = cameraCFrame * CFrame.new(0, 0, -distance) 18 | local farPlaneTopRight = farPlaneCFrame * Vector3.new(farPlaneWidth2, farPlaneHeight2, 0) 19 | local farPlaneBottomLeft = farPlaneCFrame * Vector3.new(-farPlaneWidth2, -farPlaneHeight2, 0) 20 | local farPlaneBottomRight = farPlaneCFrame * Vector3.new(farPlaneWidth2, -farPlaneHeight2, 0) 21 | 22 | local frustumCFrameInverse = (cameraCFrame * CFrame.new(0, 0, -distance2)):Inverse() 23 | 24 | local rightNormal = upVec:Cross(farPlaneBottomRight - cameraPos).Unit 25 | local leftNormal = upVec:Cross(farPlaneBottomLeft - cameraPos).Unit 26 | local topNormal = rightVec:Cross(cameraPos - farPlaneTopRight).Unit 27 | local bottomNormal = rightVec:Cross(cameraPos - farPlaneBottomRight).Unit 28 | debug.profileend() 29 | return frustumCFrameInverse, farPlaneWidth2, farPlaneHeight2, distance2, rightNormal, leftNormal, topNormal, bottomNormal, cameraCFrame 30 | end 31 | 32 | function Class.InViewFrustum( 33 | point, 34 | frustumCFrameInverse, 35 | farPlaneWidth2, 36 | farPlaneHeight2, 37 | distance2, 38 | rightNormal, 39 | leftNormal, 40 | topNormal, 41 | bottomNormal, 42 | cameraCf 43 | ) 44 | debug.profilebegin("Frustum::InViewFrustum") 45 | 46 | local cameraPos = cameraCf.Position 47 | 48 | -- Check if point lies outside frustum OBB 49 | local relativeToOBB = frustumCFrameInverse * point 50 | if 51 | relativeToOBB.X > farPlaneWidth2 52 | or relativeToOBB.X < -farPlaneWidth2 53 | or relativeToOBB.Y > farPlaneHeight2 54 | or relativeToOBB.Y < -farPlaneHeight2 55 | or relativeToOBB.Z > distance2 56 | or relativeToOBB.Z < -distance2 57 | then 58 | debug.profileend() 59 | return false 60 | end 61 | 62 | -- Check if point lies outside a frustum plane 63 | local lookToCell = point - cameraPos 64 | if rightNormal:Dot(lookToCell) < 0 or leftNormal:Dot(lookToCell) > 0 or topNormal:Dot(lookToCell) < 0 or bottomNormal:Dot(lookToCell) > 0 then 65 | debug.profileend() 66 | return false 67 | end 68 | 69 | debug.profileend() 70 | return true 71 | end 72 | 73 | function Class.ObjectInFrustum( 74 | Object, 75 | frustumCFrameInverse, 76 | farPlaneWidth2, 77 | farPlaneHeight2, 78 | distance2, 79 | rightNormal, 80 | leftNormal, 81 | topNormal, 82 | bottomNormal, 83 | cameraCFrame 84 | ) 85 | local CF = Object.CFrame 86 | local Size = Object.Size 87 | 88 | -- Allows for really big root parts to still be checked correctly 89 | local HalfFarPlane = Config.FAR_PLANE * 0.5 90 | local LinePosition = cameraCFrame.Position + (cameraCFrame.LookVector * HalfFarPlane) 91 | 92 | local Closest = Utilities.ClosestPointOnLine(LinePosition, cameraCFrame.LookVector, HalfFarPlane, CF.Position) 93 | local Inside, point = Utilities.ClosestPointInBox(CF, Size, Closest) 94 | 95 | if Inside then 96 | return true 97 | end 98 | 99 | if 100 | Class.InViewFrustum( 101 | point, 102 | frustumCFrameInverse, 103 | farPlaneWidth2, 104 | farPlaneHeight2, 105 | distance2, 106 | rightNormal, 107 | leftNormal, 108 | topNormal, 109 | bottomNormal, 110 | cameraCFrame 111 | ) 112 | then 113 | return true 114 | end 115 | 116 | return false 117 | end 118 | 119 | return Class 120 | -------------------------------------------------------------------------------- /src/Dependencies/Frustum.spec.luau: -------------------------------------------------------------------------------- 1 | local Frustum = require(script.Parent:WaitForChild("Frustum")) 2 | 3 | return function() 4 | local FakeCamera = { 5 | CFrame = CFrame.identity, 6 | FieldOfView = 70, 7 | ViewportSize = Vector2.new(1920, 1080), 8 | } 9 | 10 | local ReturnedCFrames = {} 11 | 12 | describe("Generates CFrames", function() 13 | local SolveStart = os.clock() 14 | local SolveEnd 15 | 16 | ReturnedCFrames = table.pack(Frustum.GetCFrames(FakeCamera, 500)) 17 | SolveEnd = os.clock() 18 | 19 | ReturnedCFrames["n"] = nil 20 | 21 | print(`Solved view frustum in {string.format("%.2f", (SolveEnd - SolveStart) * 1e6)}μs`) 22 | end) 23 | 24 | describe("Point In View", function() 25 | local CloseInView = Vector3.new(0, 0, -5) 26 | local FarPlaneView = Vector3.new(0, 0, -550) 27 | local OutOfView = Vector3.new(0, 0, 5) 28 | 29 | it("Close In View Point", function() 30 | expect(Frustum.InViewFrustum(CloseInView, table.unpack(ReturnedCFrames))).to.equal(true) 31 | end) 32 | 33 | it("Past FarPlane Point", function() 34 | expect(Frustum.InViewFrustum(FarPlaneView, table.unpack(ReturnedCFrames))).to.equal(false) 35 | end) 36 | 37 | it("Out Of View Point", function() 38 | expect(Frustum.InViewFrustum(OutOfView, table.unpack(ReturnedCFrames))).to.equal(false) 39 | end) 40 | end) 41 | 42 | describe("Object In View", function() 43 | local CloseFakeObject = { 44 | CFrame = CFrame.new(0, 0, -5), 45 | Size = Vector3.new(1, 1, 3), 46 | } 47 | 48 | local FarFakeObject = { 49 | CFrame = CFrame.new(0, 0, -550), 50 | Size = Vector3.new(1, 1, 3), 51 | } 52 | 53 | local OutOfViewFakeObject = { 54 | CFrame = CFrame.new(0, 0, 5), 55 | Size = Vector3.new(1, 1, 3), 56 | } 57 | 58 | it("Close In View Object", function() 59 | expect(Frustum.ObjectInFrustum(CloseFakeObject, table.unpack(ReturnedCFrames))).to.equal(true) 60 | end) 61 | 62 | it("Past FarPlane Object", function() 63 | expect(Frustum.ObjectInFrustum(FarFakeObject, table.unpack(ReturnedCFrames))).to.equal(false) 64 | end) 65 | 66 | it("Out Of View Object", function() 67 | expect(Frustum.ObjectInFrustum(OutOfViewFakeObject, table.unpack(ReturnedCFrames))).to.equal(false) 68 | end) 69 | end) 70 | end 71 | -------------------------------------------------------------------------------- /src/Dependencies/Iris/API.luau: -------------------------------------------------------------------------------- 1 | local Types = require(script.Parent.Types) 2 | 3 | return function(Iris: Types.Iris) 4 | -- basic wrapper for nearly every widget, saves space. 5 | local function wrapper(name: string): (arguments: Types.WidgetArguments?, states: Types.States?) -> Types.Widget 6 | return function(arguments: Types.WidgetArguments?, states: Types.States?): Types.Widget 7 | return Iris.Internal._Insert(name, arguments, states) 8 | end 9 | end 10 | 11 | --[[ 12 | ---------------------------- 13 | [SECTION] Window API 14 | ---------------------------- 15 | ]] 16 | 17 | Iris.Window = wrapper("Window") 18 | 19 | Iris.SetFocusedWindow = Iris.Internal.SetFocusedWindow 20 | 21 | Iris.Tooltip = wrapper("Tooltip") 22 | 23 | Iris.MenuBar = wrapper("MenuBar") 24 | 25 | Iris.Menu = wrapper("Menu") 26 | 27 | Iris.MenuItem = wrapper("MenuItem") 28 | 29 | Iris.MenuToggle = wrapper("MenuToggle") 30 | 31 | Iris.Separator = wrapper("Separator") 32 | 33 | Iris.Indent = wrapper("Indent") 34 | 35 | Iris.SameLine = wrapper("SameLine") 36 | 37 | Iris.Group = wrapper("Group") 38 | 39 | Iris.Text = wrapper("Text") 40 | 41 | Iris.TextWrapped = function(arguments: Types.WidgetArguments): Types.Widget 42 | arguments[2] = true 43 | return Iris.Internal._Insert("Text", arguments) 44 | end 45 | 46 | Iris.TextColored = function(arguments: Types.WidgetArguments): Types.Widget 47 | arguments[3] = arguments[2] 48 | arguments[2] = nil 49 | return Iris.Internal._Insert("Text", arguments) 50 | end 51 | 52 | Iris.SeparatorText = wrapper("SeparatorText") 53 | 54 | Iris.InputText = wrapper("InputText") 55 | 56 | Iris.Button = wrapper("Button") 57 | 58 | Iris.SmallButton = wrapper("SmallButton") 59 | 60 | Iris.Checkbox = wrapper("Checkbox") 61 | 62 | Iris.RadioButton = wrapper("RadioButton") 63 | 64 | Iris.Tree = wrapper("Tree") 65 | 66 | Iris.CollapsingHeader = wrapper("CollapsingHeader") 67 | 68 | Iris.InputNum = wrapper("InputNum") 69 | 70 | Iris.InputVector2 = wrapper("InputVector2") 71 | 72 | Iris.InputVector3 = wrapper("InputVector3") 73 | 74 | Iris.InputUDim = wrapper("InputUDim") 75 | 76 | Iris.InputUDim2 = wrapper("InputUDim2") 77 | 78 | Iris.InputRect = wrapper("InputRect") 79 | 80 | Iris.DragNum = wrapper("DragNum") 81 | 82 | Iris.DragVector2 = wrapper("DragVector2") 83 | 84 | Iris.DragVector3 = wrapper("DragVector3") 85 | 86 | Iris.DragUDim = wrapper("DragUDim") 87 | 88 | Iris.DragUDim2 = wrapper("DragUDim2") 89 | 90 | Iris.DragRect = wrapper("DragRect") 91 | 92 | Iris.InputColor3 = wrapper("InputColor3") 93 | 94 | Iris.InputColor4 = wrapper("InputColor4") 95 | 96 | Iris.SliderNum = wrapper("SliderNum") 97 | 98 | Iris.SliderVector2 = wrapper("SliderVector2") 99 | 100 | Iris.SliderVector3 = wrapper("SliderVector3") 101 | 102 | Iris.SliderUDim = wrapper("SliderUDim") 103 | 104 | Iris.SliderUDim2 = wrapper("SliderUDim2") 105 | 106 | Iris.SliderRect = wrapper("SliderRect") 107 | 108 | Iris.Selectable = wrapper("Selectable") 109 | 110 | Iris.Combo = wrapper("Combo") 111 | 112 | Iris.ComboArray = function(arguments: Types.WidgetArguments, states: Types.WidgetStates?, selectionArray: { any }) 113 | local defaultState 114 | if states == nil then 115 | defaultState = Iris.State(selectionArray[1]) 116 | else 117 | defaultState = states 118 | end 119 | local thisWidget = Iris.Internal._Insert("Combo", arguments, defaultState) 120 | local sharedIndex: Types.State = thisWidget.state.index 121 | for _, Selection in selectionArray do 122 | Iris.Internal._Insert("Selectable", { Selection, Selection }, { index = sharedIndex } :: Types.States) 123 | end 124 | Iris.End() 125 | 126 | return thisWidget 127 | end 128 | 129 | Iris.ComboEnum = function(arguments: Types.WidgetArguments, states: Types.WidgetStates?, enumType: Enum) 130 | local defaultState 131 | if states == nil then 132 | defaultState = Iris.State(enumType[1]) 133 | else 134 | defaultState = states 135 | end 136 | local thisWidget = Iris.Internal._Insert("Combo", arguments, defaultState) 137 | local sharedIndex = thisWidget.state.index 138 | for _, Selection in enumType:GetEnumItems() do 139 | Iris.Internal._Insert("Selectable", { Selection.Name, Selection }, { index = sharedIndex } :: Types.States) 140 | end 141 | Iris.End() 142 | 143 | return thisWidget 144 | end 145 | Iris.InputEnum = Iris.ComboEnum 146 | 147 | Iris.Table = wrapper("Table") 148 | 149 | Iris.NextColumn = function() 150 | Iris.Internal._GetParentWidget().RowColumnIndex += 1 151 | end 152 | 153 | Iris.SetColumnIndex = function(columnIndex: number) 154 | local ParentWidget: Types.Widget = Iris.Internal._GetParentWidget() 155 | assert(columnIndex >= ParentWidget.InitialNumColumns, "Iris.SetColumnIndex Argument must be in column range") 156 | ParentWidget.RowColumnIndex = math.floor(ParentWidget.RowColumnIndex / ParentWidget.InitialNumColumns) + (columnIndex - 1) 157 | end 158 | 159 | Iris.NextRow = function() 160 | -- sets column Index back to 0, increments Row 161 | local ParentWidget: Types.Widget = Iris.Internal._GetParentWidget() 162 | local InitialNumColumns: number = ParentWidget.InitialNumColumns 163 | local nextRow: number = math.floor((ParentWidget.RowColumnIndex + 1) / InitialNumColumns) * InitialNumColumns 164 | ParentWidget.RowColumnIndex = nextRow 165 | end 166 | end 167 | -------------------------------------------------------------------------------- /src/Dependencies/Iris/widgets/Button.luau: -------------------------------------------------------------------------------- 1 | local Types = require(script.Parent.Parent.Types) 2 | 3 | return function(Iris: Types.Internal, widgets: Types.WidgetUtility) 4 | local abstractButton = { 5 | hasState = false, 6 | hasChildren = false, 7 | Args = { 8 | ["Text"] = 1, 9 | }, 10 | Events = { 11 | ["clicked"] = widgets.EVENTS.click(function(thisWidget: Types.Widget) 12 | return thisWidget.Instance 13 | end), 14 | ["rightClicked"] = widgets.EVENTS.rightClick(function(thisWidget: Types.Widget) 15 | return thisWidget.Instance 16 | end), 17 | ["doubleClicked"] = widgets.EVENTS.doubleClick(function(thisWidget: Types.Widget) 18 | return thisWidget.Instance 19 | end), 20 | ["ctrlClicked"] = widgets.EVENTS.ctrlClick(function(thisWidget: Types.Widget) 21 | return thisWidget.Instance 22 | end), 23 | ["hovered"] = widgets.EVENTS.hover(function(thisWidget: Types.Widget) 24 | return thisWidget.Instance 25 | end), 26 | }, 27 | Generate = function(thisWidget: Types.Widget): TextButton 28 | local Button: TextButton = Instance.new("TextButton") 29 | Button.Size = UDim2.fromOffset(0, 0) 30 | Button.BackgroundColor3 = Iris._config.ButtonColor 31 | Button.BackgroundTransparency = Iris._config.ButtonTransparency 32 | Button.AutoButtonColor = false 33 | 34 | widgets.applyTextStyle(Button) 35 | Button.AutomaticSize = Enum.AutomaticSize.XY 36 | 37 | widgets.applyFrameStyle(Button) 38 | 39 | widgets.applyInteractionHighlights(Button, Button, { 40 | ButtonColor = Iris._config.ButtonColor, 41 | ButtonTransparency = Iris._config.ButtonTransparency, 42 | ButtonHoveredColor = Iris._config.ButtonHoveredColor, 43 | ButtonHoveredTransparency = Iris._config.ButtonHoveredTransparency, 44 | ButtonActiveColor = Iris._config.ButtonActiveColor, 45 | ButtonActiveTransparency = Iris._config.ButtonActiveTransparency, 46 | }) 47 | 48 | Button.ZIndex = thisWidget.ZIndex 49 | Button.LayoutOrder = thisWidget.ZIndex 50 | 51 | return Button 52 | end, 53 | Update = function(thisWidget: Types.Widget) 54 | local Button = thisWidget.Instance :: TextButton 55 | Button.Text = thisWidget.arguments.Text or "Button" 56 | end, 57 | Discard = function(thisWidget: Types.Widget) 58 | thisWidget.Instance:Destroy() 59 | end, 60 | } :: Types.WidgetClass 61 | widgets.abstractButton = abstractButton 62 | 63 | Iris.WidgetConstructor( 64 | "Button", 65 | widgets.extend(abstractButton, { 66 | Generate = function(thisWidget: Types.Widget): TextButton 67 | local Button: TextButton = abstractButton.Generate(thisWidget) 68 | Button.Name = "Iris_Button" 69 | 70 | return Button 71 | end, 72 | } :: Types.WidgetClass) 73 | ) 74 | 75 | Iris.WidgetConstructor( 76 | "SmallButton", 77 | widgets.extend(abstractButton, { 78 | Generate = function(thisWidget: Types.Widget): TextButton 79 | local SmallButton = abstractButton.Generate(thisWidget) :: TextButton 80 | SmallButton.Name = "Iris_SmallButton" 81 | 82 | local uiPadding: UIPadding = SmallButton.UIPadding 83 | uiPadding.PaddingLeft = UDim.new(0, 2) 84 | uiPadding.PaddingRight = UDim.new(0, 2) 85 | uiPadding.PaddingTop = UDim.new(0, 0) 86 | uiPadding.PaddingBottom = UDim.new(0, 0) 87 | 88 | return SmallButton 89 | end, 90 | } :: Types.WidgetClass) 91 | ) 92 | end 93 | -------------------------------------------------------------------------------- /src/Dependencies/Iris/widgets/Root.luau: -------------------------------------------------------------------------------- 1 | local Types = require(script.Parent.Parent.Types) 2 | 3 | return function(Iris: Types.Internal, widgets: Types.WidgetUtility) 4 | local NumNonWindowChildren: number = 0 5 | 6 | Iris.WidgetConstructor("Root", { 7 | hasState = false, 8 | hasChildren = true, 9 | Args = {}, 10 | Events = {}, 11 | Generate = function(_thisWidget: Types.Widget) 12 | local Root: Folder = Instance.new("Folder") 13 | Root.Name = "Iris_Root" 14 | 15 | local PseudoWindowScreenGui 16 | if Iris._config.UseScreenGUIs then 17 | PseudoWindowScreenGui = Instance.new("ScreenGui") 18 | PseudoWindowScreenGui.ResetOnSpawn = false 19 | PseudoWindowScreenGui.DisplayOrder = Iris._config.DisplayOrderOffset 20 | PseudoWindowScreenGui.IgnoreGuiInset = Iris._config.IgnoreGuiInset 21 | else 22 | PseudoWindowScreenGui = Instance.new("Folder") 23 | end 24 | PseudoWindowScreenGui.Name = "PseudoWindowScreenGui" 25 | PseudoWindowScreenGui.Parent = Root 26 | 27 | local PopupScreenGui 28 | if Iris._config.UseScreenGUIs then 29 | PopupScreenGui = Instance.new("ScreenGui") 30 | PopupScreenGui.ResetOnSpawn = false 31 | PopupScreenGui.DisplayOrder = Iris._config.DisplayOrderOffset + 1024 -- room for 1024 regular windows before overlap 32 | PopupScreenGui.IgnoreGuiInset = Iris._config.IgnoreGuiInset 33 | 34 | local TooltipContainer: Frame = Instance.new("Frame") 35 | TooltipContainer.Name = "TooltipContainer" 36 | TooltipContainer.AutomaticSize = Enum.AutomaticSize.XY 37 | TooltipContainer.Size = UDim2.fromOffset(0, 0) 38 | TooltipContainer.BackgroundTransparency = 1 39 | TooltipContainer.BorderSizePixel = 0 40 | 41 | widgets.UIListLayout(TooltipContainer, Enum.FillDirection.Vertical, UDim.new(0, Iris._config.PopupBorderSize)) 42 | 43 | TooltipContainer.Parent = PopupScreenGui 44 | 45 | local MenuBarContainer: Frame = Instance.new("Frame") 46 | MenuBarContainer.Name = "MenuBarContainer" 47 | MenuBarContainer.AutomaticSize = Enum.AutomaticSize.Y 48 | MenuBarContainer.Size = UDim2.fromScale(1, 0) 49 | MenuBarContainer.BackgroundTransparency = 1 50 | MenuBarContainer.BorderSizePixel = 0 51 | 52 | MenuBarContainer.Parent = PopupScreenGui 53 | else 54 | PopupScreenGui = Instance.new("Folder") 55 | end 56 | PopupScreenGui.Name = "PopupScreenGui" 57 | PopupScreenGui.Parent = Root 58 | 59 | local PseudoWindow: Frame = Instance.new("Frame") 60 | PseudoWindow.Name = "PseudoWindow" 61 | PseudoWindow.Size = UDim2.new(0, 0, 0, 0) 62 | PseudoWindow.Position = UDim2.fromOffset(0, 22) 63 | PseudoWindow.AutomaticSize = Enum.AutomaticSize.XY 64 | PseudoWindow.BackgroundTransparency = Iris._config.WindowBgTransparency 65 | PseudoWindow.BackgroundColor3 = Iris._config.WindowBgColor 66 | PseudoWindow.BorderSizePixel = Iris._config.WindowBorderSize 67 | PseudoWindow.BorderColor3 = Iris._config.BorderColor 68 | 69 | PseudoWindow.Selectable = false 70 | PseudoWindow.SelectionGroup = true 71 | PseudoWindow.SelectionBehaviorUp = Enum.SelectionBehavior.Stop 72 | PseudoWindow.SelectionBehaviorDown = Enum.SelectionBehavior.Stop 73 | PseudoWindow.SelectionBehaviorLeft = Enum.SelectionBehavior.Stop 74 | PseudoWindow.SelectionBehaviorRight = Enum.SelectionBehavior.Stop 75 | 76 | PseudoWindow.Visible = false 77 | 78 | widgets.UIPadding(PseudoWindow, Iris._config.WindowPadding) 79 | widgets.UIListLayout(PseudoWindow, Enum.FillDirection.Vertical, UDim.new(0, Iris._config.ItemSpacing.Y)) 80 | 81 | PseudoWindow.Parent = PseudoWindowScreenGui 82 | 83 | return Root 84 | end, 85 | Update = function(thisWidget: Types.Widget) 86 | if NumNonWindowChildren > 0 then 87 | local Root = thisWidget.Instance :: any 88 | local PseudoWindowScreenGui = Root.PseudoWindowScreenGui :: any 89 | local PseudoWindow: Frame = PseudoWindowScreenGui.PseudoWindow 90 | PseudoWindow.Visible = true 91 | end 92 | end, 93 | Discard = function(thisWidget: Types.Widget) 94 | NumNonWindowChildren = 0 95 | thisWidget.Instance:Destroy() 96 | end, 97 | ChildAdded = function(thisWidget: Types.Widget, childWidget: Types.Widget) 98 | local Root = thisWidget.Instance :: any 99 | 100 | if childWidget.type == "Window" then 101 | return thisWidget.Instance 102 | elseif childWidget.type == "Tooltip" then 103 | return Root.PopupScreenGui.TooltipContainer 104 | elseif childWidget.type == "MenuBar" then 105 | return Root.PopupScreenGui.MenuBarContainer 106 | else 107 | local PseudoWindowScreenGui = Root.PseudoWindowScreenGui :: any 108 | local PseudoWindow: Frame = PseudoWindowScreenGui.PseudoWindow 109 | 110 | NumNonWindowChildren += 1 111 | PseudoWindow.Visible = true 112 | 113 | return PseudoWindow 114 | end 115 | end, 116 | ChildDiscarded = function(thisWidget: Types.Widget, childWidget: Types.Widget) 117 | if childWidget.type ~= "Window" and childWidget.type ~= "Tooltip" and childWidget.type ~= "MenuBar" then 118 | NumNonWindowChildren -= 1 119 | if NumNonWindowChildren == 0 then 120 | local Root = thisWidget.Instance :: any 121 | local PseudoWindowScreenGui = Root.PseudoWindowScreenGui :: any 122 | local PseudoWindow: Frame = PseudoWindowScreenGui.PseudoWindow 123 | PseudoWindow.Visible = false 124 | end 125 | end 126 | end, 127 | } :: Types.WidgetClass) 128 | end 129 | -------------------------------------------------------------------------------- /src/Dependencies/Runtime.client.luau: -------------------------------------------------------------------------------- 1 | local Actor: Actor = script.Parent 2 | local RootObject 3 | local ColliderDescriptions 4 | local SmartboneModule 5 | local SmartboneClass 6 | 7 | local Setup = false 8 | 9 | local CONNECTIONS = {} 10 | 11 | local function c(Conn: RBXScriptConnection) 12 | table.insert(CONNECTIONS, Conn) 13 | end 14 | 15 | local function cleanup() 16 | for _, Conn: RBXScriptConnection in CONNECTIONS do 17 | Conn:Disconnect() 18 | end 19 | end 20 | 21 | local Bind 22 | Bind = Actor:BindToMessage("Setup", function(m_Object, m_ColliderDescriptions, m_SmartBone) 23 | RootObject = m_Object 24 | ColliderDescriptions = m_ColliderDescriptions 25 | SmartboneModule = m_SmartBone 26 | SmartboneClass = require(m_SmartBone) 27 | 28 | Setup = true 29 | 30 | Bind:Disconnect() 31 | end) 32 | 33 | repeat 34 | task.wait() 35 | until Setup 36 | 37 | local CollectionService = game:GetService("CollectionService") 38 | local RunService = game:GetService("RunService") 39 | local BonePhysics = SmartboneClass.new() 40 | local Dependencies = SmartboneModule.Dependencies 41 | local DebugUi = require(Dependencies.Debug.DebugUi) 42 | local Iris 43 | local Config = require(Dependencies.Config) 44 | local Utilities = require(Dependencies.Utilities) 45 | local ShouldDebug = RunService:IsStudio() or Config.ALLOW_LIVE_GAME_DEBUG 46 | local OverlayEvent = SmartboneModule:WaitForChild("OverlayEvent") 47 | 48 | local ForceDestroy = false 49 | 50 | -- So much work for such a basic debug tool 51 | local ImOverlay = { 52 | Begin = function(...) 53 | OverlayEvent:Fire("Begin", ...) 54 | end, 55 | End = function(...) 56 | OverlayEvent:Fire("End", ...) 57 | end, 58 | Text = function(...) 59 | OverlayEvent:Fire("Text", ...) 60 | end, 61 | } 62 | 63 | -- Frame counter for getting animatedworldcframe 64 | shared.FrameCounter = 0 65 | local FrameCounterOverflow = 2 ^ 17 -- Maximum number frame counter can go to before it resets to 0 =(131072) 66 | 67 | if ShouldDebug then 68 | Iris = require(Dependencies.Iris) 69 | if not Iris.HasInit() then 70 | Iris = Iris.Init() 71 | end 72 | end 73 | 74 | Actor.Name = `{RootObject.Name} - {BonePhysics.ID}` 75 | 76 | BonePhysics:LoadObject(RootObject) 77 | 78 | for _, ColliderDescription in ColliderDescriptions do 79 | BonePhysics:LoadRawCollider(ColliderDescription[1], ColliderDescription[2]) 80 | end 81 | 82 | local DebugState 83 | 84 | if ShouldDebug then 85 | DebugState = { 86 | DRAW_BONE = Iris.State(false), 87 | DRAW_PHYSICAL_BONE = Iris.State(false), 88 | DRAW_ROOT_PART = Iris.State(false), 89 | DRAW_BOUNDING_BOX = Iris.State(false), 90 | DRAW_AXIS_LIMITS = Iris.State(false), 91 | DRAW_COLLIDERS = Iris.State(false), 92 | DRAW_COLLIDER_INFLUENCE = Iris.State(false), 93 | DRAW_COLLIDER_AWAKE = Iris.State(false), 94 | DRAW_COLLIDER_BROADPHASE = Iris.State(false), 95 | DRAW_FILL_COLLIDERS = Iris.State(false), 96 | DRAW_CONTACTS = Iris.State(false), 97 | DRAW_ROTATION_LIMITS = Iris.State(false), 98 | DRAW_ACCELERATION_INFO = Iris.State(false), 99 | } 100 | end 101 | 102 | -- ShouldDebug is just if we are in studio or not 103 | if ShouldDebug then 104 | Iris:Connect(function() 105 | if RootObject:GetAttribute("Debug") ~= nil then 106 | DebugUi(Iris, BonePhysics, DebugState) 107 | end 108 | end) 109 | end 110 | 111 | c(CollectionService:GetInstanceAddedSignal("SmartCollider"):Connect(function(Object: BasePart) 112 | if not Object:IsA("BasePart") then 113 | return 114 | end 115 | 116 | local ColliderKey = Object:GetAttribute("ColliderKey") 117 | local RootColliderKey = RootObject:GetAttribute("ColliderKey") 118 | 119 | if tostring(ColliderKey) ~= tostring(RootColliderKey) then 120 | return 121 | end 122 | 123 | local ColliderObject = Utilities.GetCollider(Object) 124 | 125 | BonePhysics:LoadRawCollider(ColliderObject, Object) 126 | end)) 127 | 128 | c(Actor:BindToMessage("Destroy", function() 129 | ForceDestroy = true 130 | end)) 131 | 132 | c(RunService.Heartbeat:ConnectParallel(function(deltaTime) 133 | shared.FrameCounter += 1 134 | 135 | if shared.FrameCounter > FrameCounterOverflow then 136 | shared.FrameCounter = 0 137 | end 138 | 139 | BonePhysics:StepBoneTrees(deltaTime) 140 | 141 | if BonePhysics.ShouldDestroy or ForceDestroy then 142 | BonePhysics:Destroy() 143 | 144 | task.synchronize() 145 | cleanup() 146 | Actor:Destroy() 147 | return 148 | end 149 | 150 | -- ShouldDebug is just if we are in studio or not 151 | if ShouldDebug then 152 | if RootObject:GetAttribute("Debug") ~= nil then 153 | task.synchronize() 154 | BonePhysics:DrawDebug( 155 | DebugState.DRAW_COLLIDERS:get(), 156 | DebugState.DRAW_CONTACTS:get(), 157 | DebugState.DRAW_PHYSICAL_BONE:get(), 158 | DebugState.DRAW_BONE:get(), 159 | DebugState.DRAW_AXIS_LIMITS:get(), 160 | DebugState.DRAW_ROOT_PART:get(), 161 | DebugState.DRAW_FILL_COLLIDERS:get(), 162 | DebugState.DRAW_COLLIDER_INFLUENCE:get(), 163 | DebugState.DRAW_COLLIDER_AWAKE:get(), 164 | DebugState.DRAW_COLLIDER_BROADPHASE:get(), 165 | DebugState.DRAW_BOUNDING_BOX:get(), 166 | DebugState.DRAW_ROTATION_LIMITS:get(), 167 | DebugState.DRAW_ACCELERATION_INFO:get() 168 | ) 169 | 170 | BonePhysics:DrawOverlay(ImOverlay) 171 | end 172 | end 173 | end)) 174 | -------------------------------------------------------------------------------- /stylua.toml: -------------------------------------------------------------------------------- 1 | column_width = 150 2 | quote_style = "AutoPreferDouble" 3 | 4 | [sort_requires] 5 | enabled = true 6 | -------------------------------------------------------------------------------- /testez-companion.toml: -------------------------------------------------------------------------------- 1 | roots = ["ReplicatedStorage/SmartBone"] 2 | -------------------------------------------------------------------------------- /wally.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "jakeywastaken/smartbone-2" 3 | description = "Revamped release of SmartBone (legacy)" 4 | version = "0.5.0" 5 | license = "MIT" 6 | authors = ["CelnakRBLX", "JakeyWasTaken", "LoadingL0n3ly"] 7 | registry = "https://github.com/UpliftGames/wally-index" 8 | realm = "shared" 9 | 10 | exclude = ["**"] 11 | include = ["src-build", "src-build/*", "default.project.json", "wally.toml", "LICENSE"] 12 | --------------------------------------------------------------------------------