Git Product home page Git Product logo

snake-server's Introduction

Snake-Server

Build Status GitHub release Go Report Card Docker Pulls

Snake-Server is a server for multiplayer snake game. You can play with your friends! The special feature is that you can eat small snakes!

Take a look at a working instance here - https://snakeonline.xyz

Game demo

Usage

  1. docker run --rm -p 8080:8080 ivan1993spb/snake-server --enable-web
  2. Open in the browser http://localhost:8080/.

How to play?

  • You control a snake
  • You need to grow the biggest snake
  • You can eat apples, mice, watermelons, small and dead snakes
  • If the snake dies, you will have to start over

Installation

  • Go get

    go get github.com/ivan1993spb/snake-server@latest
    snake-server -h
    
  • Docker

    Check out the repo.

    docker pull ivan1993spb/snake-server
    
    docker run --rm -p 8080:8080 ivan1993spb/snake-server --enable-web
    
    docker run --rm ivan1993spb/snake-server -h
  • Download and install the binary

    Take a look at the release page

    Curl:

    • Set VERSION, PLATFORM and ARCHITECTURE:
      VERSION=v4.3.0
      # darwin or linux or windows
      PLATFORM=linux
      # amd64 or 386
      ARCHITECTURE=amd64
    • Download and install the binary to /usr/local/bin/:
      curl -sL "https://github.com/ivan1993spb/snake-server/releases/download/${VERSION}/snake-server-${VERSION}-${PLATFORM}-${ARCHITECTURE}.tar.gz" |\
        tar xvz -C /usr/local/bin/
  • Deploy the server using the ansible playbook

    https://github.com/ivan1993spb/snake-ansible.

CLI options

Use snake-server -h for more information.

Options:

  • --address - string - sets an address to listen and serve (default: :8080). For example: :8080, localhost:7070
  • --conns-limit - integer - to limit the number of opened web-socket connections (default: 1000)
  • --groups-limit - integer - to limit the number of games for a server instance (default: 100)
  • --enable-web - bool - to enable the embedded web client (default: false)
  • --enable-broadcast - bool - to enable the broadcasting API method (default: false)
  • --forbid-cors - bool - to forbid cross-origin resource sharing (default: false)
  • --log-json - bool - to enable JSON log output format (default: false)
  • --log-level - string - to set the log level: panic, fatal, error, warning (warn), info or debug (default: info)
  • --seed - integer - to specify a random seed (default: the number of nanoseconds elapsed since January 1, 1970 UTC)
  • --sentry-enable - bool - to enable sending logs to sentry (default: false)
  • --sentry-dsn - string - sentry's DSN (default: ""). For example: https://[email protected]/44
  • --tls-cert - string - to specify a path to a certificate file
  • --tls-enable - bool - to enable TLS
  • --tls-key - string - to specify a path to a key file
  • --debug - bool - to enable profiling routes

Clients

There is an embedded JavaScript web client compiled into the server. You can enable it with CLI flag --enable-web.

You are always welcome to create your own client!

You can find examples here:

See documentation docs/api.md and docs/websocket.md.

REST API specification: openapi.yaml.

License

See LICENSE.

snake-server's People

Contributors

dependabot[bot] avatar ivan1993spb avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

snake-server's Issues

Create a lightweight dot serialization

Create a lightweight dot serialization.

Use bit operations to serialize a dot instead of a representation of a dot as an array json.

[x,y] // now
zzz // want

MarshalJSON:

uint16(d.X)<<8 | uint16(d.Y)

Make a delay for sending broadcast messages in the game websocket

There is a broadcast message type in websocket connection to send every player in a game a message.

Now it is possible to send a lot of small broadcasts to the game without any delay and so make a lot of spam and ddos the game server.

The task is to make a delay to prevent such a ddos attack via game websocket.
And of cause, create a cli flag to pass a value for the delay.

Rename PlaygroundCMap's files

Rename PlaygroundCMap's files:

  • playground/playground.go into playground/playground_cmap.go
  • playground/playground_test.go into playground/playground_cmap_test.go

Refactor ExperimentalPlayground

ExperimentalPlayground is designed to receive *engine.Object and pass it through to engine.Map. *engine.Object contains an actual game object. Therefore, there is a necessity to manage *engine.Object somewhere on the layers above ExperimentalPlayground which turned out to be a quite complicated and awkward situation.

Rewrite ExperimentalPlayground to manage *engine.Object inside of ExperimentalPlayground:

  1. Rename *engine.Object to *engine.Container with regards to the purpose it serves
  2. Define engine.Object interface as an empty interface interface{}
  3. Make all methods of ExperimentalPlayground receive actual game objects engine.Object and wrap them into engine.Container before passing to engine.Map
  4. Store the mapping of game objects and their containers in ExperimentalPlayground: map[engine.Object]*engine.Container
  5. Add sync.RWMutex to regulate access to the map
  6. Rewrite tests for ExperimentalPlayground and add some if necessary
  7. Conduct a benchmark test to estimate the gains and loses of the new solution
  8. Add comments to ExperimentalPlayground
  9. Accept empty locations as valid when registering objects

Create a lightweight identifiers for objects

Now there are object identification using GUID strings. Identifiers are encoded to JSON as 36 byte
strings but perhaps identifiers could be more lightweight.

Use instead GUID identifiers some another way to identify objects.

