Client can now connect to servers interactively

This commit is contained in:
2024-02-22 17:30:24 -05:00
parent e68d63915d
commit 7f7bd5a781
8 changed files with 129 additions and 29 deletions

View File

@@ -22,10 +22,13 @@ public:
Gui gui_;
public:
void set_initial_state() {
void set_initial_state_connect(const eng::string &hostspec) {
// Create the world model.
world_.reset(new World(WORLD_TYPE_PREDICTIVE));
// Create the communication channel.
channel_ = new_outgoing_channel(hostspec);
// This is a temporary actor that will be used only until the server sends
// us the first difference transmission. We do this only to establish
// the invariant that there's always an actor. When the first difference
@@ -38,6 +41,34 @@ public:
// Export stuff to the graphics engine.
set_visible_world_and_actor(world_.get(), actor_id_);
// Reset the print channeler
print_channeler_.reset();
}
void set_initial_state_standalone(std::string_view srcpk) {
// Create the world model.
world_.reset(new World(WORLD_TYPE_MASTER));
// Update the source code of the master model.
world_->update_source(srcpk);
// Make sure the channel is empty.
channel_.reset();
// Create the standalone actor.
actor_id_ = world_->create_login_actor();
// TODO: initialize the standalone actor.
// Clear the unack command queue.
unack_.clear();
// Export stuff to the graphics engine.
set_visible_world_and_actor(world_.get(), actor_id_);
// Reset the print channeler
print_channeler_.reset();
}
@@ -54,30 +85,31 @@ public:
}
void world_to_asynchronous() {
if (world_->snapshot_empty()) {
world_->snapshot();
for (const Invocation &inv : unack_) {
world_->invoke(inv);
if (!world_->is_authoritative()) {
if (world_->snapshot_empty()) {
world_->snapshot();
for (const Invocation &inv : unack_) {
world_->invoke(inv);
}
}
}
}
void abandon_server() {
stdostream() << "Abandoning server." << std::endl;
// When we abandon the server, we leave the world model
// hanging around to preserve the invariant that there
// is always a world model. Then, we trigger a rescan
// of the lua source. When the lua source shows up, then
// we will create a standalone model to replace the client
// model.
// Put the world model back into a known-good state.
set_initial_state();
// Disconnect from the server.
channel_.reset();
rescan_lua_source();
}
virtual void event_init(std::string_view srcpk, int argc, char *argv[]) {
// Put the world into the starting state.
set_initial_state();
// Establish a connection to the server.
channel_ = new_outgoing_channel("nocert:localhost:8085");
set_initial_state_standalone(srcpk);
// Set the console prompt
set_console_prompt(console_.get_prompt());
@@ -85,15 +117,24 @@ public:
void send_invocation(const Invocation &inv) {
if (channel_ == nullptr) {
stdostream() << "Cannot invoke any actions, not connected." << std::endl;
return;
if ((!world_->is_authoritative()) && (inv.kind() == Invocation::KIND_LUA_SOURCE)) {
// We have a client model, but no client connection. That means we're
// in the process of shutting down a client model. The client model
// is supposed to linger until the lua source is reread. Once we have
// the lua source, we're supposed to throw out the client model and
// create a standalone model.
set_initial_state_standalone(inv.datapack());
} else {
world_->invoke(inv);
}
} else {
world_to_asynchronous();
world_->invoke(inv);
unack_.push_back(inv);
StreamBuffer *sb = channel_->out();
sb->write_uint8(util::MSG_INVOKE);
inv.serialize(sb);
}
world_to_asynchronous();
world_->invoke(inv);
unack_.push_back(inv);
StreamBuffer *sb = channel_->out();
sb->write_uint8(util::MSG_INVOKE);
inv.serialize(sb);
}
void do_luainvoke_command(const StringVec &words) {
@@ -149,6 +190,10 @@ public:
stop_driver();
}
void do_connect_command(const util::StringVec &words) {
set_initial_state_connect(util::ss("nocert:", words[1], ":8085"));
}
void do_command(const util::StringVec &words) {
if (words.empty()) return;
else if (words[0] == "luainvoke") do_luainvoke_command(words);
@@ -161,6 +206,7 @@ public:
else if (words[0] == "cpl") do_cpl_command(words);
else if (words[0] == "work") do_work_command(words);
else if (words[0] == "quit") do_quit_command(words);
else if (words[0] == "connect") do_connect_command(words);
else {
stdostream() << "Unsupported command: " << words[0] << std::endl;
}
@@ -256,9 +302,7 @@ public:
// Channel print statements.
if (print_channeler_.channel(world_->get_printbuffer(actor_id_), stdostream())) {
if (channel_ != nullptr) {
send_invocation(print_channeler_.invocation(actor_id_));
}
send_invocation(print_channeler_.invocation(actor_id_));
}
}
};