From 8232eacff26e933a7f029c5f96a48a3992a34879 Mon Sep 17 00:00:00 2001 From: reidlab Date: Fri, 11 Aug 2023 17:38:07 -0700 Subject: [PATCH] add custom hotbar --- .eslintrc | 1 + package.json | 2 + src/ReplicatedStorage/ecs/state.ts | 3 + src/ReplicatedStorage/ui/padding.tsx | 33 +++++++ src/ServerScriptService/main.server.ts | 6 +- .../StarterPlayerScripts/main.client.ts | 16 ++- .../StarterPlayerScripts/showGUI.tsx | 17 ++++ .../ui/contexts/worldContext.tsx | 34 +++++++ .../StarterPlayerScripts/ui/hotbar/hotbar.tsx | 65 +++++++++++++ .../StarterPlayerScripts/ui/hotbar/slot.tsx | 97 +++++++++++++++++++ .../StarterPlayerScripts/ui/main.tsx | 28 ++++++ yarn.lock | 10 ++ 12 files changed, 304 insertions(+), 8 deletions(-) create mode 100644 src/ReplicatedStorage/ui/padding.tsx create mode 100644 src/StarterPlayer/StarterPlayerScripts/showGUI.tsx create mode 100644 src/StarterPlayer/StarterPlayerScripts/ui/contexts/worldContext.tsx create mode 100644 src/StarterPlayer/StarterPlayerScripts/ui/hotbar/hotbar.tsx create mode 100644 src/StarterPlayer/StarterPlayerScripts/ui/hotbar/slot.tsx create mode 100644 src/StarterPlayer/StarterPlayerScripts/ui/main.tsx diff --git a/.eslintrc b/.eslintrc index d7d0de7..b216108 100644 --- a/.eslintrc +++ b/.eslintrc @@ -26,6 +26,7 @@ "@typescript-eslint/no-array-constructor": "error", "@typescript-eslint/no-empty-function": "error", "@typescript-eslint/no-empty-interface": "error", + "@typescript-eslint/no-empty-pattern": "none", "@typescript-eslint/no-namespace": "error", "@typescript-eslint/no-non-null-assertion": "warn", "@typescript-eslint/no-unused-vars": [ diff --git a/package.json b/package.json index 34f11bf..b0a850d 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,8 @@ "@rbxts/matter": "^0.6.2-ts.6", "@rbxts/plasma": "^0.4.1-ts.1", "@rbxts/rewire": "^0.3.0", + "@rbxts/roact": "^1.4.4-ts.0", + "@rbxts/roact-hooks": "^0.4.1-ts.3", "@rbxts/services": "^1.5.1", "@rbxts/testez": "^0.4.2-ts.0", "@rbxts/variant": "^1.0.2", diff --git a/src/ReplicatedStorage/ecs/state.ts b/src/ReplicatedStorage/ecs/state.ts index 7bc0c5f..c536d91 100644 --- a/src/ReplicatedStorage/ecs/state.ts +++ b/src/ReplicatedStorage/ecs/state.ts @@ -13,6 +13,7 @@ export class clientState { character: CharacterRigR6, debugEnabled: boolean, isRunning: boolean, + backpack: Backpack, // lastProcessedCommand: Inputkind, logger: Logger @@ -21,6 +22,7 @@ export class clientState { this.player = player this.debugEnabled = debugEnabled this.isRunning = isRunning + this.backpack = backpack // this.lastProcessedCommand = lastProcessedCommand this.logger = logger @@ -30,6 +32,7 @@ export class clientState { character: CharacterRigR6 debugEnabled: boolean isRunning: boolean + backpack: Backpack lastProcessedCommand?: InputKind logger: Logger diff --git a/src/ReplicatedStorage/ui/padding.tsx b/src/ReplicatedStorage/ui/padding.tsx new file mode 100644 index 0000000..6554ad7 --- /dev/null +++ b/src/ReplicatedStorage/ui/padding.tsx @@ -0,0 +1,33 @@ +import Hooks from "@rbxts/roact-hooks" +import Roact from "@rbxts/roact" + +interface PaddingProps extends Roact.JsxInstanceProperties { + Padding?: UDim | Roact.Binding + PaddingX?: UDim | Roact.Binding + PaddingY?: UDim | Roact.Binding + + Event?: Roact.JsxInstanceEvents + Change?: Roact.JsxInstanceChangeEvents +} + +const padding: Hooks.FC = (props, hooks) => { + const {} = hooks + const { Padding, PaddingX, PaddingY } = props + + const spreadableProps = { ...props } as Partial + delete spreadableProps.Padding + delete spreadableProps.PaddingX + delete spreadableProps.PaddingY + + return ( + + ) +} + +export default new Hooks(Roact)(padding) \ No newline at end of file diff --git a/src/ServerScriptService/main.server.ts b/src/ServerScriptService/main.server.ts index bd6fcdb..aa812f7 100644 --- a/src/ServerScriptService/main.server.ts +++ b/src/ServerScriptService/main.server.ts @@ -8,9 +8,9 @@ import { getEvent } from "ReplicatedStorage/remotes" const HOST = Host.Server const serverLogger = Logger.configure() - .EnrichWithProperty("Roblox-TS Version", _VERSION) - .WriteTo(Log.RobloxOutput()) - .Create() + .EnrichWithProperty("Roblox-TS Version", _VERSION) + .WriteTo(Log.RobloxOutput()) + .Create() const ServerState = new serverState( serverLogger diff --git a/src/StarterPlayer/StarterPlayerScripts/main.client.ts b/src/StarterPlayer/StarterPlayerScripts/main.client.ts index 42ca4ae..6d54254 100644 --- a/src/StarterPlayer/StarterPlayerScripts/main.client.ts +++ b/src/StarterPlayer/StarterPlayerScripts/main.client.ts @@ -1,25 +1,31 @@ import { CharacterRigR6 } from "@rbxts/character-promise" import Log, { Logger } from "@rbxts/log" -import { Players } from "@rbxts/services" +import { Players, StarterGui } from "@rbxts/services" import { start } from "ReplicatedStorage/ecs" import { clientState } from "ReplicatedStorage/ecs/state" import { Host } from "ReplicatedStorage/hosts" import { setEnvironment } from "ReplicatedStorage/idAttribute" +import showGUI from "./showGUI" const HOST = Host.Client const clientLogger = Logger.configure() - .WriteTo(Log.RobloxOutput()) - .Create() + .WriteTo(Log.RobloxOutput()) + .Create() const ClientState = new clientState( Players.LocalPlayer, (Players.LocalPlayer.Character || Players.LocalPlayer.CharacterAdded.Wait()[0]) as CharacterRigR6, false, false, + Players.LocalPlayer.WaitForChild("Backpack") as Backpack, clientLogger ) -setEnvironment(HOST) -start(HOST, ClientState) \ No newline at end of file +// no fuck off +StarterGui.SetCoreGuiEnabled(Enum.CoreGuiType.Backpack, false) + +const worldAndClientState = start(HOST, ClientState) +showGUI(worldAndClientState[0], ClientState) +setEnvironment(HOST) \ No newline at end of file diff --git a/src/StarterPlayer/StarterPlayerScripts/showGUI.tsx b/src/StarterPlayer/StarterPlayerScripts/showGUI.tsx new file mode 100644 index 0000000..e415ff3 --- /dev/null +++ b/src/StarterPlayer/StarterPlayerScripts/showGUI.tsx @@ -0,0 +1,17 @@ +import { World } from "@rbxts/matter" +import { clientState } from "ReplicatedStorage/ecs/state" +import WorldProvider from "./ui/contexts/worldContext" +import Roact from "@rbxts/roact" +import Main from "./ui/main" + +const showGUI = (world: World, state: clientState): void => { + const playerGui = state.player.WaitForChild("PlayerGui") as PlayerGui + const tree = ( + +
+ + ) + Roact.mount(tree, playerGui, "gooplerGUI") +} + +export default showGUI \ No newline at end of file diff --git a/src/StarterPlayer/StarterPlayerScripts/ui/contexts/worldContext.tsx b/src/StarterPlayer/StarterPlayerScripts/ui/contexts/worldContext.tsx new file mode 100644 index 0000000..2d0812e --- /dev/null +++ b/src/StarterPlayer/StarterPlayerScripts/ui/contexts/worldContext.tsx @@ -0,0 +1,34 @@ +import { World } from "@rbxts/matter" +import Roact, { createContext } from "@rbxts/roact" +import Hooks, { CoreHooks } from "@rbxts/roact-hooks" +import { clientState } from "ReplicatedStorage/ecs/state" + +interface WorldContextValue { + world: World + clientState: clientState +} + +interface Props { + world: World + clientState: clientState +} + +const WorldProviderWithoutHooks: Hooks.FC = (props) => { + const { world, clientState } = props + + return {props[Roact.Children]} +} + +const WorldProvider = new Hooks(Roact)(WorldProviderWithoutHooks) + +export default WorldProvider + +const WorldContext = createContext(undefined) + +export const useWorldContext = ({ useContext }: CoreHooks): WorldContextValue => { + const context = useContext(WorldContext) + if (!context) { + error("useContext must be called within a Provider") + } + return context +} \ No newline at end of file diff --git a/src/StarterPlayer/StarterPlayerScripts/ui/hotbar/hotbar.tsx b/src/StarterPlayer/StarterPlayerScripts/ui/hotbar/hotbar.tsx new file mode 100644 index 0000000..d536685 --- /dev/null +++ b/src/StarterPlayer/StarterPlayerScripts/ui/hotbar/hotbar.tsx @@ -0,0 +1,65 @@ +import Roact from "@rbxts/roact" +import Hooks from "@rbxts/roact-hooks" +import Slot from "./slot" +import { useWorldContext } from "../contexts/worldContext" +import Padding from "ReplicatedStorage/ui/padding" + +interface hotbarProps extends Roact.JsxInstanceProperties { + Event?: Roact.JsxInstanceEvents + Change?: Roact.JsxInstanceChangeEvents +} + +const hotbar: Hooks.FC = (props, hooks) => { + const {} = hooks + const {} = props + + const spreadableProps = { ...props } as Partial + + const { world, clientState } = useWorldContext(hooks) + + const keycodes: Enum.KeyCode[] = [ + Enum.KeyCode.One, + Enum.KeyCode.Two, + Enum.KeyCode.Three, + Enum.KeyCode.Four, + Enum.KeyCode.Five, + Enum.KeyCode.Six, + Enum.KeyCode.Seven, + Enum.KeyCode.Eight, + Enum.KeyCode.Nine + ] + + return ( + + + + + { + clientState.backpack.GetChildren().map((tool, i) => ( + + )) + } + + + ) +} + +export default new Hooks(Roact)(hotbar) \ No newline at end of file diff --git a/src/StarterPlayer/StarterPlayerScripts/ui/hotbar/slot.tsx b/src/StarterPlayer/StarterPlayerScripts/ui/hotbar/slot.tsx new file mode 100644 index 0000000..0c24259 --- /dev/null +++ b/src/StarterPlayer/StarterPlayerScripts/ui/hotbar/slot.tsx @@ -0,0 +1,97 @@ +import Roact from "@rbxts/roact" +import Hooks from "@rbxts/roact-hooks" +import { useWorldContext } from "../contexts/worldContext" +import { ContextActionService, HttpService } from "@rbxts/services" +import Padding from "ReplicatedStorage/ui/padding" + +interface slotProps extends Roact.JsxInstanceProperties { + index: number + keycode: Enum.KeyCode + tool: Tool + + Event?: Roact.JsxInstanceEvents + Change?: Roact.JsxInstanceChangeEvents +} + +const slot: Hooks.FC = (props, hooks) => { + const { useEffect } = hooks + const { index, keycode, tool } = props + + const spreadableProps = { ...props } as Partial + delete spreadableProps.index + delete spreadableProps.keycode + delete spreadableProps.tool + + const { world, clientState } = useWorldContext(hooks) + + const handleActivated = () => { + if (tool.Parent !== clientState.character) { + clientState.character.Humanoid.EquipTool(tool) + } else { + clientState.character.Humanoid.UnequipTools() + } + } + + // maybe opt this into our system for inputs? + useEffect(() => { + const guid = HttpService.GenerateGUID(false) + ContextActionService.BindAction( + guid, + (_, userInputState) => { + if (Enum.UserInputState.Begin === userInputState) handleActivated() + }, + false, + keycode + ) + }) + + return ( + + { + handleActivated() + } + }} + > + + + + + + + + + + + + + + ) +} + +export default new Hooks(Roact)(slot) \ No newline at end of file diff --git a/src/StarterPlayer/StarterPlayerScripts/ui/main.tsx b/src/StarterPlayer/StarterPlayerScripts/ui/main.tsx new file mode 100644 index 0000000..71fdd37 --- /dev/null +++ b/src/StarterPlayer/StarterPlayerScripts/ui/main.tsx @@ -0,0 +1,28 @@ +import Roact from "@rbxts/roact" +import Hooks from "@rbxts/roact-hooks" +import Hotbar from "./hotbar/hotbar" +import { Players } from "@rbxts/services" + +interface mainProps extends Roact.JsxInstanceEvents { + Event?: Roact.JsxInstanceEvents + Change?: Roact.JsxInstanceChangeEvents +} + +const main: Hooks.FC = (props, hooks) => { + const {} = props + const {} = hooks + + const spreadableProps = { ...props } as Partial + + return ( + + + + ) +} + +export default new Hooks(Roact)(main) \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 248ac04..22b4ad5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -118,6 +118,16 @@ resolved "https://registry.yarnpkg.com/@rbxts/rewire/-/rewire-0.3.0.tgz#47f0cd651fe405cf418936799d2a4dac6b1bb7ce" integrity sha512-wChhGZ3kEkEsMK9ZuwKpwRsC7OGVZlvxrYMR3beFgCIPXE58JKLziBLkDACmd709XCCEmsMAqv9HMCMhSTD08Q== +"@rbxts/roact-hooks@^0.4.1-ts.3": + version "0.4.1-ts.3" + resolved "https://registry.yarnpkg.com/@rbxts/roact-hooks/-/roact-hooks-0.4.1-ts.3.tgz#af9b549f5912bd50640c2887aa698e21154fadd3" + integrity sha512-+8A42hDsSwZNnXDe1XIRpJhjSpxFvkBa8nB5QM1zuL2q5G6h6SGp7augY6vp6euze/gH4/Laho07PUM8bz0RKQ== + +"@rbxts/roact@^1.4.4-ts.0": + version "1.4.4-ts.0" + resolved "https://registry.yarnpkg.com/@rbxts/roact/-/roact-1.4.4-ts.0.tgz#7f297bec03dbea9473bd2d82b148d3ae6e4f6c00" + integrity sha512-gn9mBoGG/Clzgv2kyOvLNVd9dh5t6z+jukC3ITv2HnfPqvf/sMbz/VMaBoiB7t5umuiIe0LjW0ctZrkrS+uTOA== + "@rbxts/services@^1.5.1": version "1.5.1" resolved "https://registry.yarnpkg.com/@rbxts/services/-/services-1.5.1.tgz#4536a87932f28797507ed591f0061277c52ea77f"