The sites run multiple 5-12+ player games where there are rounds of chatting and voting to eliminate players. There are bonus features like items that give special abilities, like to veto a vote.
Can Django do what node.js does for these apps? What about without a front-end framework?
Thanks, Ken. While I was researching I found a reply of yours to a similar question. Any resources you can point me to other than the Django docs and Channels docs?
I made a chat room app, and the user list will update based on who is active in it.
View:
def lobby(request, lobby_name):
lobby, created = Lobby.objects.get_or_create(lobby_name=lobby_name)
if request.user.profile.current_game == None:#retrieving user profile and adding them to lobby in DB
request.user.profile.current_game = lobby
request.user.profile.save()
return render(request, "mafia/room.html", {
'lobby_name': lobby.lobby_name,
'players': lobby.players.order_by('display_name')
})
else:
return HttpResponse("<h1>You're in a game already</h1>")
Iâm not sure what you mean by a âjuggling performanceâ.
The lobby view loads a page. That page would likely contain (directly or by reference) the code to connect and manage the websocket. Once the page is loaded, the view doesnât need to do anything else. I see it as more a âhandoffâ than a juggle.
We do it similarly to what you show here, except we use HTMX in the browser. That way we can render the html fragments on the server and just send the appropriate divs across the websocket. (We also use a slightly-patched version of django-channels-presence ¡ PyPI to track connection information across rooms.)
Iâm doing HTMX also. I could use presence, or would an async view (never wrote one) be able to keep track of player (ORM object), in a room (ORM object with relational âplayersâ), before the handoff? Then the consumer would not need the sync-to-async methods.
Keep in mind that once the view has returned the page to the browser, itâs done. It has no more effect on anything. It plays no further part in any communications.
We donât even render the people in the room in the view. The view only returns the basic structure for the page. All âactiveâ content is rendered by the consumer and related code. When a person connects to a chat room, the first thing that happens is that the consumer gets the names of the people in the room, renders the text, and sends it back out to the person connecting.
For those cases where we want to access the database in the consumer, we use the sync-to-async methods - they have never caused us any problems.
However, we have also made the architectural decision that all games are managed externally to the consumers. Each game is a Channels worker process - communication between the consumers and the games are through the channel layer. That allows us to run the game processors synchronously - ensuring we donât create any race conditions when resolving input.
(From this perspective, the âLobbyâ is just another âgameâ. A person enters text in a box in the browser, htmx sends that as a websocket frame to the consumer, the consumer forwards that text to the lobby worker, the lobby worker sends the message to all the consumers in the room. The consumers distribute that message back out to the browsers.)
How are you making the workers process and hold short-term data for specific games?
e.g. If I want to pop from a list to assign nicknames to players, where do I place this list? Is there an init method in the worker? Am wondering if the workers can hold data for these games played by each channel layer group.
Games are state machines. At any moment in time, a game is fundamentally in one of two states - either itâs waiting for input from one (or more) âplayersâ (more on that in a moment), or itâs processing input to alter the state of the game.
Our models for this get fairly involved. The state of a game consists of two parts, the general state and the game-specific state.
The general state consists of data that applies to any game being played, such as which Users are playing and when the game was started.
The game-specific state consists of all the data needed to store the state of the specific game being played. For example, if it were a chess game, it would be the current board, how much clock time is available for each person, and flags for each person to indicate whether or not they can still castle - and to which side(s). (It canât be definitively determined from the board itself.)
For tracking players, we use an object named Player as the many-to-many âthroughâ table between User and Game. The playerâs nickname is a field in that Model. (A person can have different nicknames in different games.)
Note regarding the use of the term âplayerâ above. A âplayerâ may also be a âbotâ - computer player, or a âtimerâ causing something to happen after a specified interval.