seperated client and server state, input mapper
This commit is contained in:
parent
44f63f8deb
commit
d5b77a9044
10 changed files with 104 additions and 16 deletions
|
@ -37,6 +37,7 @@
|
||||||
"@rbxts/plasma": "^0.4.1-ts.1",
|
"@rbxts/plasma": "^0.4.1-ts.1",
|
||||||
"@rbxts/rewire": "^0.3.0",
|
"@rbxts/rewire": "^0.3.0",
|
||||||
"@rbxts/services": "^1.5.1",
|
"@rbxts/services": "^1.5.1",
|
||||||
"@rbxts/testez": "^0.4.2-ts.0"
|
"@rbxts/testez": "^0.4.2-ts.0",
|
||||||
|
"@rbxts/variant": "^1.0.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ An in-dev game that I plan to make a shooter game out of.
|
||||||
— reidlab
|
— reidlab
|
||||||
|
|
||||||
# Hacks
|
# 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.
|
* 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
|
# Todo
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { Host } from "ReplicatedStorage/hosts"
|
||||||
import { tags } from "./boundTags"
|
import { tags } from "./boundTags"
|
||||||
import { Model } from "./components"
|
import { Model } from "./components"
|
||||||
import { start as startReplication, stop as stopReplication } from "./replication"
|
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 startSystems, stop as stopSystems } from "./systems"
|
||||||
import { start as startTags, stop as stopTags } from "./tags"
|
import { start as startTags, stop as stopTags } from "./tags"
|
||||||
|
|
||||||
|
@ -22,10 +22,9 @@ let connections:
|
||||||
}
|
}
|
||||||
| undefined
|
| 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."
|
if (connections) throw "ECS already running."
|
||||||
|
|
||||||
const state: State = new State()
|
|
||||||
const world = new World()
|
const world = new World()
|
||||||
const debug = new Debugger(Plasma)
|
const debug = new Debugger(Plasma)
|
||||||
debug.authorize = authorize
|
debug.authorize = authorize
|
||||||
|
@ -46,11 +45,15 @@ export function start(host: Host): [World, State] {
|
||||||
})
|
})
|
||||||
|
|
||||||
if (host === Host.All || host === Host.Server) {
|
if (host === Host.All || host === Host.Server) {
|
||||||
|
const _ServerState = state as serverState
|
||||||
|
|
||||||
startTags(world, tags)
|
startTags(world, tags)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (host === Host.All || host === Host.Client) {
|
if (host === Host.All || host === Host.Client) {
|
||||||
startReplication(world, state)
|
const ClientState = state as clientState
|
||||||
|
|
||||||
|
startReplication(world, ClientState)
|
||||||
|
|
||||||
const serverDebugger = ReplicatedStorage.FindFirstChild("MatterDebugger")
|
const serverDebugger = ReplicatedStorage.FindFirstChild("MatterDebugger")
|
||||||
if (serverDebugger && serverDebugger.IsA("ScreenGui")) {
|
if (serverDebugger && serverDebugger.IsA("ScreenGui")) {
|
||||||
|
@ -65,7 +68,7 @@ export function start(host: Host): [World, State] {
|
||||||
UserInputService.InputBegan.Connect((input) => {
|
UserInputService.InputBegan.Connect((input) => {
|
||||||
if (input.KeyCode === Enum.KeyCode.F4 && authorize(Players.LocalPlayer)) {
|
if (input.KeyCode === Enum.KeyCode.F4 && authorize(Players.LocalPlayer)) {
|
||||||
debug.toggle()
|
debug.toggle()
|
||||||
state.debugEnabled = debug.enabled
|
ClientState.debugEnabled = debug.enabled
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { AnyEntity, World } from "@rbxts/matter"
|
import { AnyEntity, World } from "@rbxts/matter"
|
||||||
import { waitForEvent } from "ReplicatedStorage/remotes"
|
import { waitForEvent } from "ReplicatedStorage/remotes"
|
||||||
import * as Components from "./components"
|
import * as Components from "./components"
|
||||||
import { State } from "./state"
|
import { clientState } from "./state"
|
||||||
|
|
||||||
type ComponentNames = keyof typeof Components
|
type ComponentNames = keyof typeof Components
|
||||||
type ComponentConstructors = (typeof Components)[ComponentNames]
|
type ComponentConstructors = (typeof Components)[ComponentNames]
|
||||||
|
@ -16,13 +16,13 @@ let connection: RBXScriptConnection | undefined
|
||||||
* Starts the replication receiver.
|
* Starts the replication receiver.
|
||||||
*
|
*
|
||||||
* @param world - The world to replicate components in
|
* @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
|
if (connection) return
|
||||||
|
|
||||||
function debugPrint(message: string, args: () => (string | number)[]): void {
|
function debugPrint(message: string, args: () => (string | number)[]): void {
|
||||||
if (state.debugEnabled) {
|
if (ClientState.debugEnabled) {
|
||||||
print("ECS Replication>", string.format(message, ...args()))
|
print("ECS Replication>", string.format(message, ...args()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
[index: string]: unknown,
|
||||||
// eslint-disable-next-line roblox-ts/no-private-identifier
|
|
||||||
debugEnabled = false
|
debugEnabled = false
|
||||||
|
isJumping = false
|
||||||
|
isRunning = false
|
||||||
|
lastProcessedCommand?: InputKind
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The server ECS state.
|
||||||
|
*/
|
||||||
|
export class serverState {
|
||||||
|
[index: string]: unknown
|
||||||
}
|
}
|
44
src/ReplicatedStorage/ecs/systems/client/inputMapper.ts
Normal file
44
src/ReplicatedStorage/ecs/systems/client/inputMapper.ts
Normal 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
|
16
src/ReplicatedStorage/inputKind.ts
Normal file
16
src/ReplicatedStorage/inputKind.ts
Normal 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>
|
|
@ -1,13 +1,16 @@
|
||||||
import { start } from "ReplicatedStorage/ecs"
|
import { start } from "ReplicatedStorage/ecs"
|
||||||
|
import { serverState } from "ReplicatedStorage/ecs/state"
|
||||||
import { Host } from "ReplicatedStorage/hosts"
|
import { Host } from "ReplicatedStorage/hosts"
|
||||||
import { setEnvironment } from "ReplicatedStorage/idAttribute"
|
import { setEnvironment } from "ReplicatedStorage/idAttribute"
|
||||||
import { getEvent } from "ReplicatedStorage/remotes"
|
import { getEvent } from "ReplicatedStorage/remotes"
|
||||||
|
|
||||||
const HOST = Host.Server
|
const HOST = Host.Server
|
||||||
|
|
||||||
|
const ServerState = new serverState()
|
||||||
|
|
||||||
// We only do this here at the moment to create a dummy event for replication.
|
// 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.
|
// In the future this will be created by the replication system.
|
||||||
getEvent("EcsReplication")
|
getEvent("EcsReplication")
|
||||||
|
|
||||||
setEnvironment(HOST)
|
setEnvironment(HOST)
|
||||||
start(HOST)
|
start(HOST, ServerState)
|
|
@ -1,8 +1,11 @@
|
||||||
import { start } from "ReplicatedStorage/ecs"
|
import { start } from "ReplicatedStorage/ecs"
|
||||||
|
import { clientState } from "ReplicatedStorage/ecs/state"
|
||||||
import { Host } from "ReplicatedStorage/hosts"
|
import { Host } from "ReplicatedStorage/hosts"
|
||||||
import { setEnvironment } from "ReplicatedStorage/idAttribute"
|
import { setEnvironment } from "ReplicatedStorage/idAttribute"
|
||||||
|
|
||||||
const HOST = Host.Client
|
const HOST = Host.Client
|
||||||
|
|
||||||
|
const ClientState = new clientState()
|
||||||
|
|
||||||
setEnvironment(HOST)
|
setEnvironment(HOST)
|
||||||
start(HOST)
|
start(HOST, ClientState)
|
|
@ -121,6 +121,11 @@
|
||||||
resolved "https://registry.yarnpkg.com/@rbxts/validate-tree/-/validate-tree-2.0.2.tgz#2a1807eaa391a482822207177ff5dcd4b8f811b2"
|
resolved "https://registry.yarnpkg.com/@rbxts/validate-tree/-/validate-tree-2.0.2.tgz#2a1807eaa391a482822207177ff5dcd4b8f811b2"
|
||||||
integrity sha512-OA0E9ZjEeOpPa3XeV5/oC51aro2QFcL5dItufbagYZW8TOsX8C+FDXLx+A/ulMwcF42WcFNcQybxzcWSS/QSrA==
|
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":
|
"@types/json-schema@^7.0.9":
|
||||||
version "7.0.12"
|
version "7.0.12"
|
||||||
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.12.tgz#d70faba7039d5fca54c83c7dbab41051d2b6f6cb"
|
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.12.tgz#d70faba7039d5fca54c83c7dbab41051d2b6f6cb"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue