Skip to content

Instantly share code, notes, and snippets.

@sasial-dev
Last active November 11, 2024 02:04
Show Gist options
  • Save sasial-dev/561bbbefd40b75425f325850edfb2b1d to your computer and use it in GitHub Desktop.
Save sasial-dev/561bbbefd40b75425f325850edfb2b1d to your computer and use it in GitHub Desktop.
Reflex Multiplayer
// 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);
};
@sasial-dev
Copy link
Author

Massive thanks to @littensy for typings help!

Please note - due to TS being strange you need to call this as combineProducers(DatabaseRoot).enhance(withMultiplayer) not withMultiplayer(combineProducers(DatabaseRoot))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment