Giter Site home page Giter Site logo

roguelike's Introduction

Caverns & Kubernetes

A Roguelike microservices ecosystem

This is the prototype for a distributed multiplayer dungeon crawl game, with a dual purpose:

  • Illustrate architecture and design patterns for building microservice-based solutions hosted in kubernetes
  • Be a fun and challenging game!

To understand what RogueLike is about

Setup

npm install to get all the code dependencies.

then compile the code:

npm run build

Running the server

The main server is started with npm start and this will fire up a server that you can then point a browser to and start playing.

(You may have to let "node" accept incoming network connections)

However, all monsters in the game are run as separate microservices. You need to set the ENV variable export ROLE="MONSTERS" before running npm start in another shell.

You can start various parts of the service using the following values for ROLE:

  • MONSTERS starts just the monster bots
  • FRONTEND starts just the web frontend
  • BACKEND starts just the connection server and cave
  • SERVER starts the frontend and backend

If no value is set for ROLE then the default behaviour is to start everything.

DEBUGGING

You can set the ENV variable DEBUG to true to switch on verbose logging.

Connect to the server from a browser

If running the server locally, point your browser here: http://127.0.0.1:3000

Keys and what they do

  • Cursor left, right, up and down : obvious movement around the current map level.
  • i : show Inventory
  • d : drop an item
  • e : eat something from your inventory
  • x : examine an item from your inventory
  • w : wear an item from your inventory
  • W : wield an item from your inventory
  • , : pick up an item
  • > : move down stairs
  • < : move up stairs
  • ? : help
  • ; : look around (using cursor keys)

Coding

The architecture aims to enable easy extensibility of the game with new features.

src/
├── client/           # client used in web frontend and bots
├── common/           # common abstractions used in front and backend
├── frontend/         # Web frontend for players
├── monsters/         # Bot code for each type of monster
├── routes/           # REST API code
├── server/           # Code for the backend server
│   ├── config/       # home for configuration of server
│   │   └── maps/     # home for map configuration files
│   ├── entities/     # Code for each type of player or monster entity
│   ├── generators/   # Code for different types of cave generation
│   └── items/        # Code for each type of item - weapons, armour, food, etc.
└── start.sh          # Entry point for microservice

Running unit tests

When coding, use these npm commands to run unit tests against the source code:

  • npm test:watch - to continuously watch for source file changes, and re-test when they do change
  • npm test:coverage - see what your code coverage is
  • npm test - a one-off run through the unit tests

Server API resources

Overall Component Architecture

Component Diagram

Class diagrams

Class Diagram

roguelike's People

Contributors

chrisesharp avatar techcobweb avatar dependabot[bot] avatar bestbeforetoday avatar katheris avatar markwoolley avatar mpburg avatar

Watchers

James Cloos avatar  avatar  avatar  avatar

roguelike's Issues

A dead bot can pick up it's own body !

This made me chuckle. Not having implemented detection of my own death, I slowed the bot movement down so I could beat it up with a manually-controlled player.

Server                                Bot
-------->DEAD---------> ignore
-------->Items update--> there is now a body object where I'm standing
…time passes…
       <----------------- pick up the body, as it's where I am.
-------->items update---> there is no body there now. (as I have picked it up successfully)

Some dungeons have rooms with items inside, but no way to get into that room.

eg:

######X   ##       ##########     ######
#####..            #####################
#### <             ##################  #
#####              ##########  #####  * 
######              ########    ###     
#########             #####     ###    #
##########             ####    ####   ##
#########             ####<    ####   ##
#######              #####    ####    ##
###                 ######   #####    ##
##                  ###############  ###
##                 #####################
##                #####< ###############

The '*' on the right is the item in the unreachable room.
X is the bot.

So it looks like the map generation has a bug gin somewhere, as this shouldn't happen.

I note there is no wall on the far right, so maybe it intended to put stairs there, but the width is out by 1 or something ?

The server reset shouldn't be on a get, but on a PUT ?

