add custom hotbar

This commit is contained in:
Reid 2023-08-11 17:38:07 -07:00
parent 72029047a5
commit 8232eacff2
12 changed files with 304 additions and 8 deletions

View file

@ -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 fuck off
StarterGui.SetCoreGuiEnabled(Enum.CoreGuiType.Backpack, false)
const worldAndClientState = start(HOST, ClientState)
showGUI(worldAndClientState[0], ClientState)
setEnvironment(HOST)

View file

@ -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 = (
<WorldProvider clientState={state} world={world}>
<Main/>
</WorldProvider>
)
Roact.mount(tree, playerGui, "gooplerGUI")
}
export default showGUI

View file

@ -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> = (props) => {
const { world, clientState } = props
return <WorldContext.Provider value={{ world, clientState }}>{props[Roact.Children]}</WorldContext.Provider>
}
const WorldProvider = new Hooks(Roact)(WorldProviderWithoutHooks)
export default WorldProvider
const WorldContext = createContext<WorldContextValue | undefined>(undefined)
export const useWorldContext = ({ useContext }: CoreHooks): WorldContextValue => {
const context = useContext(WorldContext)
if (!context) {
error("useContext must be called within a Provider")
}
return context
}

View file

@ -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<Frame> {
Event?: Roact.JsxInstanceEvents<Frame>
Change?: Roact.JsxInstanceChangeEvents<Frame>
}
const hotbar: Hooks.FC<hotbarProps> = (props, hooks) => {
const {} = hooks
const {} = props
const spreadableProps = { ...props } as Partial<hotbarProps>
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 (
<frame
{...spreadableProps}
AutomaticSize={Enum.AutomaticSize.X}
AnchorPoint={new Vector2(0.5, 1)}
BackgroundTransparency={1}
Key="Hotbar"
>
<frame Size={new UDim2(0, 0, 0.5, 0)} Position={new UDim2(0.5, 0, 0.5, 0)} BackgroundTransparency={1}>
<uilistlayout
FillDirection={Enum.FillDirection.Horizontal}
HorizontalAlignment={Enum.HorizontalAlignment.Center}
VerticalAlignment={Enum.VerticalAlignment.Bottom}
Padding={new UDim(0, 5)}
/>
<Padding
PaddingY={new UDim(0, 5)}
/>
{
clientState.backpack.GetChildren().map((tool, i) => (
<Slot
index={i + 1}
Size={new UDim2(1, 0, 1, 0)}
keycode={keycodes[i]}
tool={tool as Tool}
/>
))
}
</frame>
</frame>
)
}
export default new Hooks(Roact)(hotbar)

View file

@ -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<Frame> {
index: number
keycode: Enum.KeyCode
tool: Tool
Event?: Roact.JsxInstanceEvents<Frame>
Change?: Roact.JsxInstanceChangeEvents<Frame>
}
const slot: Hooks.FC<slotProps> = (props, hooks) => {
const { useEffect } = hooks
const { index, keycode, tool } = props
const spreadableProps = { ...props } as Partial<slotProps>
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 (
<frame {...spreadableProps} BackgroundTransparency={1} SizeConstraint={Enum.SizeConstraint.RelativeYY}>
<textbutton
Position={new UDim2(0, 0, 0, 0)}
Size={new UDim2(1, 0, 1, 0)}
BackgroundColor3={new Color3()}
BackgroundTransparency={0.3}
Text=""
Event={{
Activated: () => {
handleActivated()
}
}}
>
<uicorner CornerRadius={new UDim(0.05, 0)}/>
<uistroke
Thickness={2}
Color={new Color3(0.1, 0.1, 0.1)}
ApplyStrokeMode={Enum.ApplyStrokeMode.Border}
/>
<textlabel
Size={new UDim2(1, 0, 0.2, 0)}
Text={tostring(index)}
TextXAlignment={Enum.TextXAlignment.Left}
BackgroundTransparency={1}
TextColor3={new Color3(1, 1, 1)}
TextScaled
>
<uistroke Thickness={1}/>
</textlabel>
<textlabel
Size={new UDim2(1, 0, 1, 0)}
AnchorPoint={new Vector2(0.5, 0.5)}
Position={new UDim2(0.5, 0, 0.5, 0)}
BackgroundTransparency={1}
TextScaled
Text={tool.Name}
TextColor3={Color3.fromRGB(255, 255, 255)}
>
<uistroke Thickness={1}/>
<Padding Padding={new UDim(0.05, 0)}/>
</textlabel>
</textbutton>
</frame>
)
}
export default new Hooks(Roact)(slot)

View file

@ -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<ScreenGui> {
Event?: Roact.JsxInstanceEvents<ScreenGui>
Change?: Roact.JsxInstanceChangeEvents<ScreenGui>
}
const main: Hooks.FC<mainProps> = (props, hooks) => {
const {} = props
const {} = hooks
const spreadableProps = { ...props } as Partial<mainProps>
return (
<screengui ResetOnSpawn={false} IgnoreGuiInset {...spreadableProps}>
<Hotbar
Position={new UDim2(0.5, 0, 1, 0)}
AnchorPoint={new Vector2(0.5, 1)}
Size={new UDim2(1, 0, 0.2, 0)}
/>
</screengui>
)
}
export default new Hooks(Roact)(main)