redirect code in place
This commit is contained in:
@@ -89,7 +89,29 @@ public:
|
|||||||
sb->overwrite_int32(tw_1, tw_2 - tw_1);
|
sb->overwrite_int32(tw_1, tw_2 - tw_1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void redirect(int64_t id1, int64_t id2) {
|
||||||
|
for (auto &client : clients_) {
|
||||||
|
if (client->actor_id_ == id1) {
|
||||||
|
bool ok = world_->redirected(id1, id2);
|
||||||
|
if (!ok) delete_client(client);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Redirection is touchy: almost any world->invoke could
|
||||||
|
// call tangible.redirect. After that point, the world is
|
||||||
|
// relying on us not to control the wrong character.
|
||||||
|
void process_redirects() {
|
||||||
|
if (world_->have_redirects()) {
|
||||||
|
World::Redirects redirects = world_->fetch_redirects();
|
||||||
|
for (const auto &pair : redirects) {
|
||||||
|
redirect(pair.first, pair.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool handle_invocation(UniqueClient &client) {
|
bool handle_invocation(UniqueClient &client) {
|
||||||
|
if (client == nullptr) return false;
|
||||||
StreamBuffer *sb = client->channel_->in();
|
StreamBuffer *sb = client->channel_->in();
|
||||||
if (sb->empty()) return false;
|
if (sb->empty()) return false;
|
||||||
int64_t tr_before = sb->total_reads();
|
int64_t tr_before = sb->total_reads();
|
||||||
@@ -131,6 +153,7 @@ public:
|
|||||||
//
|
//
|
||||||
if (inv.actor() == client->actor_id_) {
|
if (inv.actor() == client->actor_id_) {
|
||||||
world_->invoke(inv);
|
world_->invoke(inv);
|
||||||
|
process_redirects();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -183,8 +206,9 @@ public:
|
|||||||
// Get the clock.
|
// Get the clock.
|
||||||
double clock = get_clock();
|
double clock = get_clock();
|
||||||
|
|
||||||
// Execute any queued invocations.
|
// Execute any delayed invocations. These always
|
||||||
// We just feed these directly into the master model.
|
// come from the local command line. We just feed
|
||||||
|
// these directly into the master model.
|
||||||
for (const Invocation &inv : delayed_invocations_) {
|
for (const Invocation &inv : delayed_invocations_) {
|
||||||
world_->invoke(inv);
|
world_->invoke(inv);
|
||||||
}
|
}
|
||||||
@@ -225,6 +249,11 @@ public:
|
|||||||
if (next_tick_ < clock + 0.3) next_tick_ = clock + 0.3;
|
if (next_tick_ < clock + 0.3) next_tick_ = clock + 0.3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This handles any redirects triggered from the server command
|
||||||
|
// line or by the tick function.
|
||||||
|
process_redirects();
|
||||||
|
util::remove_nullptrs(clients_);
|
||||||
|
|
||||||
// Traverse all existing channels, process any communication.
|
// Traverse all existing channels, process any communication.
|
||||||
for (UniqueClient &client : clients_) {
|
for (UniqueClient &client : clients_) {
|
||||||
if (client->channel_->closed()) {
|
if (client->channel_->closed()) {
|
||||||
|
|||||||
@@ -282,8 +282,8 @@ LuaDefine(tangible_getclass, "tan",
|
|||||||
LuaDefine(tangible_delete, "tan",
|
LuaDefine(tangible_delete, "tan",
|
||||||
"|Delete the specified tangible."
|
"|Delete the specified tangible."
|
||||||
"|"
|
"|"
|
||||||
"|This cannot be used to delete player tangibles,"
|
"|This cannot be used to delete actor tangibles,"
|
||||||
"|To delete a player, use tangible.redirect"
|
"|To delete a actor, use tangible.deleteactor"
|
||||||
"|") {
|
"|") {
|
||||||
LuaArg tanobj;
|
LuaArg tanobj;
|
||||||
LuaDefStack LS(L, tanobj);
|
LuaDefStack LS(L, tanobj);
|
||||||
@@ -332,14 +332,16 @@ LuaDefine(tangible_deleteactor, "tan",
|
|||||||
LuaDefine(tangible_keepactor, "tan",
|
LuaDefine(tangible_keepactor, "tan",
|
||||||
"|Mark an actor tangible to not 'delete_on_disconnect'."
|
"|Mark an actor tangible to not 'delete_on_disconnect'."
|
||||||
"|"
|
"|"
|
||||||
"|When a client connects to the server, a login actor is created and the"
|
"|When a client connects to the server, a new 'login' actor is "
|
||||||
"|client is put in control of the login actor. The client typically"
|
"|created and the client is put in control of the login actor. "
|
||||||
"|controls the login actor just long enough to type his username and password."
|
"|The login actor typically presents a login dialog. After the "
|
||||||
"|Then, he is redirected to the real actor."
|
"|client types his name and password, tangible.redirect is used "
|
||||||
|
"|to tell the client to control the real actor."
|
||||||
"|"
|
"|"
|
||||||
"|When the client is redirected to the real actor, the login actor is no longer"
|
"|When the client is redirected to the real actor, the login "
|
||||||
"|needed. The login actor has the flag 'delete_on_disconnect', so when the"
|
"|actor is no longer needed. The login actor has the "
|
||||||
"|client detaches from the login actor, it is garbage collected."
|
"|flag 'delete_on_disconnect', so when the client detaches "
|
||||||
|
"|from the login actor, it is garbage collected."
|
||||||
"|"
|
"|"
|
||||||
"|However, if the player clicks 'NEW PLAYER', then it is necessary to"
|
"|However, if the player clicks 'NEW PLAYER', then it is necessary to"
|
||||||
"|convert the login actor into a permanent actor. The most important step is to"
|
"|convert the login actor into a permanent actor. The most important step is to"
|
||||||
@@ -357,6 +359,38 @@ LuaDefine(tangible_keepactor, "tan",
|
|||||||
return LS.result();
|
return LS.result();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LuaDefine(tangible_redirect, "actor1, actor2",
|
||||||
|
"|Cause the client controlling actor1 to take a control of actor2"
|
||||||
|
"|"
|
||||||
|
"|When a client connects to the server, a new 'login' actor is "
|
||||||
|
"|created and the client is put in control of the login actor. "
|
||||||
|
"|The login actor typically presents a login dialog. After the "
|
||||||
|
"|client types his name and password, tangible.redirect is used "
|
||||||
|
"|to tell the client to control the real actor."
|
||||||
|
"|"
|
||||||
|
"|Actor1 must be currently logged in. Actor2 must not be. This "
|
||||||
|
"|function doesn't error check that the actors are valid: it just "
|
||||||
|
"|queues the redirect, then the system error checks later. This "
|
||||||
|
"|is because conditions can change. An invalid redirect will cause "
|
||||||
|
"|a disconnection."
|
||||||
|
"|") {
|
||||||
|
LuaArg lactor1, lactor2;
|
||||||
|
LuaDefStack LS(L, lactor1, lactor2);
|
||||||
|
World *w = World::fetch_global_pointer(L);
|
||||||
|
Tangible *actor1 = w->tangible_get(LS, lactor1, true);
|
||||||
|
Tangible *actor2 = w->tangible_get(LS, lactor2, true);
|
||||||
|
if (!actor1->is_controlled_) {
|
||||||
|
luaL_error(L, "Actor1 is not a controlled actor.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if ((!actor2->can_be_controlled_) || (actor2->is_controlled_)) {
|
||||||
|
luaL_error(L, "Actor2 is not an uncontrolled actor.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
w->add_redirect(actor1->id(), actor2->id());
|
||||||
|
return LS.result();
|
||||||
|
}
|
||||||
|
|
||||||
LuaDefine(tangible_build, "config",
|
LuaDefine(tangible_build, "config",
|
||||||
"|Build a new tangible object."
|
"|Build a new tangible object."
|
||||||
"|"
|
"|"
|
||||||
|
|||||||
@@ -345,6 +345,17 @@ void World::disconnected(int64_t actor_id) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool World::redirected(int64_t actor_id, int64_t new_id) {
|
||||||
|
disconnected(actor_id);
|
||||||
|
Tangible *tan = tangible_get(new_id);
|
||||||
|
if (tan && (tan->can_be_controlled_) && (!tan->is_controlled_)) {
|
||||||
|
tan->is_controlled_ = true;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
eng::string World::probe_lua_expr(int64_t actor_id, std::string_view lua) {
|
eng::string World::probe_lua_expr(int64_t actor_id, std::string_view lua) {
|
||||||
assert(stack_is_clear());
|
assert(stack_is_clear());
|
||||||
lua_State *L = state();
|
lua_State *L = state();
|
||||||
|
|||||||
@@ -243,10 +243,24 @@ public:
|
|||||||
//
|
//
|
||||||
void disconnected(int64_t actor_id);
|
void disconnected(int64_t actor_id);
|
||||||
|
|
||||||
|
// Notify the world that the front end has implemented a
|
||||||
|
// redirect. This can return null to indicate a last-minute
|
||||||
|
// failure, in which case the front end must disconnect.
|
||||||
|
//
|
||||||
|
bool redirected(int64_t actor_id, int64_t new_id);
|
||||||
|
|
||||||
|
// Add a redirect.
|
||||||
|
//
|
||||||
|
void add_redirect(int64_t a, int64_t b) { redirects_.emplace(a,b); }
|
||||||
|
|
||||||
// Fetch all redirects and clear the redirects table.
|
// Fetch all redirects and clear the redirects table.
|
||||||
//
|
//
|
||||||
Redirects fetch_redirects();
|
Redirects fetch_redirects();
|
||||||
|
|
||||||
|
// Return true if there are any redirects.
|
||||||
|
//
|
||||||
|
bool have_redirects() const { return !redirects_.empty(); }
|
||||||
|
|
||||||
// Probe an arbitrary lua expression.
|
// Probe an arbitrary lua expression.
|
||||||
//
|
//
|
||||||
// Any print-statements in the lua code are sent into
|
// Any print-statements in the lua code are sent into
|
||||||
|
|||||||
Reference in New Issue
Block a user