A tank game for the CCCB service point display.
Find a file
2024-04-16 18:28:09 +02:00
DisplayCommands socket fixes, fix tank jumping 2024-04-13 16:27:45 +02:00
tank-frontend another color for other tanks 2024-04-16 18:28:09 +02:00
TanksServer another color for other tanks 2024-04-16 18:28:09 +02:00
.dockerignore native aot in container 2024-04-10 22:03:36 +02:00
.editorconfig formatting 2024-04-13 14:08:51 +02:00
.gitignore more commands, change display communication to new lib 2024-04-12 16:10:38 +02:00
Dockerfile native aot in container 2024-04-10 22:03:36 +02:00
global.json initial project, implement binary format of display 2024-04-06 13:46:34 +02:00
Makefile dark background, dockerfile 2024-04-13 14:14:50 +02:00
README.md render current player in secondary color 2024-04-16 00:08:14 +02:00
TanksServer.sln wip new display module 2024-04-12 14:29:43 +02:00

CCCB-Tanks

Service point display

In CCCB, there is a big pixel matrix hanging on the wall. It is called "Airport Display" or "Service Point Display".

  • Resolution: 352x160=56,320 pixels
  • Pixels are grouped into 44x20=880 tiles (8x8=64 pixels each)
  • Smallest addressable unit: row of pixels inside of a tile (8 pixels = 1 byte)
  • The brightness can only be set per tile
  • Screen content can be changed using a simple UDP protocol
  • Between each row of tiles, there is a gap of around 4 pixels size. This gap changes the aspect ratio of the display.

Binary format

A UDP package sent to the display has a header size of 10 bytes. Each header value has a size of two bytes (unsigned 16 bit integer). Depending on the command, there can be a payload following the header.

The commands are implemented in DisplayCommands.

To change screen contents, these commands are the most relevant:

  1. Clear screen
    • command: 0x0002
    • (rest does not matter)
  2. Send CP437 data: render specified text into rectangular region
    • command: 0x0003
    • top left tile x
    • top left tile y
    • width in tiles
    • height in tiles
    • payload: (width in tiles * height in tiles) bytes
      • 1 byte = 1 character
      • each character is rendered into one tile (mono-spaced)
      • characters are encoded using code page 437
  3. Send bitmap window: set pixel states for a rectangular region
    • command: 0x0013
    • top left tile x
    • top left pixel y
    • width in tiles
    • height in pixels
    • payload: (width in tiles * height in pixels) bytes
      • network byte order
      • 1 bit = 1 pixel

There are other commands implemented as well, e.g. for changing the brightness.

Tanks game

  • By default, the backend also hosts the frontend

Backend

  • Stack: .NET / C# / ASP.NET / AOT-compiled
  • Both traditional JSON over HTTP APIs and real-time WebSocket communication
  • runs all game logic
  • sends image and text to the service point display
  • sends image to clients
  • currently, the game has a fixed tick and frame rate of 25/s
  • One frame is ~7KB, not including the text
  • maps can be loaded from png files containing black and white pixels or simple text files
  • some values (like tank speed) can be configured but are fixed at run time

Frontend

  • Stack: React / Vite / TypeScript / plain CSS
  • There is no server component dedicated to the frontend, everything is a single page after build
  • Shows map rendered on server by setting canvas image data
  • Sends user input to server
  • real time communication via WebSockets, HTTP for the REST

Binary formats

Controls WebSocket

  • Client sends 2 byte messages.
    • on or off: 0x01 or 0x02
    • input: Forward=0x01, Backward=0x02, Left=0x03, Right=0x04, Shoot=0x05
  • The server never sends any messages.

Observer screen WebSocket

  • same image for all clients
  • server sends same format as for the service point display
  • client responds with empty message to request the next frame

Player screen WebSocket

  • image is rendered per player
  • server sends same message as the observer WebSocket, but includes an additional 4 bits per set bit in the observer payload
    • first bit: belongs to current player
    • second bit: (reserved)
    • third and fourth bit: type of something
      • 00: wall
      • 01: tank
      • 10: bullet
      • 11: (reserved)
  • client responds with empty message to request the next frame