├── .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 | 
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 | 
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 |
--------------------------------------------------------------------------------