Code Monkey home page Code Monkey logo

viral-spiral-backend's Introduction

viral-spiral-backend

All command examples are from the repo root

Running locally

Prerequisites

  • Install postgresql locally
  • Create a database called "tattleviralspiral"
    • You can do this by running psql -U postgres and then create databaset tattleviralspiral
  • Install python3 and create a virtualenv using pipenv
pipenv shell
  • Activate the environment
pipenv shell
source ./activate_env.sh
  • Install dependencies
pipenv sync
  • Initialize the db
python setup.py

Run the server

  • Run the startup script
bash start.sh
  • Make sure you see no errors on the console

Connect the clients

  • Open your browser to localhost:5000
  • Fill up the create_game form. You should see "created game " in the console tab
  • For each player, you'll need a separate tab with localhost:5000 open. You can reuse this tab for the first player
  • For each player, join the game
  • Rest of it should be intuitive.

Communication with the server

All communication happens with sockets, using the socket.io framework. The flow is as follows:

We don't use any namespaces as of now. CORS might not be enabled on the server yet - so if you can use some broser plugin to disable cors (not tested yet) that will be great. I will look into enabling cors. The socket.io path is the default path (basically for initialization, I didn't provide any path. You can check out main_loop/templates/index.html for reference).

Actions (outgoing events):

  1. Create a game (needs to be done only once. All game names are unique):
    • Event name: "create_game"
    • Example - main_loop/index.html:95
  2. Join a game (needs to be done every time you re-load the socket):
    • Once you join a game, your client's session ID is stored in the backend
    • So if this client ID changes (might happen on a page refresh), you need to join the game again
    • Event name: "join_game"
    • Example: main_loop/index.html:143
  3. Player action - this event is triggered whenever the player performs a card action
    • Action can be to keep a card or pass a card (more details in the examples)
    • TODO add more actions like initiate cancel player, vote cancel player, make fake news, etc -- actions for each of the special powers
      • Viral spiral action is a part of pass card
    • All these actions will be a part of this same event as of now.
    • Example: main_loop/index.html:220
      • To see the different types of actions, you can analyse the data variable in that command - and see how it changes when you fill out a form and select perform action
  4. About game - returns information about this game
    • To be used to get the game state
    • Example: main_loop/index.html:311
  5. Ping
    • Sample request that sends "my_ping" and the server returns "my_pong". Can be used to check the connection to the server
  6. get queued card - get the card queued for the current player
    • Not being used in the frontend as of now since the play_card action gives this information
    • Python code: main_loop/websocket.py:265

Events (incoming events):

  1. "connect" - Triggered on successful connection. main_loop/index.html:258
  2. "play_card" - Reminder to play the card. main_loop/index.html:266
  3. "about": Response to the "about game" action: main_loop/index.html:288
  4. "whos_turn" - Triggered whenever a round starts - returns the data about who's turn it is. main_loop/index.html:295
  5. "endgame" - Triggered when the game ends. main_loop/index.html:301
  6. "text_response" - This is a generic event triggered. All data coming here goes into the console tab of the demo UI. main_loop/index.html:261
    • TODO create better specific events instead of using text_response
    • Following server events trigger this "text_response" event:
      • heartbeat every 10 seconds
      • Response to a create_game request
      • Response to a load_game request -- this action is not being used in the frontend. If you trigger a join_game it will automatically load the game.
      • Response to a player_action request
      • Response to a disconnect request
      • Response to a connect request
      • When a round finishes
      • Response to joining a game

Running Using Docker

docker-compose up

docker ps //to confirm if the services are running
docker exec -it api /bin/sh
pipenv shell
python setup.py // one time thing to run database database migrations
./start.sh

If you are on windows and are running into the source: not found error while running the ./start.sh command, then instead of it try running python main_loop/websocket.py

Debugging

These instructions are useful when you are running the server inside a docker container and using VS code as your IDE. We'll use debugpy as the debugger.

  1. Run pip install debugpy inside your container.
  2. Run pipenv shell
  3. Run python -m debugpy --listen 0.0.0.0:5678 --wait-for-client main_loop/websocket.py
  4. Open VS code and go to the Run and Debug screen. Click on the play button and choose "debugpy" to connect to the server.

You should be able to set breakpoints now. Configuration for connecting to the remote host can be seen in .vscode/launch.json

Testing

python -m unittest -v

todo : add commands to run individual test cases

Glossary

  • Round : A card's lifecyle, starts from the card being drawn and continues till the card has been passed to every player or has been kept or discarded by a player.
  • Full Round : A turn cycle, includes every player finishing their round once

Special Powers

Viral Spiral

Description

User flows

How its implemented

Testing the Feature

viral-spiral-backend's People

Contributors

