diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000..622bd36 --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,18 @@ +name: CI + +on: + push: + branches: + - master + pull_request: + branches: + - master + +jobs: + ci: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: CompeyDev/setup-rokit@v0.1.2 + - run: selene . + - run: stylua --check . diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 0000000..8a946b6 --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,24 @@ +name: Release + +on: + push: + branches: + - master + +jobs: + release: + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + - uses: CompeyDev/setup-rokit@v0.1.2 + - run: selene . + - run: stylua --check . + - run: rojo build --output build.rbxm release.project.json + - run: echo "VERSION=$(cat pesde.toml | grep -Po 'version = \"\K([0-9.]+)')" >> "$GITHUB_ENV" + - run: echo "NAME=$(cat pesde.toml | grep -Po 'name = \".*/\K([a-zA-Z_]+)')" >> "$GITHUB_ENV" + - uses: ncipollo/release-action@v1 + with: + artifacts: ${{ format('{0}.rbxm', env.NAME) }} + tag: ${{ env.VERSION }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0c573a1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,17 @@ +# Project place file +/waypoints.rbxlx + +# Roblox Studio lock files +/*.rbxlx.lock +/*.rbxl.lock + +# Roblox Studio model files +/*.rbxm + +# Pesde +roblox_packages/ +.pesde/ +/pesde.lock + +# Rojo files +/sourcemap.json \ No newline at end of file diff --git a/.luaurc b/.luaurc new file mode 100644 index 0000000..00b3bf0 --- /dev/null +++ b/.luaurc @@ -0,0 +1,3 @@ +{ + "languageMode": "strict" +} diff --git a/.styluaignore b/.styluaignore new file mode 100644 index 0000000..14b6451 --- /dev/null +++ b/.styluaignore @@ -0,0 +1 @@ +roblox_packages/ \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..6174c92 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "luau-lsp.require.directoryAliases": { + "@lune/": "~/.lune/.typedefs/0.8.9/" + }, + "files.eol": "\n" // If youre on windows +} diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..da6ab6c --- /dev/null +++ b/LICENSE @@ -0,0 +1,396 @@ +Attribution 4.0 International + +======================================================================= + +Creative Commons Corporation ("Creative Commons") is not a law firm and +does not provide legal services or legal advice. Distribution of +Creative Commons public licenses does not create a lawyer-client or +other relationship. Creative Commons makes its licenses and related +information available on an "as-is" basis. Creative Commons gives no +warranties regarding its licenses, any material licensed under their +terms and conditions, or any related information. Creative Commons +disclaims all liability for damages resulting from their use to the +fullest extent possible. + +Using Creative Commons Public Licenses + +Creative Commons public licenses provide a standard set of terms and +conditions that creators and other rights holders may use to share +original works of authorship and other material subject to copyright +and certain other rights specified in the public license below. The +following considerations are for informational purposes only, are not +exhaustive, and do not form part of our licenses. + + Considerations for licensors: Our public licenses are + intended for use by those authorized to give the public + permission to use material in ways otherwise restricted by + copyright and certain other rights. Our licenses are + irrevocable. Licensors should read and understand the terms + and conditions of the license they choose before applying it. + Licensors should also secure all rights necessary before + applying our licenses so that the public can reuse the + material as expected. Licensors should clearly mark any + material not subject to the license. This includes other CC- + licensed material, or material used under an exception or + limitation to copyright. More considerations for licensors: + wiki.creativecommons.org/Considerations_for_licensors + + Considerations for the public: By using one of our public + licenses, a licensor grants the public permission to use the + licensed material under specified terms and conditions. If + the licensor's permission is not necessary for any reason--for + example, because of any applicable exception or limitation to + copyright--then that use is not regulated by the license. Our + licenses grant only permissions under copyright and certain + other rights that a licensor has authority to grant. Use of + the licensed material may still be restricted for other + reasons, including because others have copyright or other + rights in the material. A licensor may make special requests, + such as asking that all changes be marked or described. + Although not required by our licenses, you are encouraged to + respect those requests where reasonable. More considerations + for the public: + wiki.creativecommons.org/Considerations_for_licensees + +======================================================================= + +Creative Commons Attribution 4.0 International Public License + +By exercising the Licensed Rights (defined below), You accept and agree +to be bound by the terms and conditions of this Creative Commons +Attribution 4.0 International Public License ("Public License"). To the +extent this Public License may be interpreted as a contract, You are +granted the Licensed Rights in consideration of Your acceptance of +these terms and conditions, and the Licensor grants You such rights in +consideration of benefits the Licensor receives from making the +Licensed Material available under these terms and conditions. + + +Section 1 -- Definitions. + + a. Adapted Material means material subject to Copyright and Similar + Rights that is derived from or based upon the Licensed Material + and in which the Licensed Material is translated, altered, + arranged, transformed, or otherwise modified in a manner requiring + permission under the Copyright and Similar Rights held by the + Licensor. For purposes of this Public License, where the Licensed + Material is a musical work, performance, or sound recording, + Adapted Material is always produced where the Licensed Material is + synched in timed relation with a moving image. + + b. Adapter's License means the license You apply to Your Copyright + and Similar Rights in Your contributions to Adapted Material in + accordance with the terms and conditions of this Public License. + + c. Copyright and Similar Rights means copyright and/or similar rights + closely related to copyright including, without limitation, + performance, broadcast, sound recording, and Sui Generis Database + Rights, without regard to how the rights are labeled or + categorized. For purposes of this Public License, the rights + specified in Section 2(b)(1)-(2) are not Copyright and Similar + Rights. + + d. Effective Technological Measures means those measures that, in the + absence of proper authority, may not be circumvented under laws + fulfilling obligations under Article 11 of the WIPO Copyright + Treaty adopted on December 20, 1996, and/or similar international + agreements. + + e. Exceptions and Limitations means fair use, fair dealing, and/or + any other exception or limitation to Copyright and Similar Rights + that applies to Your use of the Licensed Material. + + f. Licensed Material means the artistic or literary work, database, + or other material to which the Licensor applied this Public + License. + + g. Licensed Rights means the rights granted to You subject to the + terms and conditions of this Public License, which are limited to + all Copyright and Similar Rights that apply to Your use of the + Licensed Material and that the Licensor has authority to license. + + h. Licensor means the individual(s) or entity(ies) granting rights + under this Public License. + + i. Share means to provide material to the public by any means or + process that requires permission under the Licensed Rights, such + as reproduction, public display, public performance, distribution, + dissemination, communication, or importation, and to make material + available to the public including in ways that members of the + public may access the material from a place and at a time + individually chosen by them. + + j. Sui Generis Database Rights means rights other than copyright + resulting from Directive 96/9/EC of the European Parliament and of + the Council of 11 March 1996 on the legal protection of databases, + as amended and/or succeeded, as well as other essentially + equivalent rights anywhere in the world. + + k. You means the individual or entity exercising the Licensed Rights + under this Public License. Your has a corresponding meaning. + + +Section 2 -- Scope. + + a. License grant. + + 1. Subject to the terms and conditions of this Public License, + the Licensor hereby grants You a worldwide, royalty-free, + non-sublicensable, non-exclusive, irrevocable license to + exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or + in part; and + + b. produce, reproduce, and Share Adapted Material. + + 2. Exceptions and Limitations. For the avoidance of doubt, where + Exceptions and Limitations apply to Your use, this Public + License does not apply, and You do not need to comply with + its terms and conditions. + + 3. Term. The term of this Public License is specified in Section + 6(a). + + 4. Media and formats; technical modifications allowed. The + Licensor authorizes You to exercise the Licensed Rights in + all media and formats whether now known or hereafter created, + and to make technical modifications necessary to do so. The + Licensor waives and/or agrees not to assert any right or + authority to forbid You from making technical modifications + necessary to exercise the Licensed Rights, including + technical modifications necessary to circumvent Effective + Technological Measures. For purposes of this Public License, + simply making modifications authorized by this Section 2(a) + (4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor -- Licensed Material. Every + recipient of the Licensed Material automatically + receives an offer from the Licensor to exercise the + Licensed Rights under the terms and conditions of this + Public License. + + b. No downstream restrictions. You may not offer or impose + any additional or different terms or conditions on, or + apply any Effective Technological Measures to, the + Licensed Material if doing so restricts exercise of the + Licensed Rights by any recipient of the Licensed + Material. + + 6. No endorsement. Nothing in this Public License constitutes or + may be construed as permission to assert or imply that You + are, or that Your use of the Licensed Material is, connected + with, or sponsored, endorsed, or granted official status by, + the Licensor or others designated to receive attribution as + provided in Section 3(a)(1)(A)(i). + + b. Other rights. + + 1. Moral rights, such as the right of integrity, are not + licensed under this Public License, nor are publicity, + privacy, and/or other similar personality rights; however, to + the extent possible, the Licensor waives and/or agrees not to + assert any such rights held by the Licensor to the limited + extent necessary to allow You to exercise the Licensed + Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this + Public License. + + 3. To the extent possible, the Licensor waives any right to + collect royalties from You for the exercise of the Licensed + Rights, whether directly or through a collecting society + under any voluntary or waivable statutory or compulsory + licensing scheme. In all other cases the Licensor expressly + reserves any right to collect such royalties. + + +Section 3 -- License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the +following conditions. + + a. Attribution. + + 1. If You Share the Licensed Material (including in modified + form), You must: + + a. retain the following if it is supplied by the Licensor + with the Licensed Material: + + i. identification of the creator(s) of the Licensed + Material and any others designated to receive + attribution, in any reasonable manner requested by + the Licensor (including by pseudonym if + designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of + warranties; + + v. a URI or hyperlink to the Licensed Material to the + extent reasonably practicable; + + b. indicate if You modified the Licensed Material and + retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this + Public License, and include the text of, or the URI or + hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any + reasonable manner based on the medium, means, and context in + which You Share the Licensed Material. For example, it may be + reasonable to satisfy the conditions by providing a URI or + hyperlink to a resource that includes the required + information. + + 3. If requested by the Licensor, You must remove any of the + information required by Section 3(a)(1)(A) to the extent + reasonably practicable. + + 4. If You Share Adapted Material You produce, the Adapter's + License You apply must not prevent recipients of the Adapted + Material from complying with this Public License. + + +Section 4 -- Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that +apply to Your use of the Licensed Material: + + a. for the avoidance of doubt, Section 2(a)(1) grants You the right + to extract, reuse, reproduce, and Share all or a substantial + portion of the contents of the database; + + b. if You include all or a substantial portion of the database + contents in a database in which You have Sui Generis Database + Rights, then the database in which You have Sui Generis Database + Rights (but not its individual contents) is Adapted Material; and + + c. You must comply with the conditions in Section 3(a) if You Share + all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not +replace Your obligations under this Public License where the Licensed +Rights include other Copyright and Similar Rights. + + +Section 5 -- Disclaimer of Warranties and Limitation of Liability. + + a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE + EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS + AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF + ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, + IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, + WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, + ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT + KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT + ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. + + b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE + TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, + NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, + INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, + COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR + USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR + DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR + IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. + + c. The disclaimer of warranties and limitation of liability provided + above shall be interpreted in a manner that, to the extent + possible, most closely approximates an absolute disclaimer and + waiver of all liability. + + +Section 6 -- Term and Termination. + + a. This Public License applies for the term of the Copyright and + Similar Rights licensed here. However, if You fail to comply with + this Public License, then Your rights under this Public License + terminate automatically. + + b. Where Your right to use the Licensed Material has terminated under + Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided + it is cured within 30 days of Your discovery of the + violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any + right the Licensor may have to seek remedies for Your violations + of this Public License. + + c. For the avoidance of doubt, the Licensor may also offer the + Licensed Material under separate terms or conditions or stop + distributing the Licensed Material at any time; however, doing so + will not terminate this Public License. + + d. Sections 1, 5, 6, 7, and 8 survive termination of this Public + License. + + +Section 7 -- Other Terms and Conditions. + + a. The Licensor shall not be bound by any additional or different + terms or conditions communicated by You unless expressly agreed. + + b. Any arrangements, understandings, or agreements regarding the + Licensed Material not stated herein are separate from and + independent of the terms and conditions of this Public License. + + +Section 8 -- Interpretation. + + a. For the avoidance of doubt, this Public License does not, and + shall not be interpreted to, reduce, limit, restrict, or impose + conditions on any use of the Licensed Material that could lawfully + be made without permission under this Public License. + + b. To the extent possible, if any provision of this Public License is + deemed unenforceable, it shall be automatically reformed to the + minimum extent necessary to make it enforceable. If the provision + cannot be reformed, it shall be severed from this Public License + without affecting the enforceability of the remaining terms and + conditions. + + c. No term or condition of this Public License will be waived and no + failure to comply consented to unless expressly agreed to by the + Licensor. + + d. Nothing in this Public License constitutes or may be interpreted + as a limitation upon, or waiver of, any privileges and immunities + that apply to the Licensor or You, including from the legal + processes of any jurisdiction or authority. + + +======================================================================= + +Creative Commons is not a party to its public +licenses. Notwithstanding, Creative Commons may elect to apply one of +its public licenses to material it publishes and in those instances +will be considered the “Licensor.” The text of the Creative Commons +public licenses is dedicated to the public domain under the CC0 Public +Domain Dedication. Except for the limited purpose of indicating that +material is shared under a Creative Commons public license or as +otherwise permitted by the Creative Commons policies published at +creativecommons.org/policies, Creative Commons does not authorize the +use of the trademark "Creative Commons" or any other trademark or logo +of Creative Commons without its prior written consent including, +without limitation, in connection with any unauthorized modifications +to any of its public licenses or any other arrangements, +understandings, or agreements concerning use of licensed material. For +the avoidance of doubt, this paragraph does not form part of the +public licenses. + +Creative Commons may be contacted at creativecommons.org. + diff --git a/README.md b/README.md new file mode 100644 index 0000000..4c0c007 --- /dev/null +++ b/README.md @@ -0,0 +1,97 @@ +# Waypoints + +A simple, but customizable waypoints system for your Roblox Game! + +# Installation + +You can download the latest version from the [Releases](https://github.com/catteched/waypoints/releases) page which you can just easily drag and drop into your game under `StarterPlayer > StarterPlayerScripts`. + +# Configuration + +Theres already a few defaults in the config file for you, however you can change them to your liking. +You can then find the configuration module under the `waypoints` localscript named `config`. + +## Options + +| Option | Type | Description | +| ------------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `system` | `table` | The system(s) that will handle the waypoints. Currently uses the chat system thats included with the system.If you would like to write your own, you can read [this documentation (not available)](#) for the waypoints api. | +| `middlewareSystems` | `table` | The system(s) mainly used for authenticating. Currently it uses the provided permissions system, however you are free to write your own. You can find the documentation for it [here (not available)](#). | +| `permissions` | `table` | Specify permissions on who can or cannot use the waypoints, [look here](#permissions) for permission options. | +| `distancePrefix` | `string` | Prefix to add after the distance number. | +| `highlightFade` | `boolean` | If the highlight should also fade based on the distance from it. (maxFadeDistance also affects this) | +| `fadeDistace` | `number` | How far until the text should start fading. | +| `maxFadeDistance` | `number` | How far until the waypoint condenses its information viewing | + +## Permissions + +Helps specify who can or cannot use the waypoints based on userids and group ranks. They are specified in the `permissions` table in the config module. + +There are two types of permission tables you can use: + +- `players`: Specify specific players (via userids) that can use the waypoints. +- `groups`: Specify groups and what rank(s) can use each waypoint. + +### Players + +To specify a player, you can use their `userId` as the key, and set the value to true. For example: + +```lua +{ + ... + players = { + [123456789] = true, + [987654321] = false, -- This player wouldnt be able to use the waypoints + } +} +``` + +### Groups + +To specify a group (and the ranks) which can use the waypoints, you would use the `groupId` as the key, and set the value to a table of ranks with different modes stating how it should check the ranks. + +```lua +{ + groups = { + [123456789] = { + { + mode = "equals", -- available modes: "equals", "above", "under" + rank = 255 + }, + { + mode = "above", + rank = 100 -- any rank above 100 (non-inclusive). So 101, 102, 103, etc. + -- however, if you would like to include 100, you'd have to set the value to 99 + }, + { + mode = "under", + rank = 100 -- any rank under 100 (non-inclusive). So 99, 98, 97, etc. + } + } + } +} +``` + +# Usage + +Using the built-in chat system provided with the waypoints system, you can use `/waypoints` command to open all waypoints that are available to you. If you would like to show a group of waypoints, you can use `/waypoints ` to show only the waypoints in that group. And if you would like to hide the waypoints, you can use `/waypoints hide`. + +# Terms of Use + +## Guidelines + +- You are allowed to **modify** and **use** the work in either a commercial or non-commercial contexts[^1] +- However, you're **not allowed to sell** either the **original** or **modified** versions of our products as a standalone works or have them repackaged as your own[^2] +- You **may redistribute** the **modified version** (not original) for free to others as long it includes the proper attribution. +- You **must** give proper attribution to **catteched** in accordance to the **CC BY 4.0** License. A minimal attribution must include the original author/creator's name (in which this case is catteched), a link to the original work, a link to the discord server (`https://discord.gg/yATrVSnGSK`), and the **CC BY 4.0** License. + +Upon downloading/using our tech, you agree to the following: + +- **Providing** the **proper attribution** as outlined in the **CC BY 4.0 License** +- **Not** claim the original or modified versions of our works as your own, and to **not resell** them.[^3] + +These terms are **subject to change over time**, but you will be **notified immediately** if that ever so happens. You are also **automatically agreeing** to the new terms **if they do change** as long as you are **currently using our products in your games**. If you wish to **not comply with the new terms**, then you are **prohibited to use our products in your game** and must remove them immediately. + +[^1]: Its fine if you use it to make profit in your own works. +[^2]: Don't resell our products. +[^3]: Basically don't credit them as something that you made without adding any attribution. diff --git a/default.project.json b/default.project.json new file mode 100644 index 0000000..12cb0ff --- /dev/null +++ b/default.project.json @@ -0,0 +1,17 @@ +{ + "name": "waypoints", + "tree": { + "$className": "DataModel", + + "StarterPlayer": { + "StarterPlayerScripts": { + "waypoints": { + "$path": "src", + "packages": { + "$path": "roblox_packages" + } + } + } + } + } +} diff --git a/pesde.toml b/pesde.toml new file mode 100644 index 0000000..68c7053 --- /dev/null +++ b/pesde.toml @@ -0,0 +1,23 @@ +name = "catteched/waypoints" +version = "1.0.0" +description = "A simple waypoints viewer" +authors = ["metamethods"] +repository = "https://github.com/catteched/waypoints" +license = "CC BY" +wally_allowed = true + +[target] +environment = "roblox" + +[scripts] +roblox_sync_config_generator = ".pesde/roblox_sync_config_generator.luau" +sourcemap_generator = ".pesde/sourcemap_generator.luau" + +[indices] +default = "https://github.com/daimond113/pesde-index" + +[wally_indices] +default = "https://github.com/UpliftGames/wally-index" + +[dependencies] +vide = { wally = "centau/vide", version = "^0.3.1" } diff --git a/release.project.json b/release.project.json new file mode 100644 index 0000000..d950602 --- /dev/null +++ b/release.project.json @@ -0,0 +1,9 @@ +{ + "name": "waypoints", + "tree": { + "$path": "src", + "packages": { + "$path": "roblox_packages" + } + } +} diff --git a/rokit.toml b/rokit.toml new file mode 100644 index 0000000..e4c74d0 --- /dev/null +++ b/rokit.toml @@ -0,0 +1,11 @@ +# This file lists tools managed by Rokit, a toolchain manager for Roblox projects. +# For more information, see https://github.com/rojo-rbx/rokit + +# New tools can be added by running `rokit add ` in a terminal. + +[tools] +rojo = "rojo-rbx/rojo@7.4.4" +stylua = "JohnnyMorganz/stylua@2.0.1" +selene = "Kampfkarren/selene@0.27.1" +pesde = "pesde-pkg/pesde@0.5.0-rc.12" +lune = "lune-org/lune@0.8.9" diff --git a/selene.toml b/selene.toml new file mode 100644 index 0000000..cad49a9 --- /dev/null +++ b/selene.toml @@ -0,0 +1,5 @@ +std = "roblox+luau" + +[lints] +shadowing = "allow" +mixed_table = "allow" diff --git a/src/config.luau b/src/config.luau new file mode 100644 index 0000000..4a5da9b --- /dev/null +++ b/src/config.luau @@ -0,0 +1,26 @@ +local chat = require(script.Parent.systems.chat) +local permissions = require(script.Parent.systems.permissions) +local types = require(script.Parent.types) + +return { + -- who should handle our showing/hiding waypoints + -- you can also use a table to allow for multiple systems + -- or you can just use the default chat system provided + system = { chat }, + + -- for systems to do like permission checking or whatever + middlewareSystems = { permissions }, + + -- the prefix for the distance shown for each waypoint + -- e.g. if its "m", it'll show as 123m + distancePrefix = " studs", + + -- if you want to make the highlights fade when you get closer/farther to the waypoint + highlightFade = false, + + -- how far until the waypoint text fades + fadeDistance = 25, + + -- how far until the waypoint condenses its information + maxFadeDistance = 500, +} :: types.ConfigDefinition diff --git a/src/init.client.luau b/src/init.client.luau new file mode 100644 index 0000000..5be3a4b --- /dev/null +++ b/src/init.client.luau @@ -0,0 +1,122 @@ +local Players = game:GetService("Players") + +local config = require(script.config) +local mount = require(script.utils.mount) +local types = require(script.types) +local ui = require(script.ui) +local vide = require(script.packages.vide) +local waypoints = require(script.waypoints) + +local waypointsFolder = Instance.new("Folder") +waypointsFolder.Name = "waypoints" +waypointsFolder.Parent = workspace.Terrain + +local enabledWaypoints: { [string]: vide.Source } = {} + +local function getWaypoint(id: string): types.Waypoint? + return waypoints[id] +end + +local function getWaypoints(group: string): { [string]: types.Waypoint } + local filteredWaypoints = {} + + for id, waypoint in waypoints do + if waypoint.group ~= group then + continue + end + filteredWaypoints[id] = waypoint + end + + return filteredWaypoints +end + +local function setEnabled(id: string, enabled: boolean) + assert(enabledWaypoints[id], `Unknown waypoint id {id}`) + enabledWaypoints[id](enabled) +end + +local function setAllEnabled(enabled: boolean) + for _, enabledSource in enabledWaypoints do + enabledSource(enabled) + end +end + +local function setWaypointGroupEnabled(group, enabled: boolean) + for id, _ in getWaypoints(group) do + setEnabled(id, enabled) + end +end + +local function hideAllWaypoints() + setAllEnabled(false) +end + +local function hideWaypoints(ids: { string }) + for _, id in ids do + setEnabled(id, false) + end +end + +local function hideWaypointGroup(group: string) + setWaypointGroupEnabled(group, false) +end + +local function showAllWaypoints() + setAllEnabled(true) +end + +local function showWaypoints(ids: { string }) + for _, id in ids do + setEnabled(id, true) + end +end + +local function showWaypointGroup(group: string) + setWaypointGroupEnabled(group, true) +end + +local function middleware(): boolean + for _, middleware in config.middlewareSystems do + if not middleware(Players.LocalPlayer, config) then + return false + end + end + + return true +end + +local apiFunctions = { + getWaypoint = getWaypoint, + getWaypoints = getWaypoints, + hideAllWaypoints = hideAllWaypoints, + hideWaypoints = hideWaypoints, + hideWaypointGroup = hideWaypointGroup, + showAllWaypoints = showAllWaypoints, + showWaypoints = showWaypoints, + showWaypointGroup = showWaypointGroup, + setAllEnabled = setAllEnabled, + setEnabled = setEnabled, + setWaypointGroupEnabled = setWaypointGroupEnabled, + middleware = middleware, +} + +for _, system: types.SystemFn in config.system do + system(Players.LocalPlayer, apiFunctions) +end + +local function loadWaypoint(id: string, waypoint: types.Waypoint) + local enabled = vide.source(false) + mount(ui, waypointsFolder, waypoint, enabled) + enabledWaypoints[id] = enabled +end + +for id, waypoint in waypoints do + loadWaypoint(id, waypoint) +end + +setmetatable(waypoints, { + __newindex = function(self, id, waypoint) + loadWaypoint(id, waypoint) + rawset(self, id, waypoint) + end, +}) diff --git a/src/systems/chat.luau b/src/systems/chat.luau new file mode 100644 index 0000000..21a5b62 --- /dev/null +++ b/src/systems/chat.luau @@ -0,0 +1,31 @@ +local TextChatService = game:GetService("TextChatService") + +local types = require(script.Parent.Parent.types) + +local chatSystem: types.SystemFn = function(_, api) + TextChatService.OnIncomingMessage = function(message) + if + not api.middleware() + or not message.Text:find("^/waypoints") + or message.Status == Enum.TextChatMessageStatus.Sending + then + return + end + + local parameter = message.Text:split(" ")[2] + + if parameter == "hide" then + api.hideAllWaypoints() + return + end + + if parameter then + api.hideAllWaypoints() + api.showWaypointGroup(parameter) + else + api.showAllWaypoints() + end + end +end + +return chatSystem diff --git a/src/systems/permissions.luau b/src/systems/permissions.luau new file mode 100644 index 0000000..51fd59e --- /dev/null +++ b/src/systems/permissions.luau @@ -0,0 +1,41 @@ +local types = require(script.Parent.Parent.types) + +local permissionSystem: types.MiddlewareSystemFn = function(localPlayer, config) + local permissions = config.permissions + + if not permissions then + return true + end + + if permissions.players then + if permissions.players[localPlayer.UserId] then + return true + end + end + + if permissions.groups then + for groupId, groupPermissions in permissions.groups do + local rank = localPlayer:GetRankInGroup(groupId) + + for _, groupPermission in groupPermissions do + if + ( + groupPermission.mode == "equals" + and rank == groupPermission.rank + ) + or (groupPermission.mode == "above" and rank > groupPermission.rank) + or ( + groupPermission.mode == "under" + and rank < groupPermission.rank + ) + then + return true + end + end + end + end + + return false +end + +return permissionSystem diff --git a/src/types.luau b/src/types.luau new file mode 100644 index 0000000..86d6562 --- /dev/null +++ b/src/types.luau @@ -0,0 +1,55 @@ +export type ConfigDefinition = { + system: { SystemFn }, + middlewareSystems: { MiddlewareSystemFn }, + distancePrefix: string, + highlightFade: boolean, + fadeDistance: number, + maxFadeDistance: number, + permissions: { + groups: { + [number]: { + { + mode: "above" | "under" | "equals", + rank: number, + } + }, + }?, + players: { + [number]: boolean, + }?, + }?, +} + +export type WaypointMetadata = { + color: Color3, +} + +export type Waypoint = { + name: string, + group: string?, + position: Vector3, + highlights: { BasePart }?, +} & WaypointMetadata + +export type APIFunctions = { + getWaypoint: (id: string) -> Waypoint?, + getWaypoints: (group: string) -> { [string]: Waypoint }?, + hideAllWaypoints: () -> (), + hideWaypoints: (ids: { string }) -> (), + hideWaypointGroup: (group: string) -> (), + showAllWaypoints: () -> (), + showWaypoints: (ids: { string }) -> (), + showWaypointGroup: (group: string) -> (), + setAllEnabled: (enabled: boolean) -> (), + setEnabled: (id: string, boolean: boolean) -> (), + setWaypointGroupEnabled: (group: string, enabled: boolean) -> (), + middleware: () -> boolean, +} + +export type SystemFn = (localPlayer: Player, api: APIFunctions) -> () +export type MiddlewareSystemFn = ( + localPlayer: Player, + config: ConfigDefinition +) -> boolean + +return nil diff --git a/src/ui/init.luau b/src/ui/init.luau new file mode 100644 index 0000000..9e0c6e6 --- /dev/null +++ b/src/ui/init.luau @@ -0,0 +1,126 @@ +local Players = game:GetService("Players") +local RunService = game:GetService("RunService") + +local config = require(script.Parent.config) +local types = require(script.Parent.types) +local vide = require(script.Parent.packages.vide) + +local localPlayer = Players.LocalPlayer + +local function ui( + waypoint: types.Waypoint, + enabled: vide.Source +): BillboardGui + local distance = vide.source(0) + + local transparency = function() + return if enabled() then 0.25 else 1 + end + + local labelTransparency = function() + if not enabled() then + return 1 + end + + if distance() >= config.maxFadeDistance then + return 1 + end + + return if distance() >= config.fadeDistance + then 0 + else 5 * math.log10( + 1 + ((config.fadeDistance - distance()) / config.fadeDistance) + ) + end + + local circleTransparency = function() + return if distance() >= config.maxFadeDistance then 0 else 1 + end + + local renderSteppedConnection = RunService.RenderStepped:Connect(function() + distance(localPlayer:DistanceFromCharacter(waypoint.position)) + end) + + if waypoint.highlights then + for _, highlightPart in waypoint.highlights do + vide.create "BoxHandleAdornment" { + Name = "Highlight", + Parent = highlightPart, + Adornee = highlightPart, + Size = highlightPart.Size, + Transparency = vide.spring( + config.highlightFade and labelTransparency or transparency, + 0.5 + ), + Color3 = waypoint.color, + } + end + end + + vide.cleanup(renderSteppedConnection) + + return vide.create "BillboardGui" { + Name = waypoint.name, + Size = UDim2.new(0, 500, 0, 50), + AlwaysOnTop = true, + ClipsDescendants = false, + + StudsOffsetWorldSpace = waypoint.position, + + vide.create "Frame" { + Name = "Circle", + Size = UDim2.fromScale(0.5, 0.5), + Position = UDim2.fromScale(0.5, 0.5), + AnchorPoint = Vector2.new(0.5, 0.5), + BackgroundColor3 = waypoint.color, + BackgroundTransparency = vide.spring(circleTransparency, 0.5), + + vide.create "UICorner" { + CornerRadius = UDim.new(1, 0), + }, + + vide.create "UIAspectRatioConstraint" { + AspectRatio = 1, + }, + }, + + vide.create "CanvasGroup" { + Name = "Body", + Size = UDim2.fromScale(1, 1), + BackgroundTransparency = 1, + GroupTransparency = vide.spring(labelTransparency, 0.5), + + vide.create "TextLabel" { + Name = "Name", + Size = UDim2.fromScale(1, 0.7), + BackgroundTransparency = 1, + + Text = waypoint.name, + TextScaled = true, + TextColor3 = waypoint.color, + TextStrokeTransparency = 0.8, + + FontFace = Font.fromName("Montserrat", Enum.FontWeight.Bold), + }, + + vide.create "TextLabel" { + Name = "Distance", + Size = UDim2.fromScale(1, 0.3), + Position = UDim2.fromScale(0, 1), + AnchorPoint = Vector2.new(0, 1), + BackgroundTransparency = 1, + + Text = function() + return `{math.floor(distance())}{config.distancePrefix}` + end, + TextScaled = true, + TextColor3 = waypoint.color, + TextStrokeTransparency = 0.8, + + FontFace = Font.fromName("Montserrat"), + }, + }, + } +end + +return ui diff --git a/src/utils/mount.luau b/src/utils/mount.luau new file mode 100644 index 0000000..d35758a --- /dev/null +++ b/src/utils/mount.luau @@ -0,0 +1,10 @@ +local vide = require(script.Parent.Parent.packages.vide) + +local function mount(component: (T...) -> Instance, target: Instance, ...: T...) + local args = table.pack(...) + return vide.mount(function() + return component(table.unpack(args :: any)) + end, target) +end + +return mount diff --git a/src/utils/waypoint.luau b/src/utils/waypoint.luau new file mode 100644 index 0000000..1cc91e4 --- /dev/null +++ b/src/utils/waypoint.luau @@ -0,0 +1,87 @@ +local types = require(script.Parent.Parent.types) + +local function Waypoint( + name: string, + group: string?, + positionOrPart: Vector3 | BasePart, + highlights: { BasePart }?, + metadata: types.WaypointMetadata +): types.Waypoint + return { + name = name, + group = group, + position = if typeof(positionOrPart) == "Instance" + then positionOrPart.Position + else positionOrPart, + highlights = highlights, + color = metadata.color, + } +end + +local function BasicWaypoint( + name: string, + color: Color3, + positionOrPart: Vector3 | BasePart, + highlights: { BasePart }? +): types.Waypoint + return Waypoint(name, nil, positionOrPart, highlights, { + color = color, + }) +end + +local function GroupWaypoint( + name: string, + group: string, + color: Color3, + positionOrPart: Vector3 | BasePart, + highlights: { BasePart }? +) + return Waypoint(name, group, positionOrPart, highlights, { + color = color, + }) +end + +local function FolderWaypoint( + waypoints: { [string]: types.Waypoint }, + folder: Folder +) + local function loadPart(part: BasePart) + local id = part:GetAttribute("Id") :: string? + local group = part:GetAttribute("Group") :: string? + local color = part.Color + + assert(id, `Missing id from {part:GetFullName()}`) + + local highlights = {} + + for _, instance in part:GetChildren() do + if not instance:IsA("BasePart") then + continue + end + table.insert(highlights, instance) + end + + waypoints[id] = Waypoint(part.Name, group, part, highlights, { + color = color, + }) + end + + for _, instance in folder:GetChildren() do + if instance:IsA("BasePart") then + loadPart(instance) + end + end + + folder.ChildAdded:Connect(function(instance) + if instance:IsA("BasePart") then + loadPart(instance) + end + end) +end + +return { + BasicWaypoint = BasicWaypoint, + GroupWaypoint = GroupWaypoint, + FolderWaypoint = FolderWaypoint, + Waypoint = Waypoint, +} diff --git a/src/waypoints.luau b/src/waypoints.luau new file mode 100644 index 0000000..97cc3aa --- /dev/null +++ b/src/waypoints.luau @@ -0,0 +1,8 @@ +local types = require(script.Parent.types) +local waypoint = require(script.Parent.utils.waypoint) + +local waypoints = {} :: { [string]: types.Waypoint } + +waypoint.FolderWaypoint(waypoints, workspace:WaitForChild("Waypoints")) + +return waypoints diff --git a/stylua.toml b/stylua.toml new file mode 100644 index 0000000..8ea93d1 --- /dev/null +++ b/stylua.toml @@ -0,0 +1,5 @@ +call_parentheses = "Input" +column_width = 80 + +[sort_requires] +enabled = true diff --git a/test.luau b/test.luau new file mode 100644 index 0000000..e69de29