2026-04-04 14:33:35 -04:00
|
|
|
from channels.db import database_sync_to_async
|
2026-03-16 18:44:06 -04:00
|
|
|
from channels.generic.websocket import AsyncJsonWebsocketConsumer
|
|
|
|
|
|
|
|
|
|
|
2026-04-04 14:33:35 -04:00
|
|
|
LEVITY_ROLES = {"PC", "NC", "SC"}
|
|
|
|
|
GRAVITY_ROLES = {"BC", "EC", "AC"}
|
|
|
|
|
|
|
|
|
|
|
2026-03-16 18:44:06 -04:00
|
|
|
class RoomConsumer(AsyncJsonWebsocketConsumer):
|
|
|
|
|
async def connect(self):
|
Django Channels role-select sprint: turn_changed, roles_revealed, role_select_start consumer handlers; WS URL changed from room_slug to room_id UUID; TableSeat model - room, gamer, slot_number, role, role_revealed, seat_position fields; Room.table_status field with ROLE_SELECT, SIG_SELECT, IN_GAME choices; migration 0006_table_status_and_table_seat; pick_roles and select_role views; _role_select_context helper; _notify_turn_changed, _notify_roles_revealed, _notify_role_select_start notifiers; all gate-mutation views now call _notify_gate_update; ChannelsFunctionalTest base class with serve_static, screenshot, dump helpers; SQLite TEST NAME set to file path for ChannelsLiveServerTestCase; InMemoryChannelLayer added to test CHANNEL_LAYERS settings; FT 5 and FT 6 now passing - active seat arc and turn advance via WS, no page refresh; room.js, gatekeeper.js, role-select.js added to apps/epic/static; applets.js, game-kit.js, dashboard.js, wallet.js relocated to app-scoped static dirs; room.html: hex table, table-seat arcs, card-stack, inventory panel, role-card hand, WS scripts; _room.scss: room-shell flex layout, .table-hex polygon clip-path, .table-seat and .seat-card-arc, .card-stack eligible/ineligible states, .card flip animation, .inv-role-card stacked hand, .role-select-backdrop; gear btn and room menu always position: fixed; 375 tests, 0 skipped
2026-03-17 00:24:23 -04:00
|
|
|
self.room_id = self.scope["url_route"]["kwargs"]["room_id"]
|
|
|
|
|
self.group_name = f"room_{self.room_id}"
|
2026-03-16 18:44:06 -04:00
|
|
|
await self.channel_layer.group_add(self.group_name, self.channel_name)
|
2026-04-04 14:33:35 -04:00
|
|
|
|
|
|
|
|
self.cursor_group = None
|
|
|
|
|
user = self.scope.get("user")
|
|
|
|
|
if user and user.is_authenticated:
|
|
|
|
|
seat = await self._get_seat(user)
|
|
|
|
|
if seat:
|
|
|
|
|
if seat.role in LEVITY_ROLES:
|
|
|
|
|
self.cursor_group = f"cursors_{self.room_id}_levity"
|
|
|
|
|
elif seat.role in GRAVITY_ROLES:
|
|
|
|
|
self.cursor_group = f"cursors_{self.room_id}_gravity"
|
|
|
|
|
if self.cursor_group:
|
|
|
|
|
await self.channel_layer.group_add(self.cursor_group, self.channel_name)
|
|
|
|
|
|
2026-03-16 18:44:06 -04:00
|
|
|
await self.accept()
|
|
|
|
|
|
|
|
|
|
async def disconnect(self, close_code):
|
|
|
|
|
await self.channel_layer.group_discard(self.group_name, self.channel_name)
|
2026-04-04 14:33:35 -04:00
|
|
|
if self.cursor_group:
|
|
|
|
|
await self.channel_layer.group_discard(self.cursor_group, self.channel_name)
|
2026-03-16 18:44:06 -04:00
|
|
|
|
|
|
|
|
async def receive_json(self, content):
|
2026-04-04 14:33:35 -04:00
|
|
|
if content.get("type") == "cursor_move" and self.cursor_group:
|
|
|
|
|
await self.channel_layer.group_send(
|
|
|
|
|
self.cursor_group,
|
|
|
|
|
{"type": "cursor_move", "x": content.get("x"), "y": content.get("y")},
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
@database_sync_to_async
|
|
|
|
|
def _get_seat(self, user):
|
|
|
|
|
from apps.epic.models import TableSeat
|
|
|
|
|
return TableSeat.objects.filter(room_id=self.room_id, gamer=user).first()
|
2026-03-16 18:44:06 -04:00
|
|
|
|
|
|
|
|
async def gate_update(self, event):
|
|
|
|
|
await self.send_json(event)
|
Django Channels role-select sprint: turn_changed, roles_revealed, role_select_start consumer handlers; WS URL changed from room_slug to room_id UUID; TableSeat model - room, gamer, slot_number, role, role_revealed, seat_position fields; Room.table_status field with ROLE_SELECT, SIG_SELECT, IN_GAME choices; migration 0006_table_status_and_table_seat; pick_roles and select_role views; _role_select_context helper; _notify_turn_changed, _notify_roles_revealed, _notify_role_select_start notifiers; all gate-mutation views now call _notify_gate_update; ChannelsFunctionalTest base class with serve_static, screenshot, dump helpers; SQLite TEST NAME set to file path for ChannelsLiveServerTestCase; InMemoryChannelLayer added to test CHANNEL_LAYERS settings; FT 5 and FT 6 now passing - active seat arc and turn advance via WS, no page refresh; room.js, gatekeeper.js, role-select.js added to apps/epic/static; applets.js, game-kit.js, dashboard.js, wallet.js relocated to app-scoped static dirs; room.html: hex table, table-seat arcs, card-stack, inventory panel, role-card hand, WS scripts; _room.scss: room-shell flex layout, .table-hex polygon clip-path, .table-seat and .seat-card-arc, .card-stack eligible/ineligible states, .card flip animation, .inv-role-card stacked hand, .role-select-backdrop; gear btn and room menu always position: fixed; 375 tests, 0 skipped
2026-03-17 00:24:23 -04:00
|
|
|
|
|
|
|
|
async def role_select_start(self, event):
|
|
|
|
|
await self.send_json(event)
|
|
|
|
|
|
|
|
|
|
async def turn_changed(self, event):
|
|
|
|
|
await self.send_json(event)
|
|
|
|
|
|
2026-04-04 14:33:35 -04:00
|
|
|
async def all_roles_filled(self, event):
|
|
|
|
|
await self.send_json(event)
|
|
|
|
|
|
|
|
|
|
async def sig_select_started(self, event):
|
Django Channels role-select sprint: turn_changed, roles_revealed, role_select_start consumer handlers; WS URL changed from room_slug to room_id UUID; TableSeat model - room, gamer, slot_number, role, role_revealed, seat_position fields; Room.table_status field with ROLE_SELECT, SIG_SELECT, IN_GAME choices; migration 0006_table_status_and_table_seat; pick_roles and select_role views; _role_select_context helper; _notify_turn_changed, _notify_roles_revealed, _notify_role_select_start notifiers; all gate-mutation views now call _notify_gate_update; ChannelsFunctionalTest base class with serve_static, screenshot, dump helpers; SQLite TEST NAME set to file path for ChannelsLiveServerTestCase; InMemoryChannelLayer added to test CHANNEL_LAYERS settings; FT 5 and FT 6 now passing - active seat arc and turn advance via WS, no page refresh; room.js, gatekeeper.js, role-select.js added to apps/epic/static; applets.js, game-kit.js, dashboard.js, wallet.js relocated to app-scoped static dirs; room.html: hex table, table-seat arcs, card-stack, inventory panel, role-card hand, WS scripts; _room.scss: room-shell flex layout, .table-hex polygon clip-path, .table-seat and .seat-card-arc, .card-stack eligible/ineligible states, .card flip animation, .inv-role-card stacked hand, .role-select-backdrop; gear btn and room menu always position: fixed; 375 tests, 0 skipped
2026-03-17 00:24:23 -04:00
|
|
|
await self.send_json(event)
|
2026-03-25 11:03:53 -04:00
|
|
|
|
|
|
|
|
async def sig_selected(self, event):
|
|
|
|
|
await self.send_json(event)
|
2026-04-04 14:33:35 -04:00
|
|
|
|
|
|
|
|
async def cursor_move(self, event):
|
|
|
|
|
await self.send_json(event)
|