Skip to content

tinspin/fuse

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation


+-----------------------------+
| multiplayer online standard |
+-----------------------------+

about:

  technical sales pitch

protocol:

  - uses |;, separation:
    - '|' protocol
    - ';' objects
    - ',' attributes
  - client/server triplex http
    comet upstream, 'data: \n\n' encapsulated

platform:

  - low internal latency: stat
  - multithreaded nio with queue, linear perf.:
    - 1.000 mess./sec. on raspberry pi 1
    - 6.500 mess./sec. on raspberry pi 2
    - 100.000 mess./sec. on t2.micro
    - 200.000 mess./sec. on m4.large
    - 300.000 mess./sec. on t2.medium
    - 7.200.000 mess./sec. on c5.18xlarge
    - 9.600.000 mess./sec. on m5d.24xlarge
  - 100% uptime on hosting and routing with round-robin dns
  - 100% read uptime on persistence with custom 
    async distributed json file system database
    with region select
  - peak garbage collect:
    - 70 ms (raspberry pi 1)
    - 14 ms (raspberry pi 2)
    - 7 ms (aws micro instance)

license:

  - Source available, you have to show the logo on startup,
    sponsor the fuse tier on gumroad while you are using this,
    or any derivation, commercially. The .html and graphics are
    proprietary examples except the javascript in play.html!
    The protocol is public domain.

+------------------+
| work in progress |
+------------------+

o-> = async. broadcast to read() (c#) or read(data) (javascript) including self
x-> = async. broadcast to read() (c#) or read(data) (javascript) excluding self
i-> = async. send to one user for unique feedback
 -> = sync. return on push(data)

<…> = mandatory
[…] = optional
{…} = json

 *  = not implemented yet

<spot> = <x>,<y>,<z>
<tree> for here/gone/chat:

hierarchy:

host is a root
game is a stem and also a room.
room is a leaf

in sort of chronological order:

+-----------------------------------+
| rule                      -> echo |
+-----------------------------------+

                            // to get latency
 ping                       -> ping|done

                            // simple crash report
 snap|[data]                -> snap|done
 
                            // to get server time in millisec from 1970
 time                       -> time|done|<time>

                            // register
                            // [name] if you can't store the <id> otherwise set
                            //        to empty string (||)
                            // [pass] if you can't store the <key> otherwise set
                            //        to empty string (||)
                            //        preferably [pass] is a hash with salt 
                            //        we simply use hash(pass + name.toLowerCase())
 user|[name]|[pass]         -> user|done|<salt>|<key>|<id>
                            -> user|fail|name too short     // min 2
                            -> user|fail|name too long      // max 6
                            -> user|fail|name already registered
                            -> user|fail|name invalid       // [a-wyA-WY2-9]+
                            -> user|fail|name alpha missing // [0-9]+ reserved for <id>
                            -> user|fail|pass too short     // min 3
                            -> user|fail|pass too long      // max 9
 
                            // get salt for <name> or <id>
 salt|<name>/<id>           -> salt|done|<salt>
                            -> salt|fail|name not found
                            -> salt|fail|id not found
                            -> salt|fail|unknown problem
 
 \/ anything below          -> main|fail|salt not found
 
                            // login
                            // <hash> is either hash(<key> + <salt>)
                            //               or hash(hash(pass + name.toLowerCase()) + <salt>)
 sign|<salt>|<hash>         -> sign|done|<name>/<id>
                            -> sign|fail|wrong pass
                            -> sign|fail|unknown problem

 \/ anything below          -> main|fail|not authorized

+------------------------------+
| here you have to call pull() |
+------------------------------+

you have to wait until pull completes and you receive the first noop before you continue

+-----------------------------------------------------+
| below this line <name>/<id> is replaced with <user> |
+-----------------------------------------------------+

                            // join a game
 game|<salt>|<name>         -> game|done
                           x-> here|<tree>|<user>[|ip]
                           x-> ally|<user>
                           x-> away|<user>                  // away from keyboard
                           o-> name|<user>|<name>           // if <id> used and name set
                           o-> nick|<user>|<nick>           // if <id> used and nick set
                            -> game|fail|name invalid       // [a-zA-Z]+

 \/ anything below          -> main|fail|no game

                            // set nick for user
 nick|<salt>|<nick>         -> nick|done
                            -> nick|fail|nick invalid       // [a-zA-Z0-9.\\-]+

                            // get nick for any id
 nick|<salt>|<id>           -> nick|done|<nick>
                            -> nick|fail|not found

                            // set name for user
 name|<salt>|<name>         -> name|done
                            -> name|fail|name invalid       // [a-zA-Z0-9.\\-]+
                            -> name|fail|name alpha missing // [0-9]+ reserved for <id>
                            -> name|fail|taken

                            // get name for any id
 name|<salt>|<id>           -> name|done|<name>
                            -> name|fail|not found

                            // set pass
 pass|<salt>|<pass>         -> pass|done
 
                            // set mail
 mail|<salt>|<mail>         -> mail|done
                            -> mail|fail|mail invalid       // [a-zA-Z0-9.@\\-\\+]+

                            // away from keyboard
 away|<salt>                -> away|done
                           x-> away|<user>
                           o-> hold                         // pause

                            // back
 back|<salt>                -> back|done
                           x-> back|<user>
                           o-> free                         // unpause

                            // add/remove friend
 ally|<salt>|<user>[|info]  -> ally|done[|poll]
                            -> ally|fail|user not online
                            -> ally|fail|user busy
                           i-> poll|ally|<user>[|info]

                            // get user persistent data
 hard|<salt>|<user>|<name>  -> hard|done|{…}
                            -> hard|fail|not found

                            // get user inventory item
 item|<salt>|<user>|<name>  -> item|done|{…}
                            -> item|fail|not found

                            // get user transient data
 soft|<salt>|<user>|<name>  -> soft|done|{…}
                            -> soft|fail|salt not found
                            -> soft|fail|user not found
                            -> soft|fail|not found

                            // drop item, how many and which
 drop|<salt>|<name>|<many>  -> drop|done|<salt>
                            -> drop|fail|not found
                            -> drop|fail|not enough
                           o-> item|<salt>,<spot>,<name>,<many>

                            // pick item
 pick|<salt>|<salt>         -> pick|done
                            -> pick|fail|not found
                           o-> pick|<user>|<item>           // salt

                            // get user country (ISO 3166)
*flag|<salt>|<user>         -> flag|done|<code>

                            // enable peer-to-peer
                            // before you send this it is important to 
                            // inform the user that privacy is lost!
 peer|<salt>|<ip>           -> peer|done                    // send the internal IP

                            // host room
 room|<salt>|<type>|<size>  -> room|done
                           x-> room|<user>,<type>,<size>
                            -> room|fail|not in lobby
                            -> room|fail|type invalid       // [a-zA-Z]+

                            // list files, rooms, room items or user data (hard, soft and inventory items)
*list|<salt>|file|<date>    -> list|done|file|<date>,<size>,[hash];…
 list|<salt>|room           -> list|done|room|<user>,<type>,<here>,<size>;…
 list|<salt>|room|item      -> list|done|room|item|<salt>,<spot>,<name>,<many>;…
 list|<salt>|user|hard      -> list|done|user|hard|<name>,<size>;…
 list|<salt>|user|soft      -> list|done|user|soft|<name>,<size>;…
 list|<salt>|user|item      -> list|done|user|item|<name>,<many>;…
                            -> list|fail|not found
                            -> list|fail|type missing
                            -> list|fail|wrong type

                            // pull & push resource file
                            // data is base64 which sucks
                            // so I might implement this
                            // later... poke/peek?
*push|<salt>|<name>|<data>  -> file|done
*pull|<salt>|<name>         -> file|done|<data>

                            // join room
                            // between lock and view nobody can join
                            // this sends a poll to the user if he has no room
 join|<salt>|<user>[|info]  -> join|done|poll/room
                           i-> poll|join|<user>[|info]
                           x-> here|<tree>|<user>[|ip]      // leaf, in new room
                           x-> ally|<user>
                           x-> gone|<tree>|<user>|<room>    // stem, in lobby
                           x-> lock|<room>                  // in lobby if room is full
                            -> join|fail|not found
                            -> join|fail|already here
                            -> join|fail|is full
                            -> join|fail|user busy

                            // accept poll, you can only have one poll per user at the same time.
                            // <user> is the user name received in the poll request
                            // type = join; player joins the room of the host
                            // type = ally; both players stored as friends
 poll|<salt>|<user>|<bool>  -> poll|done|<type>
                            -> poll|fail|user not online
                            -> poll|fail|wrong user
                            -> poll|fail|type not found

                            // permanently ban user from room
*kick|<salt>|<user>         -> kick|done
                            -> kick|fail|not creator
                            -> kick|fail|not here
 
                            // exit room
 exit|<salt>                -> exit|done
                           x-> here|<tree>|<user>[|ip]      // stem, in lobby
                           x-> ally|<user>
                           x-> away|<user>                  // away from keyboard, if creator exit
                           x-> gone|<tree>|<user>|<room>    // leaf, in old room
                           x-> drop|<user>                  // in lobby if creator leaves
                           x-> stop|<user>                  // in old room if creator leaves
                           x-> open|<room>                  // in lobby if room is not full
                            -> exit|fail|in lobby

                            // quit platform
 quit|<salt>                -> quit|done
                           x-> quit|<user>

                            /* data handling save/load/tear:
                             * the default disk stored [type] is "hard"
                             * to save inventory items to disk use [type] = "item" (needs "count" number)
                             * to save transient data in memory use [type] = "soft" (disappears on relogin)
                             */

                            // save data
 save|<salt>|<name>|{…}[|type] -> save|done
                            -> save|fail|name too short // min 3
                            -> save|fail|name too long // max 64
                            -> save|fail|unknown problem

                            // load data
 load|<salt>|<name>[|type]  -> load|done|{…}
                            -> load|fail|not found

                            // delete data
 tear|<salt>|<name>[|type]  -> tear|done
                            -> tear|fail|not found

                            // play game
 play|<salt>[|seed]         -> play|done
                           o-> play[|seed]                  // to start the game
                           x-> view|<room>                  // in lobby if room has started
                            -> play|fail|in lobby
                            -> play|fail|not creator
                            -> play|fail|only one player
                            -> play|fail|already playing
                            -> play|fail|someone is away

                            // game over
 over|<salt>[|data]         -> over|done                    // insecure, only for development
                           o-> over|<user>[|data]           // the game is over
                            -> over|fail|not playing

+-----------------------------------------------------------+
| these have to be sent in a separate thread from rendering |
+-----------------------------------------------------------+

                            // chat in any room
                            // <tree> are root, stem or leaf
 chat|<salt>|<tree>|<text>  -> chat|done                    // @[user] of private destination
                           o-> chat|<tree>|<user>|<text>
                            -> chat|fail|not online

                            // send any gameplay data to room
 send|<salt>|<data>         -> send|done
                           x-> send|<user>|<data>
 
                            // send any gameplay data to room
 show|<salt>|<data>         -> show|done
                           o-> show|<user>|<data>
 
                            // motion for 3D MMO games with dynamic here/gone
 move|<salt>|<data>         -> move|done
                           x-> move|<user>|<x>,<y>,<z>;<x>,<y>,<z>,<w>;<action>(;<speed>;…)
                            //             position   |rotation       |key/button-down/up

                            // destination to interpolate to
*path|<salt>|<spot>         -> path|done
                           x-> path|<user>|<spot>

                            // object to follow
*hunt|<salt>|<salt>         -> hunt|done
                           x-> hunt|<user>|<salt>

                            // object to attack
*kill|<salt>|<salt>         -> kill|done
                           x-> kill|<user>|<salt>

 /\ type not found          -> main|fail|type not found

+-----------------+       
| broadcast rules |
+-----------------+

                           o-> noop                         // no operation; to keep socket alive
                           o-> item|<salt>,<name>,<many>,<spot>,<rota>,<velo> // dynamic with orientation
                           o-> item|<salt>,<name>,<many>,<spot>,<rota> // static with orientation
                           o-> item|<salt>,<name>,<many>,<spot>,<velo> // dynamic
                           o-> item|<salt>,<name>,<many>,<spot> // static
                           o-> warn|boot/info/none|<text>   // to broadcast global messages

+----------------+       
| sketched rules |
+----------------+

// peer protocol

*talk // send voice
*look // send eye movement
*head // send head movement
*body // send body movement
*hand // send hand movement

// name pool

 lead date
 head tail
 push pull
 show hide
 gain lose
 item info data      tape task step
 time host prey      solo      slow slot
                     skip skin size site
      fill full make seal seek sell
 slay ruin rise poll said rank rate star
 drop made halt vote read      rest peek
 body text sent loss plan page need
 find      idle keep mark mask mate look
      wake like have home
 undo tool turn      grab grip grow file
 face edit      echo drop copy      busy
      base
 paid rent cash sold coin earn bill sale
 tone tune mute walk
 zero none

// todo

 - Hm, done?!

// attribution

 res/mp3/pop.mp3 - Mark DiAngelo
 res/mp3/snap.mp3 - Mark DiAngelo
 res/svg/animal/* - Freepik
 res/console.svg - Freepik
 res/advance.svg - David Pérez
 res/fuse.svg - Freepik
  
// credits

 pilot developer: Jonas Oien
 feedback: Søren Tramm
           Nicolai Farver