Building multiplayer game using Streams v2

Building multiplayer game using Streams v2

In this talk you will learn how stream-based programming can be used to implement web frontend and multiplayer backend of the classic game: Snake.

Building dynamic applications using imperative approach tends to create lots of unmaintainable code. Stream-based programming tries to solve this problem by introducing fully declarative way of defining application logic. While using streams, you will focus on WHAT needs to be done, not HOW and WHEN.

The talk is divided into 3 parts. In the first part you will learn how to create a frontend of the Snake web game using streams as building blocks. Then, we will move to the server side and use Scala and Akka Streams library to create backend service that will allow the game to be played by multiple players. In the third part, we will discuss reactive streams and how they make asynchronous communication safe.

6f6dc1b13fd3fe35d36db3adafcb0c8e?s=128

Michał Płachta

September 21, 2016
Tweet

Transcript

  1. 6.

    michalplachta.com @miciek What’s inside? • how frontend web app written

    in streams looks like • how backend app written using streams looks like • how do Reactive Streams keep async communication safe?
  2. 11.

    michalplachta.com @miciek Stream operators: map & scan stream.map(f) • transforms

    values from stream using function f • returns a new stream with transformed values stream.scan(init, f) • accumulates values from stream using function f ◦ f(acc,val)=>new_acc • returns a new stream that outputs accumulator value
  3. 20.

    michalplachta.com @miciek Stream operators: filter stream.filter(p) • checks each value

    from stream against the predicate passed as p • returns a new stream that outputs only values that satisfy condition p Already used: • map(f) • scan(init, f(acc, val))
  4. 24.

    michalplachta.com @miciek Stream operators: merge stream.merge(stream2) • stream is merged

    with stream2 • returns a new stream that outputs values from both stream and stream2 as they appear Already used: • map(f) • scan(init, f(acc, val)) • filter(p)
  5. 28.

    michalplachta.com @miciek Stream operators: sampledBy stream.sampledBy(stream2) • last value from

    stream is taken when any value appears in stream2 • returns a new stream that outputs values from stream sampled by values from stream2 Already used: • map(f) • scan(init, f(acc, val)) • filter(p) • merge(stream2)
  6. 32.

    michalplachta.com @miciek Current implementation • “ticks” • “key presses” •

    “left key presses” • “right key presses” • “left rotations” • “right rotations” • “actions” • “dir changes” • “directions” • “snake head positions” + map, scan, filter, merge & sampledBy 10 streams
  7. 33.

    michalplachta.com @miciek Stream operators: slidingWindow stream.slidingWindow(n) • aggregate last n

    values • returns a new stream that outputs arrays of last n values from the stream • can be implemented using scan Already used: • map(f) • scan(init, f(acc, val)) • filter(p) • merge(stream2) • sampledBy(stream2)
  8. 35.

    michalplachta.com @miciek Quiz: Eating a fruit? using 6 operators •

    map(f) • scan(init, f(acc, val)) • filter(p) • merge(stream2) • sampledBy(stream2) • slidingWindow(n) & 11 streams • “ticks” • “key presses” • “left key presses” • “right key presses” • “left rotations” • “right rotations” • “actions” • “direction changes” • “directions” • “snake head positions” • “snakes”
  9. 40.

    michalplachta.com @miciek Snake Server App Requirements • clients send snake

    positions to the server • server generates fruits • server keeps scores • server broadcasts: ◦ positions of all snakes ◦ positions of fruits ◦ current scoreboard
  10. 60.

    michalplachta.com @miciek Crossing Async Boundary Push Model • not safe

    when Subscriber slower • perfect when Subscriber faster • too slow when Subscriber faster • perfect when Subscriber slower Pull Model
  11. 61.

    michalplachta.com @miciek Reactive Streams Streams with supply & demand •

    “as fast as possible, but not faster” • consumer wants to pull elements (= demand) • only then publisher can push ◦ it supplies elements until demand is satisfied
  12. 65.

    michalplachta.com @miciek Reactive Streams API public interface Publisher<T> { public

    void subscribe(Subscriber<? super T> s); } public interface Subscriber<T> { public void onSubscribe(Subscription s); public void onNext(T t); public void onError(Throwable t); public void onComplete(); } public interface Subscription { public void request(long n); public void cancel(); } public interface Processor<T, R> extends Subscriber<T>, Publisher<R> {}
  13. 67.

    michalplachta.com @miciek Reactive Streams API implementations • Project Reactor •

    Ratpack • Vert.x • Slick • Akka Stream • JDK 9 • Integrations: ◦ Kafka, ◦ Mongo, ◦ Cassandra
  14. 68.

    michalplachta.com @miciek Akka Stream model Publisher => Source Processor =>

    Flow Subscriber => Sink Our Snake implementation uses Reactive Streams!
  15. 69.

    michalplachta.com @miciek • NO ◦ frontend is pushing every 100ms

    • Possible solutions: ◦ Reactive Streams web frameworks? ◦ conflate/expand? ◦ buffer between frontend & backend? Is Snake Multiplayer safe?
  16. 70.

    michalplachta.com @miciek Links Build YOUR OWN Snake using Streams -

    blog post (step-by-step tutorial) michalplachta.com/2016/05/11/reactive-ui-by-example/ Client Side Code github.com/miciek/web-snake-react-bacon Server Side Code github.com/miciek/snake-multiplayer-akka-streams Play with streams and operators! rxmarbles.com/ Akka Streams doc.akka.io/docs/akka/2.4.9/scala/stream/ BaconJS - streams in JavaScript baconjs.github.io/