Пример #1
0
void dm_bcast_agesdl_hook(GameHost_Private* host)
{
    Game_AgeInfo info = s_ages[host->m_ageFilename];

    MOUL::NetMsgSDLStateBCast* bcast = MOUL::NetMsgSDLStateBCast::Create();
    bcast->m_contentFlags = MOUL::NetMessage::e_HasTimeSent
                            | MOUL::NetMessage::e_NeedsReliableSend;
    bcast->m_timestamp.setNow();
    bcast->m_isInitial = true;
    bcast->m_persistOnServer = true;
    bcast->m_isAvatar = false;
    bcast->m_object.m_location = MOUL::Location::Make(info.m_seqPrefix, -2, MOUL::Location::e_BuiltIn);
    bcast->m_object.m_name = "AgeSDLHook";
    bcast->m_object.m_type = 1;  // SceneObject
    bcast->m_object.m_id = 1;
    bcast->m_sdlBlob = host->m_ageSdlHook.toBlob();

    std::lock_guard<std::mutex> clientGuard(host->m_clientMutex);
    for (auto client_iter = host->m_clients.begin(); client_iter != host->m_clients.end(); ++client_iter) {
        try {
            DM_WRITEMSG(host, bcast);
            DS::CryptSendBuffer(client_iter->second->m_sock, client_iter->second->m_crypt,
                                host->m_buffer.buffer(), host->m_buffer.size());
        } catch (DS::SockHup) {
            // This is handled below too, but we don't want to skip the rest
            // of the client list if one hung up
        }
    }
    bcast->unref();
}
Пример #2
0
void DS::GateKeeper_DisplayClients()
{
    std::lock_guard<std::mutex> clientGuard(s_clientMutex);
    if (s_clients.size())
        fputs("Gate Keeper:\n", stdout);
    for (auto client_iter = s_clients.begin(); client_iter != s_clients.end(); ++client_iter)
        printf("  * %s\n", DS::SockIpAddress((*client_iter)->m_sock).c_str());
}
Пример #3
0
void dm_game_shutdown(GameHost_Private* host)
{
    {
        std::lock_guard<std::mutex> clientGuard(host->m_clientMutex);
        for (auto client_iter = host->m_clients.begin(); client_iter != host->m_clients.end(); ++client_iter)
            DS::CloseSock(client_iter->second->m_sock);
    }

    for (auto clone_iter = host->m_clones.begin(); clone_iter != host->m_clones.end(); ++clone_iter)
        clone_iter->second->unref();
    host->m_clones.clear();

    bool complete = false;
    for (int i=0; i<50 && !complete; ++i) {
        host->m_clientMutex.lock();
        size_t alive = host->m_clients.size();
        host->m_clientMutex.unlock();
        if (alive == 0)
            complete = true;
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
    if (!complete)
        fputs("[Game] Clients didn't die after 5 seconds!\n", stderr);

    s_gameHostMutex.lock();
    hostmap_t::iterator host_iter = s_gameHosts.begin();
    while (host_iter != s_gameHosts.end()) {
        if (host_iter->second == host)
            host_iter = s_gameHosts.erase(host_iter);
        else
            ++host_iter;
    }
    s_gameHostMutex.unlock();

    if (host->m_temp) {
        PostgresStrings<1> params;
        params.set(0, host->m_serverIdx);
        PQexecParams(host->m_postgres,
                "DELETE FROM game.\"Servers\" "
                "    WHERE \"idx\"=$1;",
                1, 0, params.m_values, 0, 0, 0);
    }
    PQfinish(host->m_postgres);
    delete host;
}
Пример #4
0
void dm_propagate(GameHost_Private* host, MOUL::NetMessage* msg, uint32_t sender)
{
    DM_WRITEMSG(host, msg);

    std::lock_guard<std::mutex> clientGuard(host->m_clientMutex);
    DS::SendFlag mode = (msg->m_contentFlags & MOUL::NetMessage::e_NeedsReliableSend) ? DS::e_SendNoRetry : DS::e_SendSpam;
    for (auto client_iter = host->m_clients.begin(); client_iter != host->m_clients.end(); ++client_iter) {
        if (client_iter->second->m_clientInfo.m_PlayerId == sender
            && !(msg->m_contentFlags & MOUL::NetMessage::e_EchoBackToSender))
            continue;

        try {
            DS::CryptSendBuffer(client_iter->second->m_sock, client_iter->second->m_crypt,
                                host->m_buffer.buffer(), host->m_buffer.size(), mode);
        } catch (DS::SockHup) {
            // This is handled below too, but we don't want to skip the rest
            // of the client list if one hung up
        }
    }
}
Пример #5
0
void dm_broadcast(GameHost_Private* host, MOUL::NetMessage* msg, uint32_t sender)
{
    DM_WRITEMSG(host, msg);
    DS::SendFlag mode = (msg->m_contentFlags & MOUL::NetMessage::e_NeedsReliableSend) ? DS::e_SendNoRetry : DS::e_SendSpam;

    std::lock_guard<std::mutex> hostGuard(s_gameHostMutex);
    for (auto host_it = s_gameHosts.begin(); host_it != s_gameHosts.end(); ++host_it) {
        std::lock_guard<std::mutex> clientGuard(host_it->second->m_clientMutex);
        for (auto client_it = host_it->second->m_clients.begin(); client_it != host_it->second->m_clients.end(); ++client_it) {
            if (client_it->second->m_clientInfo.m_PlayerId == sender
                && !(msg->m_contentFlags & MOUL::NetMessage::e_EchoBackToSender))
                continue;

            try {
                DS::CryptSendBuffer(client_it->second->m_sock, client_it->second->m_crypt,
                                    host->m_buffer.buffer(), host->m_buffer.size(), mode);
            } catch (DS::SockHup&) { }
        }
    }
}
Пример #6
0
void DS::GateKeeper_Shutdown()
{
    {
        std::lock_guard<std::mutex> clientGuard(s_clientMutex);
        for (auto client_iter = s_clients.begin(); client_iter != s_clients.end(); ++client_iter)
            DS::CloseSock((*client_iter)->m_sock);
    }

    bool complete = false;
    for (int i=0; i<50 && !complete; ++i) {
        s_clientMutex.lock();
        size_t alive = s_clients.size();
        s_clientMutex.unlock();
        if (alive == 0)
            complete = true;
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
    if (!complete)
        fputs("[GateKeeper] Clients didn't die after 5 seconds!\n", stderr);
}
Пример #7
0
void dm_propagate_to(GameHost_Private* host, MOUL::NetMessage* msg,
                     const std::vector<uint32_t>& receivers)
{
    DM_WRITEMSG(host, msg);
    DS::SendFlag mode = (msg->m_contentFlags & MOUL::NetMessage::e_NeedsReliableSend) ? DS::e_SendNoRetry : DS::e_SendSpam;

    for (auto rcvr_iter = receivers.begin(); rcvr_iter != receivers.end(); ++rcvr_iter) {
        std::lock_guard<std::mutex> hostGuard(s_gameHostMutex);
        for (hostmap_t::iterator recv_host = s_gameHosts.begin(); recv_host != s_gameHosts.end(); ++recv_host) {
            std::lock_guard<std::mutex> clientGuard(recv_host->second->m_clientMutex);
            auto client = recv_host->second->m_clients.find(*rcvr_iter);
            if (client != recv_host->second->m_clients.end()) {
                try {
                    DS::CryptSendBuffer(client->second->m_sock, client->second->m_crypt,
                                        host->m_buffer.buffer(), host->m_buffer.size(), mode);
                } catch (DS::SockHup) {
                    // This is handled below too, but we don't want to skip the rest
                    // of the client list if one hung up
                }
                break; // Don't bother checking the rest of the hosts, we found the one we're looking for
            }
        }
    }
}
Пример #8
0
void dm_send_members(GameHost_Private* host, GameClient_Private* client)
{
    MOUL::NetMsgMembersList* members = MOUL::NetMsgMembersList::Create();
    members->m_contentFlags = MOUL::NetMessage::e_HasTimeSent
                            | MOUL::NetMessage::e_HasPlayerID
                            | MOUL::NetMessage::e_IsSystemMessage
                            | MOUL::NetMessage::e_NeedsReliableSend;
    members->m_timestamp.setNow();
    members->m_playerId = client->m_clientInfo.m_PlayerId;

    host->m_clientMutex.lock();
    members->m_members.reserve(host->m_clients.size() - 1);
    for (auto client_iter = host->m_clients.begin(); client_iter != host->m_clients.end(); ++client_iter) {
        if (client_iter->second->m_clientInfo.m_PlayerId != client->m_clientInfo.m_PlayerId
            && !client->m_clientKey.isNull()) {
            MOUL::NetMsgMemberInfo info;
            info.m_client = client_iter->second->m_clientInfo;
            info.m_avatarKey = client_iter->second->m_clientKey;
            members->m_members.push_back(info);
        }
    }
    host->m_clientMutex.unlock();

    DM_WRITEMSG(host, members);
    DS::CryptSendBuffer(client->m_sock, client->m_crypt,
                        host->m_buffer.buffer(), host->m_buffer.size());
    members->unref();

    // Load non-avatar clones (ie NPC quabs)
    for (auto clone_iter = host->m_clones.begin(); clone_iter != host->m_clones.end(); ++clone_iter) {
        DM_WRITEMSG(host, clone_iter->second);
        DS::CryptSendBuffer(client->m_sock, client->m_crypt,
                            host->m_buffer.buffer(), host->m_buffer.size());
    }

    // Load clones for players already in the age
    MOUL::NetMsgLoadClone* cloneMsg = MOUL::NetMsgLoadClone::Create();
    cloneMsg->m_contentFlags = MOUL::NetMessage::e_HasTimeSent
                             | MOUL::NetMessage::e_NeedsReliableSend;
    cloneMsg->m_timestamp.setNow();
    cloneMsg->m_isPlayer = true;
    cloneMsg->m_isLoading = true;
    cloneMsg->m_isInitialState = true;

    MOUL::LoadAvatarMsg* avatarMsg = MOUL::LoadAvatarMsg::Create();
    avatarMsg->m_bcastFlags = MOUL::Message::e_NetPropagate
                            | MOUL::Message::e_LocalPropagate;
    avatarMsg->m_receivers.push_back(MOUL::Key::NetClientMgrKey);
    avatarMsg->m_requestorKey = MOUL::Key::AvatarMgrKey;
    avatarMsg->m_userData = 0;
    avatarMsg->m_validMsg = true;
    avatarMsg->m_isLoading = true;
    avatarMsg->m_isPlayer = true;
    cloneMsg->m_message = avatarMsg;

    {
        std::lock_guard<std::mutex> clientGuard(host->m_clientMutex);
        for (auto client_iter = host->m_clients.begin(); client_iter != host->m_clients.end(); ++client_iter) {
            if (client_iter->second->m_clientInfo.m_PlayerId != client->m_clientInfo.m_PlayerId
                && !client->m_clientKey.isNull()) {
                avatarMsg->m_cloneKey = client_iter->second->m_clientKey;
                avatarMsg->m_originPlayerId = client_iter->second->m_clientInfo.m_PlayerId;

                DM_WRITEMSG(host, cloneMsg);
                DS::CryptSendBuffer(client->m_sock, client->m_crypt,
                                    host->m_buffer.buffer(), host->m_buffer.size());
            }
        }
    }
    cloneMsg->unref();
}
Пример #9
0
void dm_game_disconnect(GameHost_Private* host, Game_ClientMessage* msg)
{
    // Unload the avatar clone if the client committed hara-kiri
    if (msg->m_client->m_isLoaded && !msg->m_client->m_clientKey.isNull()) {
        MOUL::LoadCloneMsg* cloneMsg = MOUL::LoadCloneMsg::Create();
        cloneMsg->m_bcastFlags = MOUL::Message::e_NetPropagate
                               | MOUL::Message::e_LocalPropagate;
        cloneMsg->m_receivers.push_back(MOUL::Key::NetClientMgrKey);
        cloneMsg->m_cloneKey = msg->m_client->m_clientKey;
        cloneMsg->m_requestorKey = MOUL::Key::AvatarMgrKey;
        cloneMsg->m_userData = 0;
        cloneMsg->m_originPlayerId = msg->m_client->m_clientInfo.m_PlayerId;
        cloneMsg->m_validMsg = true;
        cloneMsg->m_isLoading = false;

        MOUL::NetMsgLoadClone* netMsg = MOUL::NetMsgLoadClone::Create();
        netMsg->m_contentFlags = MOUL::NetMessage::e_HasTimeSent
                               | MOUL::NetMessage::e_NeedsReliableSend;
        netMsg->m_timestamp.setNow();
        netMsg->m_isPlayer = true;
        netMsg->m_isLoading = false;
        netMsg->m_isInitialState = false;
        netMsg->m_message = cloneMsg;
        netMsg->m_object = msg->m_client->m_clientKey;

        dm_propagate(host, netMsg, msg->m_client->m_clientInfo.m_PlayerId);
        netMsg->unref();

        host->m_states.erase(msg->m_client->m_clientKey);
    }

    MOUL::NetMsgMemberUpdate* memberMsg = MOUL::NetMsgMemberUpdate::Create();
    memberMsg->m_contentFlags = MOUL::NetMessage::e_HasTimeSent
                              | MOUL::NetMessage::e_IsSystemMessage
                              | MOUL::NetMessage::e_NeedsReliableSend;
    memberMsg->m_timestamp.setNow();
    memberMsg->m_member.m_client = msg->m_client->m_clientInfo;
    memberMsg->m_member.m_avatarKey = msg->m_client->m_clientKey;
    memberMsg->m_addMember = false;

    dm_propagate(host, memberMsg, msg->m_client->m_clientInfo.m_PlayerId);
    memberMsg->unref();
    SEND_REPLY(msg, DS::e_NetSuccess);

    // Release any stale locks
    host->m_lockMutex.lock();
    for (auto it = host->m_locks.begin(); it != host->m_locks.end(); ) {
        if (it->second == msg->m_client->m_clientInfo.m_PlayerId)
            it = host->m_locks.erase(it);
        else
            ++it;
    }
    host->m_lockMutex.unlock();

    // Reassign game-mastership if needed...
    {
        std::lock_guard<std::mutex> gmGuard(host->m_gmMutex);
        if (host->m_gameMaster == msg->m_client->m_clientInfo.m_PlayerId) {
            MOUL::NetMsgGroupOwner* groupMsg = MOUL::NetMsgGroupOwner::Create();
            groupMsg->m_contentFlags = MOUL::NetMessage::e_HasTimeSent
                                     | MOUL::NetMessage::e_IsSystemMessage
                                     | MOUL::NetMessage::e_NeedsReliableSend;
            groupMsg->m_timestamp.setNow();
            groupMsg->m_groups.resize(1);
            groupMsg->m_groups[0].m_own = true;
            DM_WRITEMSG(host, groupMsg);

            // This client has already been removed from the map, so we can just
            // pick the 0th client and call him the new owner :)
            std::lock_guard<std::mutex> clientGuard(host->m_clientMutex);
            if (host->m_clients.size()) {
                GameClient_Private* newOwner = host->m_clients.begin()->second;
                host->m_gameMaster = newOwner->m_clientInfo.m_PlayerId;
                try {
                    DS::CryptSendBuffer(newOwner->m_sock, newOwner->m_crypt,
                                        host->m_buffer.buffer(), host->m_buffer.size());
                } catch (...) {
                    fprintf(stderr, "[Game] Ownership transfer to %i from %i failed.",
                            msg->m_client->m_clientInfo.m_PlayerId, newOwner->m_clientInfo.m_PlayerId);
                    DS_DASSERT(false);
                }
            } else {
                host->m_gameMaster = 0;
            }
            groupMsg->unref();
        }
    }

    // Good time to write this back to the vault
    dm_local_sdl_update(host, host->m_localState.toBlob());

    // TODO: This should probably respect the age's LingerTime
    //       As it is, there might be a race condition if another player is
    //       joining just as the last player is leaving.
    if (host->m_clients.size() == 0)
        host->m_channel.putMessage(e_GameShutdown, 0);
}