ecsx-framework/ECSx

Idea: ECSx.ServerEvents

Closed this issue · 1 comments

When the client is sensitive to network traffic, or the game state is very large, the cost of synchronizing all states each time is very high.

Is it possible to add an event list, just like client events, you can add events yourself every time you update the component, and only synchronize events to the client.

Only need to refresh all status at optional times.

In this way, the client can distinguish modifications based on events and synchronize the differences with the server.

Hi Binsect and thanks for the interesting questions. As you mentioned, using a naive approach such as in the Ship tutorial, where every item is synchronized every frame, is often not ideal.

You introduced one possibility which is the publisher-subscriber pattern, where updates to the backend state would emit messages, to be received somehow by the client. If you're using Phoenix, you already have Phoenix.PubSub set up, so this is a good fit. Simply update your System code to include a broadcast:

defmodule MyApp.Systems.Destruction do
  ...
  def run do
    for ship <- HitPoints.search(0) do
      destroy_ship(ship)
      Phoenix.PubSub.broadcast(MyApp.PubSub, "topic" {:ship_destroyed, ship})
    end
  end
end

and then any clients (e.g. LiveView) can subscribe to the topic to receive the messages:

defmodule MyAppWeb.ClientLive do
  def mount(...) do
    Phoenix.PubSub.subscribe(MyApp.PubSub, "topic")
  end

  def handle_info({:ship_destroyed, entity}, socket) do
    # update client state
  end
end

The reason ECSx needs to provide a special ClientEvents API is to ensure that Component writes are serialized (due to technical implementation details using OTP). Going the other direction, from backend to frontend, does not have this issue, so it's not necessary for ECSx to force users into a single implementation if they wish to use this subscriber pattern.

Another possibility to solve the original issue, which is more difficult to implement but more robust (and used in many existing video games), is to reduce the amount of data transferred by calculating as many updates as possible on the client itself. That is a massive topic with lots of writing on it already so I'll leave that to you to research if you're interested 🙂