bhargav-dave avatar dennyabrain avatar elgohr avatar rishavt avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

viral-spiral-backend's Issues

Add fact checking / passing restrictions in the backend

If card affinity == player affinity, force pass
if card affinity == player affinity, no fact check
same for bias

Currently (in the prototype) these need to be implemented by the frontend. We will need to discuss whether backend limitiation adds to the user experience or not - and accordingly prioritize whether to keep this as a frontend feature or add to the backend.

(Context on the above comment - if we want to show reasons for force pass, for example if we want to tell the player that they need to pass the card because it matches with their affinity, it's better to (also) have this decision making logic - of whether to pass or keep - in the frontend. In that case, the backend restriction just becomes a security feature - which we can do after the initial demo). @dennyabrain let's discuss this sometime.

How to address the database host

I am referring to this
host="127.0.0.1"

looks like it needs to be this string for it to work for you and "db" for it to work for my docker setup. lets resolve it. probably by using an environment variable coz that would be easiest and also make it work in the cloud setup.

Investigate Scalability

Right now the game runs on one machine and the state is retained in memory and database. If we had to consider a userbase of 1000 simultaneous game sessions, what would scaling this up look like.

Performance benchmarking

  • Single user performance
  • Multiple user performance

  • Automated tests for APIs
  • Manual testing with throttled APIs
    • If we expect a scale of 100 users, and with 100 users the 90 percentile API load time is 2 seconds, then we throttle the APIs to take at least 2 seconds and do manual testing in the team
    • Get feedback on how playable the game is with this manual testing and if we need to improve the performance right away.

Viral Spiral Power

Feature Description :

if a user receives a card and they have the "viral spiral" power, they can choose to send any of the cards they own to multiple players in their turn.

Expected Outcome :

  1. User receives a card and see a button "Viral Spiral"
  2. User clicks on the button and a popup appears
  3. In the popup, user should be able to see the cards they own and select one of them AND select the player(s) they want to send the cards to

There are 2 scenarios now :

  1. user selects the card that they had just received and sends it to players
    in this case the card disappears from their screen and it pops up on other player's screens.

  2. user selects the card different from the one they received and sends it to players
    in this case the "viral spiral" popup disappears but the card they just received is still on their screen. It should only have the "keep" and "discard" options. They can't use the "pass to X" feature anymore.
    The card they used "viral spiral" with should show up on other player's screen.

Add player authentication

Player password along with a game password
this can be simply stored in JS - no need to ask the user

  • To prevent browsers of multiple players from cross-performing actions

Socket support

  • every event should send out a message in the socket
    • Storyline events (world events) go out to everyone in the game
    • Player events go out to that single player
  • Every action should be an incoming event

"Mark As Fake" power not working as expected

Scenario A :

If you draw a fake card and you mark it as fake

  1. the UI should show a "fake" stamp
  2. the card gets discarded automatically

Scenario B :

If Player A sends a fake news card to player B and player B marks it as fake, player A loses a point.

  1. player B sees a "fake" stamp
  2. the card gets discarded automatically

Turn into fake news Power

{
"original_request": {
"message": "player_action",
"args": [
{
"game": "MitaliTestingRoom_02",
"player": "Denny",
"action": "action_fake_news",
"kwargs": {
"card_instance_id": "e0557c7472934089b98d9120fe0b26e5",
"fake_card_id": "a47423f8ef244fd7ae6ec0663491e7a3"
}
}
]
},
"error": "Fake card not found a47423f8ef244fd7ae6ec0663491e7a3\nTraceback (most recent call last):\n File "/root/.local/share/virtualenvs/app-4PlAip0Q/lib/python3.9/site-packages/flask_socketio/init.py", line 826, in _handle_event\n ret = handler(*args)\n File "/app/main_loop/websocket.py", line 431, in player_action\n response = runner.perform_action(player_name, action, **kwargs)\n File "/app/main_loop/websocket.py", line 196, in perform_action\n return player.perform_action(action, **kwargs)\n File "/app/models/player.py", line 419, in perform_action\n return getattr(self, action)(**kwargs)\n File "/app/models/player.py", line 303, in action_fake_news\n raise NotFound(f"Fake card not found {fake_card_id}")\nexceptions.NotFound: Fake card not found a47423f8ef244fd7ae6ec0663491e7a3"
}

Investigate "create game" time

I've started noticing a very noticeable delay in receiving acknowledgement from the server after emitting a "create_game" event. Doesn't feel right for what i think it takes to create a room.

Alternate Game Creation Workflow

To create a game a user should only have to specify how many players will be joining the game. The person creating the game does not need to remember or type usernames of other players. So in the create game userflow, we let the user specify the password for the room and how many players will join the game. Once the game room is created and a link generated for it, other players can join this room by entering the password and their preferred username for the game.

let viral spiral share older cards

Subtasks:

  • Write code to get all previously held cards - and send this to the frontend
  • Allow accepting which card to share - in the share card action
    • This might already be happening, just double check

events from backend to frontend

  1. game status changes
  2. game action events
    3. player action events
    4. room action events
    5. for example if someone gets a viral spiral power, broadcast it to them as well as the room
  3. improve UX events - like someone disconnecting, joining, leaving, etc etc - to be sent to the room

Splash Screen to announce Game End

Feedback Session :

Adhiraj Writes some text for predefined end states
eg player wins but at what cost to the world
Denny will use the about_game payload to summarize the game
give players a title

Improve game sharing usability

Currently we support joining a room by entering the game name and its password. I think we can reduce the friction here by enabling support for joining the game via urls. so if lets say every room had a url like http://viral-spiral.itch.io/room?id=asdfasdf-asdfasdf-asdf, when a player clicks on it, they are only asked for the password to join this game (and optionally their own username too but thats not a constraint to join this room)

This might overlap with issues of whether we identify games by their room name or their uuid. for instance if we create a room by the name 'best-room' which has a id in the database like asdfasdf-asdfafd-asdfa, should we make the urls be https://viralspiral.itch.io/room?name=best-room or https://viralspiral.itch.io/room?name=asdfasdf-asdfafd-asdfa

Authenticate all socket io events using decorator

check message["password"] against the password for the game runner

Maybe create a game runner utility function called authenticate() - and call that in the decorator

  • You can set an additional kwarg in the decorator before passing it on to the function - called "game_runner"
  • This way you don't need to load the game runner everytime

Create another decorator to verify that a player has joined a game (their saved client_id is correct)

play_card event seems to be received after the player has taken action

When playing the game, if user A receives play_card message and emits the action_pass_card, after receiving the acknowledgement for that event, the user receives 1 more message of play_card type.
Given that this user only receives 1 more message of play_card, I am guessing this is a race condition type thing where the server acknowledges the pass_card action and THEN changes the logic for who should be receiving the play_card event.

Does it make sense on why something like this should happen?

Add storyline related things

  • Card generator logic - in progress
  • Create a storyline DB object(s)
    • This stores the current state of the storyline
    • This will have events
      • each card pass will be an event
      • Will display some information and/or end the game on each event
      • Might update the game rules on each event
        • Figure out if/how

Currently for dev testing we will use a simple story line -

  1. Card generation logic is random
  2. If single persons score == 15 they win
  3. If world bias == 15 game ends

Improve the Room Creation Experience

In the game, when the user clicks the "Create Room" button, it takes a while for the room to be created. I think around 5,6 seconds. From what i have learnt from @RishavT, this is something that can be optimized with some effort.

Till we get to that point, I think we can make this less confusing for the user by providing some visual feedback of the game creation process.
Right now all they see is a "Creating Game" banner at the top.
We could add some motion (progress bar or spinning bar), or providing slightly nerdy "behind the scenes" messages like
"Creating Room", "Initializing Players", "Choosing Cards", "Builing Encyclopedia".

Change the Room Creation Flow

We want to reduce the friction in creating and joining rooms.

Adhiraj suggested this flow :

  1. Player visits viralspiral.net
  2. Player enters the player count and clicks on "Create Room"
  3. Player gets a link that they can share with others.
  4. Player can click on the "join room" button next to the link to join the room themself

When the other Players click on the link, they just have to enter their chosen name.

As and when players are joining the room, the other players see a notification that "Player X has joined the room"

When everyone has joined the room, they see a notification that "The Game has started"

At this point the first card shows on the current player's screen.

Doubts :

While it might be acceptable to use just a randomly generated ID as the identifier for a room during the playtest sessions, how abuse proof is that in a production setting. Adhiraj mentioned that a lot of online multiplayer games are done this way. How do they prevent abuse? are they just banking on the fact that no one is trying to hack their way through to other people's room?
I think that generating human friendly room names and short numeric codes as password might be safer? so for instance i could say join the "happy panda" room with 5392 as the code. Should be less abuse prone?

Research on frontend

  • Finalize frontend tech
    • Network interaction tech - websockets?
    • State management and frontend logic tech - react?
    • UI rendering tech - canvas based something?

@dennyabrain assigning this to you since you have more experience on this front although I will also help out. We can also delay this until we hire someone - although I would like to finalize at least the first two aspects asap.

Depends on: at least 1 final UI design (for the UI rendering tech). The other two can be finalised before that.

Some requirements (from a tech PoV) that I can think of):

  1. Sync of the saved state with the backend asynchronously
  2. Ability to load the saved state from the backend (or re-create the state using information from the backend APIs) in case of a disconnect

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.