Resetting the server using an HTTP GET command seems wrong to me.
I know it's convenient, but changing the server state violates the read-only nature by adding a side-effect.

If this gets changed, then the README.md may also need changing, or wherever the current HTTP API is documented/defined.

Wield an object, and it is marked as (wielding) forever.

Pick up a dagger, look in your inventory
Dagger
Wield the dagger, look in your inventory
Dagger (wielding)
OK so far.

Now the fun bit.

Un-wield the dagger, to just put it back in the inventory.
Look in your inventory:
Dagger (wielding)
huh ? Im not wielding it any longer.

So drop it.
Then pick it up again.
Look in your inventory:
Dagger (wielding)

So it seems the item is never un-marked as being wielded.

Jest test (rogue-client.test.js) failing

npm test to run the unit tests... bang.

FAIL test/rogue-client.test.js
● monster connects to server › should see other entities die

TypeError: Cannot read property '0' of undefined

  367 |       
  368 |       if (bot2started && event === EVENTS.delete) {
> 369 |         let other = bot1.client.getItemsAt(pos1.x, pos1.y, pos1.z)[0];
      |                     ^
  370 |         expect(other.getDescription()).toEqual("goblin corpse");
  371 |         bot1.stop();
  372 |         done();

  at Object.ready (test/rogue-client.test.js:369:21)
  at GoblinBot.ready (src/monsters/bot.js:23:20)
  at GoblinBot.refresh (src/monsters/bot.js:42:14)
  at callback (src/monsters/bot.js:11:80)
  at Socket.<anonymous> (src/client/entity-client.js:52:13)
  at Socket.Emitter.emit (node_modules/socket.io-client/node_modules/component-emitter/index.js:145:20)
  at Socket.emitEvent (node_modules/socket.io-client/build/socket.js:264:20)
  at Socket.onevent (node_modules/socket.io-client/build/socket.js:251:18)
  at Socket.onpacket (node_modules/socket.io-client/build/socket.js:215:22)
  at Manager.Emitter.emit (node_modules/socket.io-client/node_modules/component-emitter/index.js:145:20)
  at Manager.ondecoded (node_modules/socket.io-client/build/manager.js:204:15)
  at Decoder.Emitter.emit (node_modules/socket.io-parser/node_modules/component-emitter/index.js:145:20)
  at Decoder.add (node_modules/socket.io-parser/dist/index.js:117:23)
  at Manager.ondata (node_modules/socket.io-client/build/manager.js:196:22)
  at Socket.Emitter.emit (node_modules/engine.io-client/node_modules/component-emitter/index.js:145:20)
  at Socket.onPacket (node_modules/engine.io-client/lib/socket.js:387:16)
  at WS.<anonymous> (node_modules/engine.io-client/lib/socket.js:196:14)
  at WS.Emitter.emit (node_modules/engine.io-client/node_modules/component-emitter/index.js:145:20)
  at WS.onPacket (node_modules/engine.io-client/lib/transport.js:103:10)
  at WS.onData (node_modules/engine.io-client/lib/transport.js:96:10)
  at WebSocket.ws.onmessage (node_modules/engine.io-client/lib/transports/websocket.js:113:12)
  at WebSocket.onMessage (node_modules/engine.io-client/node_modules/ws/lib/event-target.js:132:16)
  at Receiver.receiverOnMessage (node_modules/engine.io-client/node_modules/ws/lib/websocket.js:825:20)
  at Receiver.dataMessage (node_modules/engine.io-client/node_modules/ws/lib/receiver.js:437:14)
  at Receiver.getData (node_modules/engine.io-client/node_modules/ws/lib/receiver.js:367:17)
  at Receiver.startLoop (node_modules/engine.io-client/node_modules/ws/lib/receiver.js:143:22)
  at Receiver._write (node_modules/engine.io-client/node_modules/ws/lib/receiver.js:78:10)
  at Socket.socketOnData (node_modules/engine.io-client/node_modules/ws/lib/websocket.js:900:35)

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.