seperated client and server state, input mapper

This commit is contained in:
Reid 2023-07-20 14:48:17 -07:00
parent 44f63f8deb
commit d5b77a9044
10 changed files with 104 additions and 16 deletions

View file

@ -37,6 +37,7 @@
"@rbxts/plasma": "^0.4.1-ts.1",
"@rbxts/rewire": "^0.3.0",
"@rbxts/services": "^1.5.1",
"@rbxts/testez": "^0.4.2-ts.0"
"@rbxts/testez": "^0.4.2-ts.0",
"@rbxts/variant": "^1.0.2"
}
}

View file

@ -8,7 +8,7 @@ An in-dev game that I plan to make a shooter game out of.
— reidlab
# Hacks
* I get a strange error about private identifiers in [`./src/ReplicatedStorage/ecs/state.ts:7`](./src/ReplicatedStorage/ecs/state.ts)
* 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

View file

@ -6,7 +6,7 @@ import { Host } from "ReplicatedStorage/hosts"
import { tags } from "./boundTags"
import { Model } from "./components"
import { start as startReplication, stop as stopReplication } from "./replication"
import { State } from "./state"
import { clientState, serverState } from "./state"
import { start as startSystems, stop as stopSystems } from "./systems"
import { start as startTags, stop as stopTags } from "./tags"
@ -22,10 +22,9 @@ let connections:
}
| undefined
export function start(host: Host): [World, State] {
export function start<S extends object>(host: Host, state: S): [World, S] {
if (connections) throw "ECS already running."
const state: State = new State()
const world = new World()
const debug = new Debugger(Plasma)
debug.authorize = authorize
@ -46,11 +45,15 @@ export function start(host: Host): [World, State] {
})
if (host === Host.All || host === Host.Server) {
const _ServerState = state as serverState
startTags(world, tags)
}
if (host === Host.All || host === Host.Client) {
startReplication(world, state)
const ClientState = state as clientState
startReplication(world, ClientState)
const serverDebugger = ReplicatedStorage.FindFirstChild("MatterDebugger")
if (serverDebugger && serverDebugger.IsA("ScreenGui")) {
@ -65,7 +68,7 @@ export function start(host: Host): [World, State] {
UserInputService.InputBegan.Connect((input) => {
if (input.KeyCode === Enum.KeyCode.F4 && authorize(Players.LocalPlayer)) {
debug.toggle()
state.debugEnabled = debug.enabled
ClientState.debugEnabled = debug.enabled
}
})
}

View file

@ -1,7 +1,7 @@
import { AnyEntity, World } from "@rbxts/matter"
import { waitForEvent } from "ReplicatedStorage/remotes"
import * as Components from "./components"
import { State } from "./state"
import { clientState } from "./state"
type ComponentNames = keyof typeof Components
type ComponentConstructors = (typeof Components)[ComponentNames]
@ -16,13 +16,13 @@ let connection: RBXScriptConnection | undefined
* Starts the replication receiver.
*
* @param world - The world to replicate components in
* @param state - The global state for the ECS
* @param ClientState - The client state for the ECS
*/
export function start(world: World, state: State): void {
export function start(world: World, ClientState: clientState): void {
if (connection) return
function debugPrint(message: string, args: () => (string | number)[]): void {
if (state.debugEnabled) {
if (ClientState.debugEnabled) {
print("ECS Replication>", string.format(message, ...args()))
}
}

View file

@ -1,8 +1,21 @@
/* eslint-disable roblox-ts/no-private-identifier */
import { InputKind } from "ReplicatedStorage/inputKind"
/**
* The global ECS state.
* The client ECS state.
*/
export class State {
export class clientState {
[index: string]: unknown,
// eslint-disable-next-line roblox-ts/no-private-identifier
debugEnabled = false
isJumping = false
isRunning = false
lastProcessedCommand?: InputKind
}
/**
* The server ECS state.
*/
export class serverState {
[index: string]: unknown
}

View file

@ -0,0 +1,44 @@
import { useDeltaTime, useEvent, useThrottle, World } from "@rbxts/matter"
import { UserInputService } from "@rbxts/services"
import { clientState } from "ReplicatedStorage/ecs/state"
import { InputKind } from "ReplicatedStorage/inputKind"
let holdDuration = 0
function inputMapper(_: World, client: clientState): void {
for (const [, input, gpe] of useEvent(UserInputService, "InputBegan")) {
if (gpe) return undefined
if (input.KeyCode !== Enum.KeyCode.Unknown) {
client.lastProcessedCommand = InputKind.KeyDown(input.KeyCode)
} else if (input.UserInputType === Enum.UserInputType.MouseButton1) {
if (useThrottle(0.5)) {
client.lastProcessedCommand = InputKind.PointerClick
return undefined
}
client.lastProcessedCommand = InputKind.DoubleClick
}
return undefined
}
for (const [, input, gpe] of useEvent(UserInputService, "InputEnded")) {
if (gpe) return undefined
if (input.KeyCode !== Enum.KeyCode.Unknown) {
client.lastProcessedCommand = InputKind.KeyUp(input.KeyCode)
} else if (input.UserInputType === Enum.UserInputType.MouseButton1) {
client.lastProcessedCommand = InputKind.HoldRelease
}
return undefined
}
if (UserInputService.IsMouseButtonPressed(Enum.UserInputType.MouseButton1)) {
holdDuration += useDeltaTime()
client.lastProcessedCommand = InputKind.Hold(holdDuration)
return
}
holdDuration = 0
client.lastProcessedCommand = undefined
return
}
export = inputMapper

View file

@ -0,0 +1,16 @@
import variantModule, { TypeNames, VariantOf } from "@rbxts/variant"
export const InputKind = variantModule({
// Sub-messages
KeyDown: (key: Enum.KeyCode) => ({ key }),
KeyUp: (key: Enum.KeyCode) => ({ key }),
Hold: (duration: number) => ({ duration }),
// Messages
HoldRelease: {},
DoubleClick: {},
PointerMove: {},
PointerClick: {}
})
export type InputKind<T extends TypeNames<typeof InputKind> = undefined> = VariantOf<typeof InputKind, T>

View file

@ -1,13 +1,16 @@
import { start } from "ReplicatedStorage/ecs"
import { serverState } from "ReplicatedStorage/ecs/state"
import { Host } from "ReplicatedStorage/hosts"
import { setEnvironment } from "ReplicatedStorage/idAttribute"
import { getEvent } from "ReplicatedStorage/remotes"
const HOST = Host.Server
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.
getEvent("EcsReplication")
setEnvironment(HOST)
start(HOST)
start(HOST, ServerState)

View file

@ -1,8 +1,11 @@
import { start } from "ReplicatedStorage/ecs"
import { clientState } from "ReplicatedStorage/ecs/state"
import { Host } from "ReplicatedStorage/hosts"
import { setEnvironment } from "ReplicatedStorage/idAttribute"
const HOST = Host.Client
const ClientState = new clientState()
setEnvironment(HOST)
start(HOST)
start(HOST, ClientState)

View file

@ -121,6 +121,11 @@
resolved "https://registry.yarnpkg.com/@rbxts/validate-tree/-/validate-tree-2.0.2.tgz#2a1807eaa391a482822207177ff5dcd4b8f811b2"
integrity sha512-OA0E9ZjEeOpPa3XeV5/oC51aro2QFcL5dItufbagYZW8TOsX8C+FDXLx+A/ulMwcF42WcFNcQybxzcWSS/QSrA==
"@rbxts/variant@^1.0.2":
version "1.0.2"
resolved "https://registry.yarnpkg.com/@rbxts/variant/-/variant-1.0.2.tgz#91863201d3eb8f7759d7c5719f4af54ae969b8d4"
integrity sha512-cLfjIheMFmII0YMlLbChjD+jj3jcmLhcli2xXdGXCE1WIt6txOYqehaLZcUxyK6D6tFL727txhaseKu+3Hiazg==
"@types/json-schema@^7.0.9":
version "7.0.12"
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.12.tgz#d70faba7039d5fca54c83c7dbab41051d2b6f6cb"