Last active
November 11, 2024 02:04
-
-
Save sasial-dev/561bbbefd40b75425f325850edfb2b1d to your computer and use it in GitHub Desktop.
Reflex Multiplayer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Under the MIT | |
import type { Producer, InferState, InferActions } from "@rbxts/reflex"; | |
import { createProducer } from "@rbxts/reflex"; | |
import { Dictionary as Object } from "@rbxts/sift"; | |
// from reflex! | |
type ReplaceStateParameters<State, Actions> = { | |
readonly [K in keyof Actions]: Actions[K] extends (state: any, ...args: infer Args) => any | |
? (state: State, player: Player, ...args: Args) => State | |
: never; | |
}; | |
// we do NOT want to add setPlayerState, as that would set the player's state for all mutiplayer producers | |
type PlayerActions<State> = { | |
readonly removePlayer: (state: State, player: Player) => State; | |
}; | |
export const withMultiplayer = < | |
P extends Producer, | |
S extends InferState<P>, | |
A extends ReplaceStateParameters<Map<Player, S>, InferActions<P>> & PlayerActions<Map<Player, S>>, | |
>( | |
producer: P, | |
): Producer<Map<Player, S>, A> => { | |
const actions = Object.map( | |
producer.getActions() as Record<string, (state: S, ...args: unknown[]) => S>, | |
(action) => { | |
return (combinedState: Map<Player, S>, player: Player, ...args: unknown[]) => { | |
const nextState = table.clone(combinedState); | |
if (!nextState.has(player)) { | |
nextState.set(player, producer.getState()); | |
} | |
const producerState = nextState.get(player)!; | |
nextState.set(player, action(producerState, ...args)); | |
return nextState; | |
}; | |
}, | |
) as never; | |
(actions as Writable<PlayerActions<Map<Player, S>>>).removePlayer = (state, player) => { | |
const nextState = table.clone(state); | |
nextState.delete(player); | |
return nextState; | |
}; | |
return createProducer(new Map(), actions); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Massive thanks to @littensy for typings help!
Please note - due to TS being strange you need to call this as
combineProducers(DatabaseRoot).enhance(withMultiplayer)
notwithMultiplayer(combineProducers(DatabaseRoot))