diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..e3389d2 --- /dev/null +++ b/.env.example @@ -0,0 +1 @@ +ROBLOXSECURITY="_|WARNING:-DO-NOT-SHARE-THIS.--Sharing-this-will-allow-someone-to-log-in-as-you-and-to-steal-your-ROBUX-and-items.|youReallyThoughtBuddy" \ No newline at end of file diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..94154ee --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: "npm" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "daily" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..636edaa --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,36 @@ +name: Build +on: + pull_request: + push: + +jobs: + build: + name: Build + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v3 + + - name: Set Node.js 16.x + uses: actions/setup-node@v3 + with: + node-version: 16.x + + - name: Run install + uses: borales/actions-yarn@v4 + with: + cmd: install # will run `yarn install` command + + - name: Install aftman + uses: ok-nick/setup-aftman@v0.3.0 + + - name: Build + uses: borales/actions-yarn@v4 + with: + cmd: build # will run `yarn build` command + + - name: Upload Artifact + uses: actions/upload-artifact@v3 + with: + name: goopler + path: build.rbxl \ No newline at end of file diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..4215f99 --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,37 @@ +name: Deploy +on: + pull_request: + push: + +jobs: + build: + name: Build + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v3 + + - name: Set Node.js 16.x + uses: actions/setup-node@v3 + with: + node-version: 16.x + + - name: Run install + uses: borales/actions-yarn@v4 + with: + cmd: install # will run `yarn install` command + + - name: Install aftman + uses: ok-nick/setup-aftman@v0.3.0 + + - name: Build + uses: borales/actions-yarn@v4 + with: + cmd: build # will run `yarn build` command + + - name: Deploy project + run: mantle deploy -e default + env: + ROBLOSECURITY: ${{ secrets.ROBLOSECURITY }} + MANTLE_AWS_ACCESS_KEY_ID: ${{ secrets.MANTLE_AWS_ACCESS_KEY_ID }} + MANTLE_AWS_SECRET_ACCESS_KEY: ${{ secrets.MANTLE_AWS_SECRET_ACCESS_KEY }} \ No newline at end of file diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..000284a --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,27 @@ +name: Lint +on: + pull_request: + push: + +jobs: + build: + name: ESLint + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v3 + + - name: Set Node.js 16.x + uses: actions/setup-node@v3 + with: + node-version: 16.x + + - name: Run install + uses: borales/actions-yarn@v4 + with: + cmd: install # will run `yarn install` command + + - name: Lint + uses: borales/actions-yarn@v4 + with: + cmd: lint # will run `yarn lint` command diff --git a/.gitignore b/.gitignore index 08f78e7..f7722cf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,15 +1,21 @@ -# Builds +# builds /out build.rbxl *.tsbuildinfo -# Deps +# deps /node_modules /include -# Mac junk +# mac users.. stop making these files or im gonna get mad 😡😡😡 .DS_Store /__MACOSX -# Logs -*.log \ No newline at end of file +# logs +*.log + +# my secrets 😍😎 +.env + +# we use remote stuff now +.mantle-state.yml \ No newline at end of file diff --git a/aftman.toml b/aftman.toml index bf4433e..4446b13 100644 --- a/aftman.toml +++ b/aftman.toml @@ -4,4 +4,5 @@ # To add a new tool, add an entry to this table. [tools] rojo = "rojo-rbx/rojo@7.3.0" -run-in-roblox = "rojo-rbx/run-in-roblox@0.3.0" \ No newline at end of file +run-in-roblox = "rojo-rbx/run-in-roblox@0.3.0" +mantle = "blake-mealey/mantle@0.11.9" \ No newline at end of file diff --git a/mantle.yml b/mantle.yml new file mode 100644 index 0000000..ead3b5c --- /dev/null +++ b/mantle.yml @@ -0,0 +1,29 @@ +environments: + - label: default + +target: + experience: + icon: marketing/gameIcon.jpg + thumbnails: + - marketing/gameThumbnailDefault.jpg + configuration: + genre: fps + playableDevices: [computer] + privateServers: + price: 50 + enableStudioAccessToApis: true + avatarType: r6 + places: + start: + file: build.rbxl + configuration: + name: Goopler + description: |- + Read my github repo reidlabwastaken/goopler if u can hahaha + maxPlayerCount: 100 + +state: + remote: + region: us-west-2 + bucket: goopler-mantle-states + key: goopler \ No newline at end of file diff --git a/marketing/gameIcon.jpg b/marketing/gameIcon.jpg new file mode 100644 index 0000000..421e826 Binary files /dev/null and b/marketing/gameIcon.jpg differ diff --git a/marketing/gameThumbnailDefault.jpg b/marketing/gameThumbnailDefault.jpg new file mode 100644 index 0000000..df0d667 Binary files /dev/null and b/marketing/gameThumbnailDefault.jpg differ diff --git a/package.json b/package.json index 34f11bf..c0b5efd 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,8 @@ "watch": "rbxtsc -w --rojo default.project.json --verbose", "lint": "eslint src tests --max-warnings 0", "serve": "rojo serve default.project.json", - "test": "yarn run build && run-in-roblox --place build.rbxl --script out/tests/runners/run.server.lua" + "test": "yarn run build && run-in-roblox --place build.rbxl --script out/tests/runners/run.server.lua", + "deploy": "yarn run build && mantle deploy -e default" }, "devDependencies": { "@rbxts/compiler-types": "^2.1.1-types.0", @@ -33,7 +34,6 @@ }, "dependencies": { "@rbxts/character-promise": "^1.0.2", - "@rbxts/log": "^0.6.3", "@rbxts/matter": "^0.6.2-ts.6", "@rbxts/plasma": "^0.4.1-ts.1", "@rbxts/rewire": "^0.3.0", diff --git a/readme.md b/readme.md index 7907ef1..9122218 100644 --- a/readme.md +++ b/readme.md @@ -7,25 +7,32 @@ An in-dev game that I plan to make a shooter game out of. — reidlab +# Setup +When you first setup this repository, you probably want to add your `.ROBLOSECURITY` cookie into the `.env` file for automatic deployment with [Mantle](https://mantledeploy.vercel.app/). You also should change the ID of the game. + # Hacks * I get a strange error about private identifiers in [`./src/ReplicatedStorage/ecs/state.ts`](./src/ReplicatedStorage/ecs/state.ts) * I decided to omit the "TS" folder from [`./default.project.json:40`](./default.project.json) due to the script override not working in Health.server.ts in StarterCharacterScripts. # Todo ### High priority +* Fix automatic deployment. Its fixed itself, but its broken again. By the time this commit goes through I bet it will work again. Honestly super weird. Just make it consistant * Add tests -* Add guns. Try it in default roblox-ts and slowly reimplement it into our component system. +* Add guns. Try it in default roblox-ts and slowly reimplement it into our component system #### Medium priority * Crouching * Animations +* Change remote state to a provider where I dont have to worry about money +* Seperate dev&prod environments (maybe later??? the game is very early stage so idk) +* Migrate todo to somewhere else like the issues tab ##### Low priority * Camera bobble * Add the bound tags in [`./src/ReplicatedStorage/ecs/boundTags.ts`](./src/ReplicatedStorage/ecs/boundTags.ts) -* Cooler sprinting! (Tween fov and speed) +* Cooler sprinting!! (Tween fov and speed) * Crouching? # Fixes ### High Priority -* Currently, when resetting, sometimes your health goes back up. This is due to the reconciliation of health. Simply put, your health is not being set to zero inside of our entity component system, due to us not having the reset event currently like that. See it here: [StarterGui.SetCore](https://create.roblox.com/docs/reference/engine/classes/StarterGui#SetCore) It uses BindableEvents. +* Currently, when resetting, sometimes your health goes back up. This is due to the reconciliation of health. Simply put, your health is not being set to zero inside of our entity component system, due to us not having the reset event currently like that. See it here: [StarterGui.SetCore](https://create.roblox.com/docs/reference/engine/classes/StarterGui#SetCore) It uses BindableEvents and stuff idk #### Medium priority ##### Low priority \ No newline at end of file diff --git a/src/ReplicatedStorage/ecs/index.ts b/src/ReplicatedStorage/ecs/index.ts index 6c51ee9..1854ea9 100644 --- a/src/ReplicatedStorage/ecs/index.ts +++ b/src/ReplicatedStorage/ecs/index.ts @@ -45,9 +45,9 @@ export function start(host: Host, state: S): [World, S] { }) if (host === Host.All || host === Host.Server) { - const ServerState = state as serverState + const _ServerState = state as serverState - startTags(world, tags, ServerState) + startTags(world, tags) } if (host === Host.All || host === Host.Client) { diff --git a/src/ReplicatedStorage/ecs/replication.ts b/src/ReplicatedStorage/ecs/replication.ts index 6b2184b..e299a8d 100644 --- a/src/ReplicatedStorage/ecs/replication.ts +++ b/src/ReplicatedStorage/ecs/replication.ts @@ -6,17 +6,27 @@ import { clientState } from "./state" type ComponentNames = keyof typeof Components type ComponentConstructors = (typeof Components)[ComponentNames] +const DEBUG_SPAWN = "Spawn %ds%d with %s" +const DEBUG_DESPAWN = "Despawn %ds%d" +const DEBUG_MODIFY = "Modify %ds%d adding %s, removing %s" + let connection: RBXScriptConnection | undefined /** * Starts the replication receiver. * * @param world - The world to replicate components in - * @param client - The client state for the ECS + * @param ClientState - The client state for the ECS */ -export function start(world: World, client: clientState): void { +export function start(world: World, ClientState: clientState): void { if (connection) return + function debugPrint(message: string, args: () => (string | number)[]): void { + if (ClientState.debugEnabled) { + print("ECS Replication>", string.format(message, ...args())) + } + } + const replicationEvent = waitForEvent("EcsReplication") const serverToClientEntity = new Map() @@ -28,11 +38,7 @@ export function start(world: World, client: clientState): void { if (clientId !== undefined && next(componentMap)[0] === undefined) { world.despawn(clientId) serverToClientEntity.delete(serverId) - client.logger.Debug( - "ECS Replication> Despawn {@clientId}s{@serverId}", - clientId, - serverId - ) + debugPrint(DEBUG_DESPAWN, () => [clientId, serverId]) continue } @@ -66,12 +72,7 @@ export function start(world: World, client: clientState): void { if (clientId === undefined) { const clientId = world.spawn(...componentsToInsert) serverToClientEntity.set(serverId, clientId) - client.logger.Debug( - "ECS Replication> Spawn {@clientId}s{@serverId} with {@insertNames}", - clientId, - serverId, - insertNames.join(",") - ) + debugPrint(DEBUG_SPAWN, () => [clientId, serverId, insertNames.join(",")]) } else { if (componentsToInsert.size() > 0) { world.insert(clientId, ...componentsToInsert) @@ -81,13 +82,12 @@ export function start(world: World, client: clientState): void { world.remove(clientId, ...componentsToRemove) } - client.logger.Debug( - "ECS Replication> Modify {@clientId}s{serverId} adding {@insertNames}, removing {@removeNames}", + debugPrint(DEBUG_MODIFY, () => [ clientId, serverId, insertNames.size() > 0 ? insertNames.join(", ") : "nothing", removeNames.size() > 0 ? removeNames.join(", ") : "nothing" - ) + ]) } } } diff --git a/src/ReplicatedStorage/ecs/state.ts b/src/ReplicatedStorage/ecs/state.ts index 7bc0c5f..625362e 100644 --- a/src/ReplicatedStorage/ecs/state.ts +++ b/src/ReplicatedStorage/ecs/state.ts @@ -1,54 +1,23 @@ /* eslint-disable roblox-ts/no-private-identifier */ import { CharacterRigR6 } from "@rbxts/character-promise" -import { Logger } from "@rbxts/log" import { InputKind } from "ReplicatedStorage/inputKind" /** * The client ECS state. */ export class clientState { - constructor( - player: Player, - character: CharacterRigR6, - debugEnabled: boolean, - isRunning: boolean, - // lastProcessedCommand: Inputkind, - - logger: Logger - ) { - this.character = character - this.player = player - this.debugEnabled = debugEnabled - this.isRunning = isRunning - // this.lastProcessedCommand = lastProcessedCommand - - this.logger = logger - } - - player: Player - character: CharacterRigR6 - debugEnabled: boolean - isRunning: boolean + [index: string]: unknown + character?: CharacterRigR6 + player?: Player + debugEnabled = false + isRunning = false lastProcessedCommand?: InputKind - - logger: Logger } /** * The server ECS state. */ export class serverState { - constructor( - logger: Logger - ) { - this.logger = logger - } - - logger: Logger -} - -/** - * The shared ECS state. - */ -export type sharedState = serverState & clientState \ No newline at end of file + [index: string]: unknown +} \ No newline at end of file diff --git a/src/ReplicatedStorage/ecs/tags.ts b/src/ReplicatedStorage/ecs/tags.ts index c71047c..291b540 100644 --- a/src/ReplicatedStorage/ecs/tags.ts +++ b/src/ReplicatedStorage/ecs/tags.ts @@ -2,7 +2,6 @@ import { AnyEntity, Component, World } from "@rbxts/matter" import { CollectionService } from "@rbxts/services" import { getIdAttribute } from "ReplicatedStorage/idAttribute" import { Model, Transform } from "./components" -import { serverState } from "./state" export type ComponentConstructor = () => Component @@ -16,8 +15,7 @@ const connections: RBXScriptConnection[] = [] */ export function start( world: World, - bound: ReadonlyMap>, - server: serverState + bound: ReadonlyMap> ): void { function spawnBound( instance: Instance, @@ -28,13 +26,13 @@ export function start( if (instance.PrimaryPart) { primaryPart = instance.PrimaryPart } else { - server.logger.Warn("Attempted to tag a model that has no primary part: {@instance}", instance) + warn("Attempted to tag a model that has no primary part:", instance) return } } else if (instance.IsA("BasePart")) { primaryPart = instance } else { - server.logger.Warn("Attempted to tag an instance that is not a Model or BasePart: {@instance}", instance) + warn("Attempted to tag an instance that is not a Model or BasePart:", instance) return } diff --git a/src/ServerScriptService/ecs/systems/server/replication.ts b/src/ServerScriptService/ecs/systems/server/replication.ts index aaba13e..23db406 100644 --- a/src/ServerScriptService/ecs/systems/server/replication.ts +++ b/src/ServerScriptService/ecs/systems/server/replication.ts @@ -1,7 +1,6 @@ import { useEvent, World } from "@rbxts/matter" import { Players } from "@rbxts/services" import * as Components from "ReplicatedStorage/ecs/components" -import { serverState } from "ReplicatedStorage/ecs/state" import { getEvent } from "ReplicatedStorage/remotes" type ComponentName = keyof typeof Components @@ -21,7 +20,7 @@ const replicatedComponents: ReadonlySet = REPLICATED_COMPO getEvent("EcsReplication") -function replication(world: World, server: serverState): void { +function replication(world: World): void { const replicationEvent = getEvent("EcsReplication") let payload: Map> | undefined @@ -44,7 +43,7 @@ function replication(world: World, server: serverState): void { } } - server.logger.Debug("Sending initial payload to {@player}", player) + print("Sending initial payload to", player) replicationEvent.FireClient(player, payload) } diff --git a/src/ServerScriptService/main.server.ts b/src/ServerScriptService/main.server.ts index bd6fcdb..e1e4051 100644 --- a/src/ServerScriptService/main.server.ts +++ b/src/ServerScriptService/main.server.ts @@ -1,4 +1,3 @@ -import Log, { Logger } from "@rbxts/log" import { start } from "ReplicatedStorage/ecs" import { serverState } from "ReplicatedStorage/ecs/state" import { Host } from "ReplicatedStorage/hosts" @@ -7,14 +6,7 @@ import { getEvent } from "ReplicatedStorage/remotes" const HOST = Host.Server -const serverLogger = Logger.configure() - .EnrichWithProperty("Roblox-TS Version", _VERSION) - .WriteTo(Log.RobloxOutput()) - .Create() - -const ServerState = new serverState( - serverLogger -) +const ServerState = new serverState() // We only do this here at the moment to create a dummy event for replication. // In the future this will be created by the replication system. diff --git a/src/StarterPlayer/StarterPlayerScripts/main.client.ts b/src/StarterPlayer/StarterPlayerScripts/main.client.ts index aef73c6..36dc015 100644 --- a/src/StarterPlayer/StarterPlayerScripts/main.client.ts +++ b/src/StarterPlayer/StarterPlayerScripts/main.client.ts @@ -1,5 +1,4 @@ import { CharacterRigR6 } from "@rbxts/character-promise" -import Log, { Logger } from "@rbxts/log" import { Players } from "@rbxts/services" import { start } from "ReplicatedStorage/ecs" import { clientState } from "ReplicatedStorage/ecs/state" @@ -8,19 +7,11 @@ import { setEnvironment } from "ReplicatedStorage/idAttribute" const HOST = Host.Client -const clientLogger = Logger.configure() - .EnrichWithProperty("Roblox-TS Version", _VERSION) - .WriteTo(Log.RobloxOutput()) - .Create() +const ClientState = new clientState() -const ClientState = new clientState( - Players.LocalPlayer, - (Players.LocalPlayer.Character || Players.LocalPlayer.CharacterAdded.Wait()[0]) as CharacterRigR6, - false, - false, - - clientLogger -) +const player = Players.LocalPlayer +ClientState.character = (player.Character || player.CharacterAdded.Wait()[0]) as CharacterRigR6 +ClientState.player = player setEnvironment(HOST) start(HOST, ClientState) \ No newline at end of file diff --git a/src/Workspace/NotABasePart.rbxmx b/src/Workspace/NotABasePart.rbxmx new file mode 100644 index 0000000..93a1d9c --- /dev/null +++ b/src/Workspace/NotABasePart.rbxmx @@ -0,0 +1,118 @@ + + true + null + nil + + + false + + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + + 19 + 2.00000119 + 22 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + true + true + true + true + Default + 0 + 4288914085 + + false + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + false + false + 256 + + NotABasePart + + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + 0 + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + -1 + RXhhbXBsZQ== + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + 1 + 1 + + 4 + 4 + 4 + + + + + + + 1 + 1 + 1 + + 5 + Remilia Scarlet deka fumo + 9961773472 + + http://www.roblox.com/asset/?id=9961773438 + 0 + 1 + + + + \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 248ac04..e087f5d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -91,23 +91,11 @@ resolved "https://registry.yarnpkg.com/@rbxts/compiler-types/-/compiler-types-2.1.1-types.0.tgz#a1f02b57402dffec474dd6656ec1d8a897b9756b" integrity sha512-wBRma9MgPbOxvCaQEUvraHLHAmLFGW9R6fT65+MBu3uCYM6vUNWj8l4dHRxgkUK8lnGYdGWxsr/sZFk8sdvwog== -"@rbxts/log@^0.6.3": - version "0.6.3" - resolved "https://registry.yarnpkg.com/@rbxts/log/-/log-0.6.3.tgz#65b51a897a2d646457db95b563ade3313e08d0be" - integrity sha512-YZpDvjL7yif9aYuNAkuM9vnegcwQmOwX0CfvGfWvrzCpmARY4Ey2pTMhoEgxKo36HcdPPi3aLxmcuvn0NHrPPg== - dependencies: - "@rbxts/message-templates" "^0.3.1" - "@rbxts/matter@^0.6.2-ts.6": version "0.6.4" resolved "https://registry.yarnpkg.com/@rbxts/matter/-/matter-0.6.4.tgz#49ff6ce56bada1ce7c5e2715a05daaa3fb7615e6" integrity sha512-84naXqNpUfb5aCEcKf99wdqNnNAuwXh4B73GMQBzrUGiF70m0EWTdmm0qHihdlghGPrCRBSFeYK5esMJvKs/SQ== -"@rbxts/message-templates@^0.3.1": - version "0.3.2" - resolved "https://registry.yarnpkg.com/@rbxts/message-templates/-/message-templates-0.3.2.tgz#85169980cf73f659282aa9846290ceaf06967167" - integrity sha512-79onYskH3pgrBT73Zs+biQ31vAVvupKQaxGNWGjyGsxwNhO2YaN/qkut0bvOshaGa+ZzqAXApRVrN8ifIMPiMQ== - "@rbxts/plasma@^0.4.1-ts.1": version "0.4.1-ts.1" resolved "https://registry.yarnpkg.com/@rbxts/plasma/-/plasma-0.4.1-ts.1.tgz#3d8db367c3220e6b6953cdddbf8af9f087165392"