GithubHelp home page GithubHelp logo

maelstromeous / cards Goto Github PK

View Code? Open in Web Editor NEW
1.0 1.0 0.0 4.37 MB

A online card game replica of a popular card game (CAH) designed for small groups

JavaScript 7.01% SCSS 0.23% Vue 48.66% Shell 0.02% TypeScript 44.09%

cards's People

Contributors

maelstromeous avatar

Stargazers

 avatar

Watchers

 avatar  avatar  avatar

cards's Issues

Game Data

Proper thought needs to be applied to the game data / state. This needs to be a highly portable body of data in order to syncronise with clients quickly and efficently.

Data objects can be kept small by ensuring that card data (the text within the cards themeselves) is kept seperate from game data.

Full Game state

A lite version will be made available for the homepage game list. This is the full fat version.

 {
    "id": "magnum-detroit",
    "name": "Pigs DO fly!",
    "status": "playing",
    "locked": true, // Server still maintains authority on this. It will ignore the client when checking they can join the game.
    "validToJoin": true, // Denotes whether the game is accessible from the server itself to render for the client. Note the server has authority, it will ignore the client when joining the game.
    "roundCount": 1, // How many rounds this game has played

    "people": {  // Expanded array of player objects without their sessionIds
      "host": {
        "id": "UUID4",
        "name": "Maelstromeous",
        "score": 1,
        "ready": true // Denotes if the player has all cards loaded etc, reported from the client
        "chosenCard": "UUID4", // Player's card choice, if they have one yet
      },
      "players": [{
        "id": "UUID4",
        "name": "SomeAwesomeDude",
        "score": 2,
        "ready": true,
        "chosenCard": "UUID4",
      }],
      "spectators": [{}]
    },

    "options": {
      "gameType": "tsar", // Denotes game's type, quite important
      "scoreToWin": 5,
      "maxPlayers": 6, // Impose hard limit?
      "maxSpectators": 10, // Impose hard limit?
      "packs": [123, 1234, 12345] // Packs enabled for the game
      "chatEnabled": true,
      "roundTimer": 30, // Seconds to give players to make choices before random selection
      "idleTimer": 120 // Seconds before booting players from the session
    },

    "typeSpecificData": { // Made this mode specific as it depends on game type. Signifies who's the tsar.
      "tsar": {
        "currentTsar": "Player3 UUID",
        "previousTsars": [ // The updating of this has to be done carefully, otherwise a player might have tsar multiple times.
          "Player1 UUID",
          "Player2 UUID",
          "Player3 UUID"
        ],
        "nextTsar": "Player4 UUID"
      }
    },

    "cards": { // Holds state of cards in play, this'll be a bit tricky. Card text etc will be exposed via API calls
      "black": {
        "id": "UUID4"
      },
      "white": [{
        "player1 UUID": {
          "cards": ["UUID4", "UUID4"] // Array of 10 cards
        }
      }]
    },

    "serverSide": { // Details not to be exposed to the client to prevent cheating etc, could be done at API level rather than an object like this.
      "gamePassword": "foobar", // Stored as a hash obvs
      "bannedPlayers": [], // List of player IDs who are banned from the game
      "cards": {
        "played": { // List of card IDs already played so the server doesn't give players the same cards
          "white": ["UUID4"],
          "black": ["UUID4"]
        }
      }
    },
  }

Lite Game Data

Bare minimum needed to render the homepage, this will be requested via an API call with a certain flag.

{
          id: 'shark-tale',
          name: 'A medium game',
          status: 'lobby',
          locked: true,
          validToJoin: true,
          people: {
            host: {
              name: "Warcore"
            },
            players: [
              {name: "SomeAwesomeDude"},
              {name: "SomeAnnoyingDude"},
              {name: "A lady in red"},
              {name: "A dude in blue"},
              {name: "A gentlemen in blue"},
            ]
          },
          options: {
            pointsToWin: 5,
            maxPlayers: 7,
          },
          winConditions: {
            type: 'tsar',
          }
},

Player Data

{
    "id": "UUID4",
    "name": "Maelstromeous",
    "sessionId": "somerandomcookiestring",
}

Card Pack data

{
    "id": 123,
    "name": "PAX Prime 2014",
    "official": true
}

White card data

{
    "id": "UUID4",
    "type": "white",
    "text": "ADVENTURE!",
    "pack": 123
},

Black card data

Note here there's an extra pick attribute.

{
    "id": "UUID4",
    "type": "black",
    "text": "Aww babe, your burps smell like _!",
    "pick": 1, // Max 3?
    "pack": 123
}

Functionality design

Design / outline of the functionality of the project, what the experience is going to be etc.

Purpose

The purpose of the project is to provide a better online Cards Against Humanity experience. There are a few websites that do this, notably https://pretendyoure.xyz/zy/, which has a number of issues I intend to correct:

  1. It's design is visually awful 🤢
  2. The implementation of card moves is very slow and clunky. It uses polling to pick up new cards being picked by other players and decisions by the Card Tsar. This creates a massive amount of network traffic. Often Card Tsar selections are missed and it's not clear who earned a point with what card.
  3. The site depends on using servers, of which they are always full. There should be no need for every single communication between players to go through a server, a P2P connection via webRTC should do this trick. A server may be needed to host details to prevent the game being lost, such as current game state.

Requirements

Visual design

Firstly, the design of the site has to be visually appealing in order to achieve popularity. The site should also be themeable, should the user want to use white mode or dark mode etc. This could be easily achieved with a CSS framework and proper application of sensible design.

Thought has to be put into mobile. It's no longer out of the realms of reality that card games are being played on phones over VoIP calls e.g. Discord etc for fun.

Game design

