Thanks for this amazing framework!
I am encountering a possible limitations in triggering some actions whenever something happens. Indeed, the available Events API is only for predefined events and is only related to the ctx object.
To my understanding, it is not possible to create a custom event, and trigger / handle it server side from multiple areas of the code. For instance, I could define an event "CardPlayed" that is notified within a move (every time a player plays a card). Then, if there are one or more handler registered for that event, they will be executed. Otherwise nothing would happen.
Am I missing something?
ctx: {..., PlayerID: string | undefined}
correct?
Hi all. I have a couple of conceptual questions I'm hoping someone can help me out with.
Let's say I have a game with two stages in the turn section:
turn {
stages: {
doSomething: {
moves: { DoSomething },
next: "selectCardsAndShowOne"
}
selectOneCardToShow: {
moves: { SelectOneCardToShow}
}
}
}
Basically, each turn you do some move (the "doSomething" stage) and then you have to, let's say, pick two cards from a deck, show on on the board, and discard the other (the "selectOneCardToShow" stage).
My issue is that the move in the second stage ("SelectOneCardToShow") consists of taking two cards into your hand from a deck and choosing one to display to everyone. In my mind, and maybe this is the wrong way to think about it, it's only the last part that's the actual move, because the only part where the player has to make a choice. The first part, where the two cards are picked from the deck, isn't really under the player's control. He has to do it, and he has to pick the top two cards.
So how do you model that first part? What part of the framework runs the code which takes the two cards from the deck and puts them into the player's hand?
One thought that occurred to me is that I could do it as part of the previous move, the "DoSomething". At the end of that move, I could transfer two cards into the player's hand. But that seems messy, especially since those cards have nothing to do with "DoSomething".
Is there a "beginStage" hook I can run? That could work but I didn't see one in the docs.
Another option is to treat the "Pick two cards" part as a separate move. That seems weird too, especially since the player doesn't really have anything to do except pick the cards. No choice to be made or anything. I guess one could do that, but I'm still not sure how I'd "enforce" the move, since it's basically mandatory now.
Any thoughts or ideas? Thanks in advance.
Hello guys, i have a big problem since few days, when i start my script cmd to launch my server, i get an error which says :
"[C:\Users\kavne\Desktop\cardgame\src\server.js:1
Error [ERR_REQUIRE_ESM]: require() of ES Module C:\Users\user\Desktop\cardgame\src\server.js not supported.
Instead change the require of server.js in null to a dynamic import() which is available in all CommonJS modules.] {
code: 'ERR_REQUIRE_ESM'
}"
It Strange because my package.json contains "type: 'module' "
Anyone could help me please ??
Hi guys. I have a conceptual question. I am working on a game where for each turn, each player should execute some moves and then pass the turn to another player to do the same moves, for example:
Turn 1:
Turn 2:
...
How can I create a game structure for that?
Hi there,
I have added a button to my game to allow the player to undo their last action, but when I click the button nothing seems to happen. I have confirmed that the handler is setup correctly and props.undo()
is getting hit. Is there something else that I need to do to utilize undo/redo?
Hello!
I'm trying to use typescript with boardgame.io and I get stuck with this error:
Uncaught Error: Move state is not JSON-serialiazable.
See https://boardgame.io/documentation/#/?id=state for more information.
My problem seems to be, that I'm adding an array of very primitive Objects to the state:
export class Card {
suit: string;
rank: number;
shortname: string;
constructor(suit: string, rank: number) {
this.suit = suit;
this.rank = rank;
this.shortname = this.suit + this.rank;
}
}
export type Hand = Card[];
...
export interface SpadesGameState {
bids: string[];
score: number[];
hands: Hand[];
currentTrick?: Trick;
lastTrick?: Trick;
dealer: number;
isSpadesOpen: boolean;
}
...
return { ...G, isSpadesOpen: false, currentTrick: undefined, lastTrick: undefined, hands: [[new Card("d", 1),new Card("d", 4)], [], [], []] as Hand[]}
Is it really true that I cannot have a GameState that has a typed ("classed") property inside or should I search for the error elsewhere..?
matchData
object with isConnected: true
Certain events are double-firing inappropriately, and I'm at a loss for why. I have a phase in which most turns are automatic. In the exceptions, I shunt players into a stage to make a move before ending the turn. An onEnd
hook for the turn then fires. My problem is that, sometimes, that onEnd
hook fires twice. It seems to happen when either the phase ends or the event needs to call another move function. At least in the latter case, the top of the call stack looks like: (my onEnd
hook) > wrapFn
> produce
> wrapFn
, where both wrapFn
s come from the Immer plugin. This seems weird, and calls to mind this old bug: boardgameio/boardgame.io#544. But I don't know how to fix or work around it.
Appreciate any help you can give.
Hello, I have an array (called 'selection') in my game state (G). I want a react component to refresh when an item is added/removed to/from this array. The problem is that my 'useEffect' function does not trigger.
export function MyBoard({ ctx, G, moves }) {
const [selection, setSelection] = useState([]);
useEffect(() => {
setSelection(G.selection);
}, [G.selection]);
... }
Here is the code (in my moves) that adds an element to the array (I avoid using 'push' as it does not change the array) :
G.selection = [...G.selection, item];
Thank you for your help !
Hi i just posted a new issue here : boardgameio/boardgame.io#1100
"Hi ! i have a custom lobby mechanism on my project which implement basic matchmaking between players.
When sufficient players have joined the lobby i create the match from my api and send an event to all the players to redirect them to the match page.
When the match page load, an http call occurs to log the user to the game server.
It seems that the boardgame implementation cannot handle simultaneous connection changes properly.
When someone logs into the match (https://github.com/boardgameio/boardgame.io/blob/main/src/master/master.ts#L400)
the match metadata is fetched from my database, modified to include the new metadata, sent to all clients and then saved to the database.
When 2 players joins the match simultaneously, this logic is called 4 times simultaneously and it looks like that some players are overriding the metadata changes of previous users.
For example:
Player 1 is redirected to match page
Player 2 is redirected to match page
Player 1 onConnectionChange method start and fetch metadata
Player 2 onConnectionChange method start and fetch metadata
Player 1 onConnectionChange method modify metadata and save it to the database
Player 2 onConnectionChange method modify metadata and save it to the database
as Player 2 fetched the metadata before Player 1 finished modifying and saving it to the database, when Player 2 modify and save the metadata into the database, the data is outdated and does not contain Player 1 isConnected and credentials values. Player 2 is correctly logged into the match but Player 1 stay on the "Connecting..." screen indefinitely and the match get stuck when his turn start...
Sometimes everything plays nicely in the correct order but most of the time, for example in a 4 players match, a player stay on the loading screen and the match is blocked, this is really critical for my project, how can this be fixed ?"
Does anyone has encountered the same behavior ? and maybe found a solution for it ?
Hello! I'm currently wrapping my head around the difference between stages and phases.
I get that a stage works within the concept of a turn, i.e. that it retains the concept of the current player, and that a phase is a lot broader in scope, where you can change turn order, current player, etc.
One unique thing that a stage provides that a phase does not on its own is the ability for other players to makes moves during the current player's turn, i.e. other players can make moves without modifying the value of the "current player".
In fact, to me, this is the killer feature of stages - the ability to have more that one player making moves. I say this because if you take this feature out of consideration, then there's not much a difference between stages and phases, is there? Am I wrong about that?
In particular, if you don't need the ability for other players to make moves on someone else's turn, then I imagine you can just treat phases like stages - especially if the phases all have a turn order of CONTINUE (i.e. the current player in the next phase is the one who ended the previous phase). With phases all having a turn order of CONTINUE, and if we don't need other players to make moves during the current player's turn, is there really a difference between phases and stages?
I was wondering whether anybody could give me an opinion on my lobby/site to play games.
It's https://cuberail.games, and the source is on https://github.com/lkingsford/CubeRailDotGames. The one game on it is on https://github.com/lkingsford/EmuBayOnlineClient
Going to thread to describe what I've got happening with the lobby (and more precisely, what I'm wondering if there's a better way to do)
I'm trying to run some game state tests using:
let client = Client({ game: customGameSetup, playerID: '0', multiplayer: Local() });
when I run the tests I get CONSOLE ERROR messages:
ERROR: invalid value returned by turn.order.first — expected number got object “null”.
which seems to be coming from bgio not my source... any idea what causes this issue? Likely I'm misusing the Client instance but not sure how.
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at <url>. (Reason: CORS request did not succeed). Status code: (null).
. I currently have the origins on the server set as origins: [Origins.LOCALHOST]
, and I may change the setup to two servers.