For example integers could be more convenient.

// 8 byte identifier
objectID64 := rand.Int63()
// 4 byte identifier
objectID32 := rand.Int31()

Or short (<=10 bytes) strings could be used. But it would be better use integers because:

objectIDstr = "id" // 16 bit + string

Add error handler to WS upgrader

Now WS upgrader uses error handler by default. In case of failure of upgrading of a connection, default error handler will write a status code and log error message and then HTTP handler will try to rewrite status and write new error message. It is necessary to redeclare error handler for upgrader in order to aviod such a messy error processing.

Update Go version up to 1.14

Update Go version from 1.12 up to 1.14

Also

  • Delete unnecessary -mod vendor
  • Delete setting of var GO111MODULE=1

Refactor and redeclare HTTP handlers and server

Now the server object and routes are initialized in the main function and handlers are defined in the handlers module, which also contains some general business logic.

This scheme is good if there is a small server. However, the Snake-Server has become bigger and now such a scheme of the project is messy.

Refactor and redeclare HTTP handlers and server as following structure:

core/                                                        business logic

(may be)

server/core                                               business logic

server/
server/http/
server/http/utils/                                          WriteResponseJSON here
server/http/handlers/
server/http/handlers/{handler_name}
server/http/middlewares/

Prometheus metrics handler is going to be started on a special separated port which will be only for metrics and controlled by a CLI flag.

The HTTP client's handler is going to be moved from the client/ module to server/http/handlers/.

Find a new http framework which will be better then the current.

Helper:

  • WriteResponseJSON(w http.ResponseWriter, statusCode int, response json.Marshaler) error
  • bytes writer?

Migrating to Go Modules

Migrating to Go Modules:

  • Rewrite Dockerfile, Makefile, .travis.yml: create flags if necessary
  • Ensure that all the dependencies have been committed correclty

Create mouse object

Create mouse object.

Mouse have got one dot and a direction. It must walk around the game map by the random manner.

Mouse would be a food for snakes.

Some example.

{
  "type": "mouse",
  "id": 22,
  "dot": [3, 2],
  "dir": "north"
}

Add tests for DotMask

Tests:

  • Add test case for DotMask.Copy when some rows of the table are longer than limit
  • Add test for DotMask.TurnRandom with predefined seeds

Panic: send on closed channel

panic: send on closed channel

goroutine 103 [running]:
github.com/ivan1993spb/snake-server/world.(*World).event(0xc420055180, 0x7b1402, 0x7b1420, 0xc4201e0930)
        /go/src/github.com/ivan1993spb/snake-server/world/world.go:44 +0x103
github.com/ivan1993spb/snake-server/world.(*World).DeleteObject(0xc420055180, 0x7b1420, 0xc4201e0930, 0xc4201e5280, 0x3, 0x3, 0xc42019d540)
        /go/src/github.com/ivan1993spb/snake-server/world/world.go:276 +0xd5
github.com/ivan1993spb/snake-server/objects/corpse.(*Corpse).run(0xc4201e0930)
        /go/src/github.com/ivan1993spb/snake-server/objects/corpse/corpse.go:72 +0x195
created by github.com/ivan1993spb/snake-server/objects/corpse.NewCorpse
        /go/src/github.com/ivan1993spb/snake-server/objects/corpse/corpse.go:37 +0x12c

Tasks to be implemented or thought through

Tasks to be implemented or thought

Ideas

  • Create a core layer to invoke methods from API handlers.
  • Create handler with server limits.
  • Create a queue of the commands to the snake.
    Create queue in Snake object:
    commandQueue chan snake.Command
    Collect and implement commands:
    ["north", "east", "north", "north", "north", "east"]
  • Create guarded API with a secret kay (token):
    For API methods:
    • Broadcast
    • Objects
  • Create team fighting mode
  • Switch handlers from net/http server to fasthttp:
  • Setup cache headers for static files: write or find a negroni middleware for caching
  • Create length to snake JSON structure to give to clients opportunity to distinguish dangerous snakes and weak
  • Game sessions to allow reconnections

Global TODOs

  • Create more tests
  • Create more comments

To make tasks

  • Create CLI flag to set up max limit value of gamers in a game.
  • Create log message with list of addresses to listen and serve.
  • Create Prometheus metrics for channels lengths
  • Create firing and listening of game events
    • an apple eating
    • a snake killing
    • a death
    • watermelon eating

Add config module

Add a module to configurate the server.

The module uses YAML configs and flags.

Flags have bigger priority than YAML directives.

YAML config is stored in a file. The path to the file is defined by an environment variable.

Invalid memory allocation in Playground

Invalid memory allocation in playground.Playground

  • In func UpdateObject keysToRemove allocate not len but cap
  • In func UpdateObjectAvailableDots keysToRemove allocate not len but cap

Create cache for game objects method

Create a cache N seconds for the method API: GET /api/games/{id}/objects.

Use headers to notice a client about caching.

Create a field for time stamp to be returned in result json object

Example:

{
"objects":[],
"time": ...
}

Change the hunting rule

Now a snake can eat another snake if the first snake has eaten at least one apple and the second snake hasn't eaten any food.
It would be better if big long snakes could eat any snake smaller then them but not only the smallest just started snakes.
It seems to be right to use this formula:

can_I_eat = my_len >= a_snake_len^2

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.