So the game itself will heavily match Cards Against Humanity, which is basically the following premise:

  1. Each player gets a set of white cards. They need to match their white cards to the black card of the round, in the funniest / darkest way possible.
  2. Once all players have made their moves, the round continues and moves onto the Card Tsar, who must then pick the white card(s) that they think is the most funny / fucked up / dark.
  3. Once the card Tsar has chosen their favourite, the person who played the chosen white card gains a point.
  4. The round then moves on, with a new card Tsar chosen.
  5. The game needs to have programmable limits, e.g. first to 5 points wins, etc.

There are various card packs out there. For the Alpha, I'll be choosing the classic pack, then implement the other packs at a later date. Thankfully, there is a website with the entire set of CAH packs available as a JSON download: https://crhallberg.com/cah/

Experience

To address the issues of say pretendyoure.xyzzy, the experience needs to be butter smooth. Namely the specifics:

  • Cards played by other players should show up as played instantly (real time)
  • The choice of your cards needs to be user friendly. If you have many cards, they need to be displayed correctly, especially on mobile
  • The spread of cards to choose by the Card Tsar need to be clear
  • Any double cards need to be clearly grouped together as well
  • It needs to be clear who is winning / current scores
  • Sharing of the game needs to be easy (probably via a random link to the game, easiest thing to do)
  • Hotjoin?
  • Game needs to be lockable to certain people (via a password probably)

As a host setting up the game

  • Game name (attempt to filter out rude names, but perhaps that should be part of the fun)
  • Card pack choice
  • Enable / Disable chat
  • Kick / Ban players from the game
  • Score limit
  • Player limit
  • Spectator limit (oof)
  • Idle timer

As a player

  • Chat (believe it or not people use this)
  • Clear selection of their cards
  • Clear visualisation of the black card
  • Clearly see the choice of the card Tsar
  • Points / current leaders
  • Current card Tsar
  • Game status (e.g. connected, rejoin)

Card data ingest

In order to properly seperate cards, each card contained within the JSON Against Humanity DB (https://crhallberg.com/cah/) needs to be ingested into a NoSQL database, in the format as determined by #19.

This will require a mechanism to ingest the data.

Full file available in root, cah-cards.json.

Cheater prevention

Need to think about how to prevent sending invalid data to the game state with cards that don't exist etc. Perhaps a server centric model is warrented with changes to game state being pushed to users rather than polled from users.

Server should be authority - if a card that has been played isn't recognised by the server, it should be chucked, and a potential warning in the chat displayed.

Chat lines

Create a database of quirky chat lines, such as:

  • Round 1: FIGHT
  • Maelstromeous is the lord of the cards!
  • Maelstromeous is now god. Fear him.
  • Maelstromeous has played their hand!
  • Maelstromeous has shown their true colours!
  • Maelstromeous has submitted their opinion. It’ll be queried, lost, found, subjected to public enquiry, lost again and finally buried in soft peat for 3 months and recycled as firelighters.

Stack setup

Setting up of the stack required to run the project.

This is likely going to be run on K8s for hosting simplicity for myself, plus it'll be nice to get back into K8s again.

Game variations

Would be nice to add game variations, e.g.:

  • Winner by popular vote rather than Card Tsar's choice
  • Purely random winner. Let the chaos ensue.
  • Anarchy white cards: Random number of white cards to be chosen

Tests

I believe this should be an opportunity to finally get into automated tests.

Netcode

So for the connection, Socket.io(Websocket/Http) or a Websocket is used. This means connections use TCP, meaning packet drop is not an issue however this might add some lag. More lag can occur due to the single connection with bidirectional chatter.

Connections will look like the following. The first part is the heartbeats, the client(once connected) will start sending these at a fixed interval, and the server will respond with an acknowledgment of it. Failure to send a heartbeat or receive an acknowledgment means the connection has gone bad and needs to be terminated/disconnected. The server has to account for network lag. Socket.io has this functionality by default, and this information is here for the sake of completion.

The next step is identification. The client before connecting should have already created an identification token using an Http endpoint. The identification is used to start a session. The client will receive a session token in return. Optional a user can send a session id with an event number. These last ones can be used to resume a connection/session. When identified any messages that are sent to the client will have an event counter to keep track of received messages in case of a reconnect. This is only there to continue where a client left on resuming. Note that the server only keeps these events for a certain amount of time, meaning resuming is not always possible.

A new session, will receive information on all games that are public/joinable. From there it can send a command to join a game.

When joining a game. It will receive the game state from the perspective of the client. This includes public elements of the game(e.g. the black card, list of submitted white cards with or without content, player stats, and any additional metadata) and the unique player elements(e.g. list of white cards, and any additional metadata). The information should be sent in such a way that no information is exposed that can be used to cheat(e.g. the content of a card when face down, links between players and cards).

From here the client will receive updates of the game states, and these messages will be used to patch the game state. This will reduce the amount of traffic and be a good fit for Vue, but will however complicate the code as the patch/merge mechanism needs to be solid to avoid incorrect states. Handling the correct order of events will be very important.

The client will have depending on the metadata/game state the ability to send certain commands(e.g. to submit cards, choose a winner). These are done through means of the update messages similar to those received from the server. This means that a permission system needs to be in place on the server to validate the commands and make sure that they are allowed from the perspective of the server. However if possible network lag needs to be a consideration. This can be done by letting the client know in some way or form that it cannot send a command before actually invalidating them(e.g. round state goes from active, to finishing, to ended).

I also would recommend separating the game and chat. Mainly as chat has other considerations than the game in terms of netcode. Also, some hard limits need to be in place when it comes to the game so the games will stay playable. Limits can be static or a more dynamic system can be in place where newer games can be moved to another server. Also, static limits can be loosely defined at first and be tightened later on.

Site template

Design of the site template, overall themes, general feel of the product.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.