diff --git a/luprex/cpp/core/lpxclient.cpp b/luprex/cpp/core/lpxclient.cpp index ae862e46..e0b7744d 100644 --- a/luprex/cpp/core/lpxclient.cpp +++ b/luprex/cpp/core/lpxclient.cpp @@ -234,7 +234,7 @@ public: void receive_diff_from_server(StreamBuffer *sb) { world_to_synchronous(); try { - DebugCollector dbc(""); + DebugCollector dbc(""); int64_t nactor = world_->patch_everything(sb, &dbc); if (nactor != actor_id_) change_actor_id(nactor); dbc.dump(stdostream()); diff --git a/luprex/cpp/core/lpxserver.cpp b/luprex/cpp/core/lpxserver.cpp index 6a17e704..4e925ef3 100644 --- a/luprex/cpp/core/lpxserver.cpp +++ b/luprex/cpp/core/lpxserver.cpp @@ -14,6 +14,8 @@ public: int64_t actor_id_; SharedChannel channel_; UniqueWorld sync_; + double last_diff_; + bool async_diff_; }; using UniqueClient = std::unique_ptr; using ClientVector = eng::vector; @@ -29,6 +31,8 @@ public: HttpChannelVec http_server_channels_; int64_t admin_id_; Gui gui_; + int next_diff_chan_; + double next_tick_; public: virtual void event_init(std::string_view srcpk, int argc, char *argv[]) override { @@ -57,6 +61,9 @@ public: // Export stuff to the graphics engine. set_visible_world_and_actor(master_.get(), admin_id_); + + // for ticking. + next_tick_ = 0.0; } void do_luainvoke_command(const util::StringVec &words) { @@ -165,11 +172,14 @@ public: client->channel_->out()->write_uint8(util::MSG_ACK); client->channel_->out()->write_uint32(0); client->sync_->invoke(inv); - send_diffs(client); + client->async_diff_ = true; return true; } virtual void event_update() override { + // Get the clock. + double clock = get_clock(); + // Execute any queued invocations. // We just feed these directly into the master model. eng::vector invocations = get_queued_invocations(); @@ -200,13 +210,14 @@ public: client->actor_id_ = master_->create_login_actor(); // TODO: initialize the login actor on the master. client->channel_ = std::move(chan); + client->async_diff_ = true; + client->last_diff_ = -100.0; client->sync_.reset(new World(WORLD_TYPE_PREDICTIVE)); // This login actor is never used, it is just to preserve the invariant that // the client model and the server synchronous model are identical. client->sync_->create_login_actor(); clients_.emplace_back(client); stdostream() << "New client: actor id=" << client->actor_id_ << std::endl; - send_diffs(clients_.back()); } else if (chan->port() == 8080) { HttpChannel htchan; htchan.channel_ = chan; @@ -214,6 +225,13 @@ public: } } + // If the clock has advanced far enough, tick the master model. + if (clock >= next_tick_) { + master_->invoke(Invocation(Invocation::KIND_TICK, 0, 0, "")); + next_tick_ += 1.0; + if (next_tick_ < clock + 0.3) next_tick_ = clock + 0.3; + } + // Traverse all existing channels, process any communication. for (UniqueClient &client : clients_) { if (client->channel_->closed()) { @@ -223,6 +241,15 @@ public: // Check for received invocations. while (handle_invocation(client)); + + // Possibly send a diff. + double diffdelay = 5.0; + if (client->async_diff_) diffdelay = 0.1; + if (clock >= client->last_diff_ + diffdelay) { + send_diffs(client); + client->last_diff_ = clock; + client->async_diff_ = false; + } } util::remove_nullptrs(clients_);