Client can now connect to servers interactively
This commit is contained in:
@@ -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_));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user